Cheat Engine 常用汇编
Cheat Engine 常用汇编

仅包含 Cheat Engine 常用的寄存器和指令,比如 FPU、MMX 之类的罕见或完全用不到的不在此列出。想了解更多可参考 MSDNasm-dude/wiki。Cheat Engine 汇编器并不完整,部分指令和寄存器无法通过 AAS 汇编

§通用寄存器

使用前记得 push 备份

寄存器低 8 位高 8 位16 位32 位64 位说明
aa/alahaxeaxrax临时变量、返回值
bb/blbhbxebxrbx-
cc/clchcxecxrcx计数器、this 指针、传递参数
dd/dldhdxedxrdx传递参数
sisilsihsiesirsi索引、传递参数
didildihdiedirdi索引、传递参数
r8r8b/r8lr8hr8wr8dr8传递参数
r9r9b/r9lr9hr9wr9dr9传递参数
r10r10b/r10lr10hr10wr10dr10被调用的代码段持有
r11r11b/r11lr11hr11wr11dr11被调用的代码段持有
r12r12b/r12lr12hr12wr12dr12调用的代码段持有
r13r13b/r13lr13hr13wr13dr13调用的代码段持有
r14r14b/r14lr14hr14wr14dr14调用的代码段持有
r15r15b/r15lr15hr15wr15dr15调用的代码段持有

§控制寄存器

除非知道自己在干什么,否则不要去动它

寄存器说明低 8 位高 8 位16 位32 位64 位
bp基址寄存器bplbphbpebprbp
sp堆栈寄存器splsphspesprsp
ip地址寄存器ipliphipeiprip

§SIMD 寄存器

128 位寄存器,可存储 4 个 32位数据或 2 个 64 位数据,一般用于存储标量浮点数据,但也可以作为通用寄存器使用,需要打包数据再操作以提高性能

寄存器寄存器寄存器寄存器寄存器寄存器寄存器寄存器
xmm0xmm1xmm2xmm3xmm4xmm5xmm6xmm7
xmm8xmm9xmm10xmm11xmm12xmm13xmm14xmm15

§堆栈指令

一般而言,在需要进行比较的时候需要通过堆栈备份数据,还有一个常见场景就是借一个寄存器用于中转数据,但也可以观察上下文找到后续必定被改写的寄存器当作临时寄存器;堆栈处理是重中之重,处理不好很容易崩掉应用程序

指令说明
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 PTR8 位
WORD PTR16 位
DWORD PTR32 位
QWORD PTR64 位
未指定与平台同步
指令说明
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无符号双精度,有序比较,我也没弄清楚

§控制指令

修饰说明
SHORT8 位范围内相对跳转(-128 ~ +127)
NEAR16 位范围内相对跳转(-32768 ~ +32767)
FAR32 位范围内绝对跳转,会生成 5 字节 E9 指令
FAR64 位范围内绝对跳转,会生成 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,eaxxmm0 = (Single)eax
cvtsi2ss xmm0,[eax+04]xmm0 = (Single)[eax+04]
cvtsi2sd xmm0,eaxxmm0 = (Double)eax
cvtsi2sd xmm0,[eax+04]xmm0 = (Double)[eax+04]
cvtss2si eax,xmm0eax = (Int32)xmm0
cvtss2si eax,[eax+04]eax = (Int32)[eax+04]
cvtss2sd xmm0,xmm1xmm0 = (Double)xmm0
cvtss2sd xmm0,[eax+04]xmm0 = (Double)[eax+04]
cvtsd2si eax,xmm0eax = (Int32)xmm0,溢出截断
cvtsd2si eax,[eax+04]eax = (Int32)[eax+04],溢出截断
cvtsd2ss xmm0,xmm1xmm0 = (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 之类的指令使用
作者
ragnaroks
发布时间
2022-03-03
更新时间
2022-09-24
创作协议