Cheat Engine 常用汇编
仅包含 Cheat Engine 常用的寄存器和指令,比如 FPU、MMX 之类的罕见或完全用不到的不在此列出。想了解更多可参考 MSDN 或 asm-dude/wiki。Cheat Engine 汇编器并不完整,部分指令和寄存器无法通过 AAS 汇编
§通用寄存器
使用前记得 push 备份
寄存器 | 低 8 位 | 高 8 位 | 16 位 | 32 位 | 64 位 | 说明 |
---|---|---|---|---|---|---|
a | a/al | ah | ax | eax | rax | 临时变量、返回值 |
b | b/bl | bh | bx | ebx | rbx | - |
c | c/cl | ch | cx | ecx | rcx | 计数器、this 指针、传递参数 |
d | d/dl | dh | dx | edx | rdx | 传递参数 |
si | sil | sih | si | esi | rsi | 索引、传递参数 |
di | dil | dih | di | edi | rdi | 索引、传递参数 |
r8 | r8b/r8l | r8h | r8w | r8d | r8 | 传递参数 |
r9 | r9b/r9l | r9h | r9w | r9d | r9 | 传递参数 |
r10 | r10b/r10l | r10h | r10w | r10d | r10 | 被调用的代码段持有 |
r11 | r11b/r11l | r11h | r11w | r11d | r11 | 被调用的代码段持有 |
r12 | r12b/r12l | r12h | r12w | r12d | r12 | 调用的代码段持有 |
r13 | r13b/r13l | r13h | r13w | r13d | r13 | 调用的代码段持有 |
r14 | r14b/r14l | r14h | r14w | r14d | r14 | 调用的代码段持有 |
r15 | r15b/r15l | r15h | r15w | r15d | r15 | 调用的代码段持有 |
§控制寄存器
除非知道自己在干什么,否则不要去动它
寄存器 | 说明 | 低 8 位 | 高 8 位 | 16 位 | 32 位 | 64 位 |
---|---|---|---|---|---|---|
bp | 基址寄存器 | bpl | bph | bp | ebp | rbp |
sp | 堆栈寄存器 | spl | sph | sp | esp | rsp |
ip | 地址寄存器 | ipl | iph | ip | eip | rip |
§SIMD 寄存器
128 位寄存器,可存储 4 个 32位数据或 2 个 64 位数据,一般用于存储标量浮点数据,但也可以作为通用寄存器使用,需要打包数据再操作以提高性能
寄存器 | 寄存器 | 寄存器 | 寄存器 | 寄存器 | 寄存器 | 寄存器 | 寄存器 |
---|---|---|---|---|---|---|---|
xmm0 | xmm1 | xmm2 | xmm3 | xmm4 | xmm5 | xmm6 | xmm7 |
xmm8 | xmm9 | xmm10 | xmm11 | xmm12 | xmm13 | xmm14 | xmm15 |
§堆栈指令
一般而言,在需要进行比较的时候需要通过堆栈备份数据,还有一个常见场景就是借一个寄存器用于中转数据,但也可以观察上下文找到后续必定被改写的寄存器当作临时寄存器;堆栈处理是重中之重,处理不好很容易崩掉应用程序
指令 | 说明 |
---|---|
push eax | 将 eax 压入栈顶,即 [esp] = eax |
pop eax | 将栈顶的值弹出到 eax,即 eax = [esp] |
pushfd | 将 32 位标识寄存器压入栈顶 |
popfd | 将栈顶的值弹出到 32 位标识寄存器 |
pushfq | 将 64 位标识寄存器压入栈顶 |
popfq | 将栈顶的值弹出到 64 位标识寄存器 |
pushad | 将 32 位寄存器压入栈顶 |
popad | 将栈顶的值弹出到 32 位寄存器 |
pushaq | 将 64 位寄存器压入栈顶 |
popaq | 将栈顶的值弹出到 64 位寄存器 |
call | 设置 IP 为方法地址并将当前 IP 压栈,方法中用 [ebp+04]、[rbp+08] 获得 call 的地址 |
leave | 将 ebp 写入 esp 并从堆栈弹出到 ebp |
ret | 将栈恢复并从栈中弹出 IP 寄存器 |
add esp,04 | 将栈顶拉高 4 个字节 |
sub esp,04 | 将栈顶降低 4 个字节 |
§移动指令
修饰 | 说明 |
---|---|
BYTE PTR | 8 位 |
WORD PTR | 16 位 |
DWORD PTR | 32 位 |
QWORD PTR | 64 位 |
未指定 | 与平台同步 |
指令 | 说明 |
---|---|
mov eax,ebx | 移动寄存器数据,eax = ebx |
mov eax,A0B0 | 移动立即数到寄存器,eax = 0xA0B0 |
mov eax,[eax+A0] | 移动内存数据到寄存器,eax = [eax+A0] |
mov [eax+A0],eax | 移动寄存器数据到内存,[eax+A0] = eax |
mov [eax+A0],A0B0 | 移动立即数到内存,[eax+A0] = 0xA0B0 |
§运算指令
指令 | 说明 |
---|---|
lea eax,[eax+A0B0] | 地址运算,eax = eax + 0xA0B0 |
lea eax,[eax-A0B0] | 地址运算,eax = eax - 0xA0B0 |
inc eax | 数值运算,eax = eax + 1 |
dec eax | 数值运算,eax = eax - 1 |
add eax,A0B0 | 数值运算,eax = eax + 0xA0B0 |
sub eax,A0B0 | 数值运算,eax = eax - 0xA0B0 |
- | - |
sar eax,04 | 算术右移,eax = eax >> 0x04,保留符号,若 eax 为 0x70 则 eax = 112/2/2/2/2 |
sar [eax+04],04 | 同上 |
shr eax,04 | 逻辑右移,eax = eax >> 0x04,补 0 |
shr [eax+04],04 | 同上 |
sal eax,04 | 算术左移,eax = eax << 0x04,保留符号,若 eax 为 0x07 则 eax = 7*2*2*2*2 |
sal [eax+04],04 | 同上 |
shl eax,04 | 逻辑左移,eax = eax << 0x04,补 0 |
shl [eax+04],04 | 同上 |
shld eax,ebx,04 | 逻辑左移,从 ebx(00110011) 左移 4 位到 eax(00000000) => 00000011 |
shld [eax+04],ebx,04 | 同上 |
shrd eax,ebx,04 | 逻辑右移,从 ebx(00110011) 右移 4 位到 eax(00000000) => 00110000 |
shrd [eax+04],ebx,04 | 同上 |
- | - |
and eax,ebx | 逻辑与 |
and eax,[ebx+04] | 同上 |
and [eax+04],ebx | 同上 |
test eax,ebx | 类似 cmp,只设置标志位,不修改寄存器,常用于判断是否为 0 |
test eax,[ebx+04] | 同上 |
test [eax+04],ebx | 同上 |
not eax | 逻辑非,亦称为反转,按位取反 |
or eax,ebx | 逻辑或 |
or eax,[ebx+04] | 同上 |
or [eax+04],ebx | 同上 |
xor eax,ebx | 逻辑异或 |
xor eax,[ebx+04] | 异或 |
xor [eax+04],ebx | 异或 |
xor eax,eax | 异或特殊用法,可用最低代价清空指定寄存器 |
xorps xmm0,xmm1 | 逻辑异或 |
xorps xmm0,[ebx+04] | 逻辑异或 |
xorps xmm0,xmm0 | 异或特殊用法,可用最低代价清空指定寄存器 |
- | - |
mul ebx | 无符号乘,edx:eax = eax * ebx,用 edx 和 eax 联合出一个 64 位寄存器存放结果,其它位数操作与此一致 |
mul DWORD PTR [ebx+04] | 无符号乘,edx:eax = eax * [ebx+04],用 edx 和 eax 联合出一个 64 位寄存器存放结果,其它位数操作与此一致 |
div ebx | 无符号除,eax = edx:eax / ebx,edx = edx:eax % ebx,其它位数操作与此一致 |
div DWORD PTR [ebx+04] | 无符号除,eax = edx:eax / [ebx+04],edx = edx:eax % [ebx+04],其它位数操作与此一致 |
imul ebx | 有符号乘,edx:eax = eax * ebx,用 edx 和 eax 联合出一个 64 位寄存器存放结果,其它位数操作与此一致 |
imul DWORD PTR [ebx+04] | 有符号乘,edx:eax = eax * [ebx+04],用 edx 和 eax 联合出一个 64 位寄存器存放结果,其它位数操作与此一致 |
imul eax,ebx | 有符号乘,eax = eax * ebx,溢出丢弃并设置标志位,其它位数操作与此一致 |
imul eax,DWORD PTR [ebx+04] | 有符号乘,eax = eax * [ebx+04],溢出丢弃并设置标志位,其它位数操作与此一致 |
imul eax,A0B0 | 有符号乘,eax = eax * 0xA0B0,溢出丢弃并设置标志位,其它位数操作与此一致 |
imul eax,ebx,A0B0 | 有符号乘,eax = ebx * 0xA0B0,溢出丢弃并设置标志位,其它位数操作与此一致 |
imul eax,DWORD PTR [ebx+04],A0B0 | 有符号乘,eax = [ebx+04] * 0xA0B0,溢出丢弃并设置标志位,其它位数操作与此一致 |
idiv ebx | 有符号除,eax = edx:eax / ebx,edx = edx:eax % ebx,溢出异常,其它位数操作与此一致 |
idiv DWORD PTR [ebx+04] | 有符号除,eax = edx:eax / [ebx+04],edx = edx:eax % [ebx+04],溢出异常,其它位数操作与此一致 |
§比较指令
关于浮点数比较部分可以参考x86架构中UCOMISS浮点比较指令所产生的条件码
指令 | 说明 |
---|---|
cmp eax,ebx | 无符号,用减法的方式比较两个寄存器并设置标志位 |
cmp eax,[eax+04] | 无符号,用减法的方式比较寄存器和内存数据并设置标志位 |
cmp [eax+04],eax | 无符号,用减法的方式比较寄存器和内存数据并设置标志位 |
- | - |
ucomiss xmm0,xmm1 | 无符号单精度,用减法的方式比较两个寄存器并设置标志位 |
ucomiss xmm0,[eax+04] | 无符号单精度,用减法的方式比较寄存器和内存数据并设置标志位 |
comiss xmm0,xmm1 | 有符号单精度,用减法的方式比较两个寄存器并设置标志位 |
comiss xmm0,[eax+04] | 有符号单精度,用减法的方式比较寄存器和内存数据并设置标志位 |
ucomisd xmm0,xmm1 | 无符号双精度,用减法的方式比较两个寄存器并设置标志位 |
ucomisd xmm0,[eax+08] | 无符号双精度,用减法的方式比较寄存器和内存数据并设置标志位 |
comisd xmm0,xmm1 | 有符号双精度,用减法的方式比较两个寄存器并设置标志位 |
comisd xmm0,[eax+08] | 有符号双精度,用减法的方式比较寄存器和内存数据并设置标志位 |
- | - |
cmpss xmm0,xmm1,0 | 无符号单精度,xmm0 = xmm0 == xmm1 ? +0.0 : -QNaN |
cmpss xmm0,xmm1,1 | 无符号单精度,xmm0 = xmm0 < xmm1 ? +0.0 : -QNaN |
cmpss xmm0,xmm1,2 | 无符号单精度,xmm0 = xmm0 <= xmm1 ? +0.0 : -QNaN |
cmpss xmm0,xmm1,3 | 无符号单精度,无序比较,我也没弄清楚 |
cmpss xmm0,xmm1,4 | 无符号单精度,xmm0 = xmm0 != xmm1 ? +0.0 : -QNaN |
cmpss xmm0,xmm1,5 | 无符号单精度,xmm0 = xmm0 >= xmm1 ? +0.0 : -QNaN |
cmpss xmm0,xmm1,6 | 无符号单精度,xmm0 = xmm0 > xmm1 ? +0.0 : -QNaN |
cmpss xmm0,xmm1,7 | 无符号单精度,有序比较,我也没弄清楚 |
cmpsd xmm0,xmm1,0 | 无符号双精度,xmm0 = xmm0 == xmm1 ? +0.0 : -QNaN |
cmpsd xmm0,xmm1,1 | 无符号双精度,xmm0 = xmm0 < xmm1 ? +0.0 : -QNaN |
cmpsd xmm0,xmm1,2 | 无符号双精度,xmm0 = xmm0 <= xmm1 ? +0.0 : -QNaN |
cmpsd xmm0,xmm1,3 | 无符号双精度,无序比较,我也没弄清楚 |
cmpsd xmm0,xmm1,4 | 无符号双精度,xmm0 = xmm0 != xmm1 ? +0.0 : -QNaN |
cmpsd xmm0,xmm1,5 | 无符号双精度,xmm0 = xmm0 >= xmm1 ? +0.0 : -QNaN |
cmpsd xmm0,xmm1,6 | 无符号双精度,xmm0 = xmm0 > xmm1 ? +0.0 : -QNaN |
cmpsd xmm0,xmm1,7 | 无符号双精度,有序比较,我也没弄清楚 |
§控制指令
修饰 | 说明 |
---|---|
SHORT | 8 位范围内相对跳转(-128 ~ +127) |
NEAR | 16 位范围内相对跳转(-32768 ~ +32767) |
FAR | 32 位范围内绝对跳转,会生成 5 字节 E9 指令 |
FAR | 64 位范围内绝对跳转,会生成 14 字节 FF 25 指令,一般不会这样用而是借用寄存器跳转 |
未指定 | 平台相关,例如 64 位平台将生成 14 字节指令 |
jg、jl 使用 OF、AF、SF 标志位,而 ja、jb 使用 ZF、CF、PF 标志位
指令 | 说明 |
---|---|
mov eip,eax | 设置 IP 为 eax |
pop eip | 从栈顶弹出到 IP |
call | 设置 IP 为方法地址并将当前 IP 压栈,方法中用 [ebp+04]、[rbp+08] 获得 call 的地址 |
ret | 将栈恢复并从栈中弹出 IP 寄存器 |
jmp eax | 设置 IP 为 eax |
jmp [eax+04] | 设置 IP 为 [eax+04] |
je eax | 等于条件,设置 IP 为 eax |
je [eax+04] | 等于条件,设置 IP 为 [eax+04] |
jne eax | 不等于条件,设置 IP 为 eax |
jne [eax+04] | 不等于条件,设置 IP 为 [eax+04] |
jg eax | 大于条件,设置 IP 为 eax |
jg [eax+04] | 大于条件,设置 IP 为 [eax+04] |
jge eax | 大于等于条件,设置 IP 为 eax |
jge [eax+04] | 大于等于条件,设置 IP 为 [eax+04] |
jl eax | 小于条件,设置 IP 为 eax |
jl [eax+04] | 小于条件,设置 IP 为 [eax+04] |
jle eax | 小于等于条件,设置 IP 为 eax |
jle [eax+04] | 小于等于条件,设置 IP 为 [eax+04] |
jng | 同 jle |
jnl | 同 jge |
ja eax | 大于条件,设置 IP 为 eax |
ja [eax+04] | 大于条件,设置 IP 为 [eax+04] |
jae eax | 大于等于条件,设置 IP 为 eax |
jae [eax+04] | 大于等于条件,设置 IP 为 [eax+04] |
jb eax | 小于条件,设置 IP 为 eax |
jb [eax+04] | 小于条件,设置 IP 为 [eax+04] |
jbe eax | 小于等于条件,设置 IP 为 eax |
jbe [eax+04] | 小于等于条件,设置 IP 为 [eax+04] |
jna | 同 jbe |
jnb | 同 jae |
§转换指令
指令 | 说明 |
---|---|
cvtsi2ss xmm0,eax | xmm0 = (Single)eax |
cvtsi2ss xmm0,[eax+04] | xmm0 = (Single)[eax+04] |
cvtsi2sd xmm0,eax | xmm0 = (Double)eax |
cvtsi2sd xmm0,[eax+04] | xmm0 = (Double)[eax+04] |
cvtss2si eax,xmm0 | eax = (Int32)xmm0 |
cvtss2si eax,[eax+04] | eax = (Int32)[eax+04] |
cvtss2sd xmm0,xmm1 | xmm0 = (Double)xmm0 |
cvtss2sd xmm0,[eax+04] | xmm0 = (Double)[eax+04] |
cvtsd2si eax,xmm0 | eax = (Int32)xmm0,溢出截断 |
cvtsd2si eax,[eax+04] | eax = (Int32)[eax+04],溢出截断 |
cvtsd2ss xmm0,xmm1 | xmm0 = (Single)xmm0,溢出截断 |
cvtsd2ss xmm0,[eax+04] | xmm0 = (Single)[eax+04],溢出截断 |
§杂项
指令 | 说明 |
---|---|
DB | 写入字节,DB 67 45 23 01 就是 dd 0x1234567 |
$opreate $count DUP($byte) | 重复,DB 16 DUP(90) 就是连续写入 16 个 nop,这里的 16 是十进制 |
align $widthSize | 地址对齐,align 4 即是让接下来的一行对齐到 4 字节,配合 movaps 之类的指令使用 |