x86/x64 汇编与调用约定
理解指令、寄存器和内存操作,是阅读 Cheat Engine 反汇编窗口的基础。本章面向已能找到练习程序数值地址的读者,帮助你判断指令对数据和程序状态的影响。
从一条写入指令入手
打开 CE 自带 Tutorial,在第 5 关按界面提示定位数值,并用“查找是什么写入此地址”收集指令。假设在一个 64 位目标中观察到 mov [rbx+18],eax:方括号表示内存操作数,目的地址由 RBX 当前值加十六进制偏移 18 得到,EAX 的低 32 位被写入。这个表达式是教学假设,不是当前 Tutorial 实测指令;若使用 Tutorial-i386.exe,应根据窗口实际显示的 32 位寄存器计算。右键查看寄存器和附近指令,将计算出的有效地址与数值地址对照。
mov eax,[rbx+18] 的方向相反,表示读内存;lea rax,[rbx+18] 通常是计算地址而不是读取该地址内容。add、sub 改变结果并更新某些标志位;cmp 根据相减设置标志,后续 je、jne 等条件跳转依赖这些标志。忽略比较和分支,容易只改到显示而没有改变真正的计算。
位宽、寄存器与调用
在 x86 与 x64 中,常见寄存器名称有 EAX 和 RAX;RAX 是 64 位寄存器,EAX 是其低 32 位。写入 EAX 在 x86-64 下会将 RAX 的高 32 位清零,写入 AX 或 AL 则有不同效果。地址宽度、操作数宽度和数值类型是不同概念:64 位进程仍可能使用 32 位整数。
函数调用涉及参数、返回值、堆栈与保存责任。Windows x64 的常见整数或指针参数依次使用 RCX、RDX、R8、R9,但仍需考虑具体调用点、浮点参数、栈空间和编译器生成代码;不可把某个寄存器的瞬时值当成固定参数。调用别的函数前还要考虑栈对齐和调用约定。若不了解其影响,保持练习局限在观察,不贸然插入调用。
验证与常见误判
反汇编视图中逐条记录地址、机器码长度、操作数与上下游条件,触发一次已知操作后检查寄存器,再换一个对象观察是否进入同一段代码。单次观察只能说明这一刻发生了什么,循环和共享代码可能在不同对象上复用同一指令。不要把显示的模块偏移、某一次运行的堆地址或示例中的偏移当作通用常量。
练习验收:不改变内存,解释一条写入指令的目的地址和写入宽度,说明一条相邻条件跳转依赖什么,并重复两次操作验证命中位置。
如果看到的有效地址与地址表不一致,先核对偏移是否以十六进制解释,再检查捕获到的寄存器是否来自同一次命中。对多个线程或对象,记录每一次命中时的上下文有助于区分不同执行路径。