- In this article - 此文
- Instruction Notation - 指令符号
- Memory, Data Transfer, and Data Conversion - 内存,数据传输,数据转换
- Effective Address - 有效的地址
- Data Transfer - 数据传输
- Stack Manipulation - 栈操作
- Data Conversion - 数据转换
- Arithmetic and Bit Manipulation - 算术与位操作
- Arithmetic - 算术
- Binary-coded Decimal - 二进制编码的十进制
- Bits - Bit位
- Control Flow - 控制流
- String Manipulation - 字符串操作
- Flags - 标记位
- Interlocked Instructions - 原子锁指令
- Miscellaneous - 杂项
- Idioms - 常用的
使用*(星号)标记上的都是非常重要的指令,没标记上的都不是关键指令。
在x86 处理,指令是变长的,所以练习逆向的反汇编看到的指令大小也是与此相应变长的。此文的后面blablabla的一堆无用废话真特么懒得翻译,这就是西方的文章特色吗?讲的是断点调试反汇编的位置要选择好而已。因为有些代码优化后,或是有些代码汇编后对应的汇编指令是不指一条的。或是有些代码因为预测、优化等删除了部分源码对应的指令,所以断点是没有反应的。但是原文写的太特么难看,我也不想看,就用自己的话来描述。
Instruction Notation - 指令符号一般的指令符号将目标寄存器放左边,而源寄存器放右边。然而,这个规则有些例外。
算术指令通常有两个寄存器,由源与目标寄存器组合而成。当对两个寄存器(源与目标)算术运算后,结果会写到目标寄存器。(这里的翻译我改了一下,因为原文写的真特么辣鸡,真的很讨厌英文的辣鸡表达方式,但是太多技术起源都是用英文资料的,不然我才不去翻译。这段描述可以这么理解,如:add
算术指令,有dst
, src
两个寄存器,将dst
与src
相加,并将结果设置到dst
,即可:add dst, src;
就是将dst = dst + src
或是dst+=src
的意思)
一些指令有16位与32位版本,但这里只列出32位版本的。这里也不会列出 floating-point 浮点指令,privileged 特权指令,和仅仅用于段模型的指令(Microsoft Win32 不会使用)。
为了节省空间,许多指令都使用合并的形式,如下列例子:
是否重要指令参数意义*MOVr1,r/m/#nr1=r/m/#n第一个参数必须是一个寄存器,但第二个可以是寄存器或是内存地址,或是一个立即数。 (译者jave.lin:上面的r1
就是必须为寄存器
,r/m/#n
对应寄存器/内存地址/立即数
,立即数的时候前面需要价格#
井号,立即数的意思就是一个写死的数值,如#999
)
为了节省更多的空间,指令也可以如下表示:
是否重要指令参数意义*MOVr1/m,r/m/#nr1/m=r/m/#n译者jave.lin:目标值可以是一个寄存器,也可以是一个内存地址
意思是第一个参数可以是一个寄存器,也可以是一个内存地址,而第二个可以是一个寄存器,内存地址,或是立即数。
另外说明一下,dst, src 不能两边都是内存地址。
更进一步的说,带有位宽(8,16,32)的可以附加到源src或是目标dst表示参数必须的位宽大小。例如,r8意思是8bit位的寄存器。
Memory, Data Transfer, and Data Conversion - 内存,数据传输,数据转换内存与数据传输指令不影响标记。
Effective Address - 有效的地址 是否重要指令参数意义*LEAr,m载入有效的地址(r = address of m,r = m的地址例如,LEA eax, [esi+4] 意思 eax = esi + 4。该指令常用语执行算术。
Data Transfer - 数据传输 是否重要指令参数意义MOVr1/m,r2/m/#nr1/m=r2/m/#nMOVr1/m,r/m/#n符号扩展或*MOVZXr,r/m零扩展MOVSX和MOVZX是mov指令的特殊版本,它们执行从源到目标的符号扩展或零扩展。这是仅有的允许源与目标是不同大小的指令(实际上,他们也必须是不同的大小)。
Stack Manipulation - 栈操作栈指针是存放在 esp 寄存器。esp 的值指向栈顶(最近的push,最早的pop的位置),越早存于栈中的元素它的地址将越大(栈的地址增长是负的,几:push会减少esp,pop会增加esp)
是否重要指令参数意义PUSHr/m/#n数值压栈POPr/m数值出栈PUSHFD标记压栈POPFD标记出栈PUSHAD所有整型压栈POPAD所有整型出栈ENTER#n,#n构建栈帧*LEAVE清理栈帧C/C++编译器不会使用enter指令。(enter指令用于如Algol或Pascal程序语言的嵌套调用。)
leave 指令等价于:
mov esp, ebp
pop ebp
Data Conversion - 数据转换
指令意义CBW转换 byte (al) 为 word (ax)。CWD转换 word (ax) 为 dword (dx:ax)CWDE转换 word (ax) 为 dword (eax)CDQ转换 dword (eax) 为 qword (edx:eax)
CBW例子:al = 10000000, ax = 11111111 10000000, if al = 01111111, ax = 00000000 01111111,就是将al的最高位设置到ax的高位中
Arithmetic and Bit Manipulation - 算术与位操作所有算术与位操作指令都会修改flags标记。
Arithmetic - 算术 是否重要指令参数意义ADDr1/m, r2/m/#nr1/m += r2/m/#nADCr1/m, r2/m/#nr1/m += r2/m/#n + 进位SUBr1/m, r2/m/#nr1/m -= r2/m/#nSBBr1/m, r2/m/#nr1/m -= r2/m/#n + 进位NEGr1/mr1/m = -r1/mINCr/mr/m +=1DECr/mr/m -=1CMPr1/m, r2/m/#n计算r1/m - r2/m/#ncmp 指令计算减法与根据减法结果设置 flags 标记,但把结果抛到外面去了。下面通常是配合 jump 指令来测试减法结果来执行跳转。
是否重要指令参数意义MULr/m8ax = al * r/m8MULr/m16dx:ax = ax * r/m16MULr/32edx:eax = eax * r/m32IMULr/m8ax = al * r/m8IMULr/m16dx:ax = ax * r/m16IMULr/m32edx:eax = eax * r/m32IMULr1, r2/mr1 *= r2/mIMULr1, r2/m, #nr1 = r2/m * #n无符号与有符号的操作。在操作过后flags标记的状态是不确定的。
是否重要指令参数意义DIVr/m8(ah, al) = (ax % r/m8, ax / r/m8)ah=ax % (r/m8)的余数,al = ax / (r/m8)的商DIVr/m16(dx, ax) = dx:ax / r/m16DIVr/m32(edx, eax) = edx:eax / r/m32IDIVr/m8(ah, al) = ax / r/m8IDIVr/m16(dx, ax) = dx:ax / r/m16IDIVr/m32(edx, eax) = edx:eax / r/m32无符号与有符号除法。第一个寄存器在伪代码中解释是接收余数,而第二个是接收商。如果目标的结果已出,那么除法会有异常生成。
在除法过后的 flags 标记是不确定的。
是否重要指令参数意义*SETccr/m8设置 r/m8 为 0 或 1如果cc 条件为true,那么8bit位设置为1。否则8bit位设置为0。
Binary-coded Decimal - 二进制编码的十进制你将不会在汇编指令里看到这个指令,除了你在用COBOL调试代码时会编写外。
指令意思DAA十进制的加法DAS十进制的减法上面这些指令在执行二进制编码的十进制操作后会修改 al 寄存器。
指令意思AAAASCII adjust after addition(ASCII的加法)AASASCII adjust after subtraction(ASCII的减法)上面这些指令在执行了二进制编码的十进制操作后会修改 gl 寄存器。
指令意思AAMASCII adjust after multiplication(ASCII的乘法)AADASCII adjust after division(ASCII的除法)上面这些指令在执行了二进制编码的十进制操作后会修改 al 与 ah 寄存器。
Bits - Bit位 是否重要指令参数意义ANDr1/m, r2/m/#nr1/m = r1/m and r2/m/#nORr1/m, r2/m/#nr1/m = r1/m or r2/m/#nXORr1/m, r2/m/#nr1/m = r1/m xor r2/m/#nNOTr1/mr1/m = 按位 r1/m取反*TESTr1/m, r2/m/#n计算r1/m = r1/m and r2/m/#ntest 指令计算逻辑 与 操作并根据结果设置 flags 标记,但不会把结果抛出去。下面列出常见的根据tests逻辑与的条件跳转。
是否重要指令参数意义SHLr1/m, cl/#nr1/m = cl/#n zero-fill*SARr1/m, cl/#nr1/m >>= cl/#n sign-fill最后一个bit位位移后放到进位标记。
是否重要指令参数意义SHLDr1, r2/m, cl/#nShift left double.对double类型左移对 r1 左位移 cl/#n 的位数,并将 r2/m 的最高位(最左边的bit位)填充到 r1 的最低位(最右边的bit位)。r1 最左边被位移出的放置到carry进位标记。 假如r1=0101, r2=1000, #n=1, 就是r1向左位移1位,r1=x101x,最左边的x先抛弃并写入carry进位,最右边的x位将用r2的最左边的bit位(即:最高位)来填入,r2[=1000最高为是1,所以r1=101x中的最右边的x填入1,r1的结果为1011
指令参数意义SHRDr1, r2/m, cl/#nShift right double.对double类型右移对 r1 右位移 cl/#n 位数,并将 r2/m 最低为填入r1的最高位(最左边的bit位)。r1 最右边被位移出的放置到carry进位标记。
指令参数意义BTr1, r2/#n复制 r1 对应的 r2/#n 位到carry标记为。按这么说r1就是mask掩码的作用BTSr1, r2/#n设置 r1 的所有1位 对应的 r2/#n 位上,并将r2复制到carry标记为。BTCr1, r2/#n清理 r1 的所有1位 对应的 r2/#n 位上,并将r2复制到carry标记为。 Control Flow - 控制流 是否重要指令参数意义Jccdest分支条件JMPdest直接跳转CALLdest直接调用*CALLr/m直接调用call 指令先将 return 的地址压栈,然后再跳转到目标地址。
是否重要指令参数意义*RET#n返回返回指令先pop出栈,然后跳转到栈上的return 返回的地址。一个非零的 #n 在 RET 后作为参数,代表pop出栈后的返回地址,#n 值应该被添加到 stack pointer 栈指针里。
指令意义LOOP减少 ecx 的值,如果非零结果,则跳转。LOOPZ减少 ecx 的值,如果非零结果,并且 zr 标记位有被设置了==(zr == 1)==,则跳转。LOOPNZ减少 ecx 的值,如果非零结果,并且 zr 标记位没被设置==(zr == 0)==,则跳转。JECXZ如果 ecx 为零,则跳转。这些指令都是 x86 的 CISC 遗留产物,而在近代处理器实际上会比使用长时间编写的等效机制都要慢。(没看懂)
String Manipulation - 字符串操作 是否重要指令参数意义MOVST将 esi 传送到 edi 上。CMPST比较 esi 和 edi。SCAST扫描 edi 到 accT 上。LODST从 esi 加载到 accT 上。STOST从a ccT 储存 到 edi 上。在操作后,源与目标寄存器都会根据对应设置的 direction flag (方向标记:上或下)来 增加或减少 sizeof(T) 的量。
指令前缀可以使用 REP 来重复操作 ecx 寄存器上指定的次数。
rep mov 指令常用于复制内存块。
rep stos 指令常用于使用 accT 来填充到内存块。
Flags - 标记位 指令意思LAHF从flags 标记为加载到 ah。SAHF储存 ah 的值到 flags 上。STC设置进位。CLC清理进位。CMC完成进位。STD设置方向为下。CLD设置方向为上。STI启用中断。CLI禁用中断。 Interlocked Instructions - 原子锁指令 指令参数意义XCHGr1, r/m交换r1 与 r/m的值。XADDr1, r/m增加r1 到 r/m,上,并将原始值放回 r1。CMPXCHGr1, r/m比较与调整条件。cmpxchg 指令是以下处理流的原子版本:
cmp accT, r/m
jz match
mov accT, r/m
jmp done
match:
mov r/m, r1
done:
Miscellaneous - 杂项
是否重要指令参数意义INT#n捕获内核。BOUNDr,m如果r不在范围内则捕获。*NOP无操作。XLATBal = [ebx + al]BSWAPr在寄存器中交换字节序。(Little Endian/Big Endian)
这里 int 指令有个特殊的情况。
指令参数意义INT3调试器断点捕获。操作码 INT 3 是 0xCC。操作码 NOP 是 0x90。
当调试代码时,你可能需要补上外面的一些代码。你可以使用 0x90 来替换掉有问题的字节。
Idioms - 常用的 是否重要指令参数意义XORr,rr = 0TESTr,r检测 r 是否为零。*ADDr,r左位移r 1位。