强大的x86指令

收集两个指令,参考格蠹汇编和高级调试网站

AdvDbg System Section : 强大的x86指令

函数开头的通用写法

00401013 83ec40           sub     esp,40h
00401016 53               push    ebx
00401017 56               push    esi
00401018 57               push    edi
00401019 8d7dc0           lea     edi,[ebp-40h]
0040101c b910000000       mov     ecx,10h
00401021 b8cccccccc       mov     eax,0CCCCCCCCh
00401026 f3ab             rep stos dword ptr es:[edi]

1. 最上面的减法指令是把栈指针向低地址方向调整,相当于腾出(分配)一段空间给当前函数中的局部变量使用。

2. 接下来的3个push语句是把EBXESIEDI这3个寄存器的值保存到栈上,防止当前函数破坏了它们的值,根据约定,返回到父函数时这几个寄存器的值应该保持不变。

3. 再下面的4条指令是把刚刚分配的局部变量区全部填充为0xCC,也就是INT 3指令(断点)的机器码;

1)lea指令是把这段空间的起始地址放到EDI寄存器

2)第一个mov指令是把空间的长度(以DWORD为单位)放入ECX寄存器

3)第二个mov指令是把填充内容放入EAX寄存器

4)最后的rep stos指令是具有循环功能的串指令,它把EAX的值存入EDI指向的内存,然后自动递增EDI,递减ECX。这条串指令的机器码只有两个字节(0xf3ab)​,真可谓是精悍。

再说明一下两个著名串指令

在下面这条循环赋值(串赋值)指令中,ESI和EDI分别指向源和目标,ECX用作计数器,控制要复制的长度。

rep movs dword ptr es:[edi],dword ptr [esi]

CPU执行这条指令时,会自动调整ESI、EDI和ECX的值,循环执行。著名的memcpy函数内部就使用了这条指令。

类似地,memset函数内部主要依靠的是下面这条串存储指令:

rep stos dword ptr es:[edi]

这条指令执行时,CPU会将EAX中的值写到EDI指向的内存,然后调整EDI和ECX。

值得一提的是,上面这两条串指令的机器码都只有两个字节,分别是0xf3a50xf3ab

一个复杂表达式

今天调试一个应用程序时,偶然中看到一条很长的x86指令,机器码有11个字节,目标操作数是一个堪称复杂的表达式,于是摘录下来。

1020f789 c78491c400000000000000 mov dword ptr [ecx+edx*4+0C4h],0

其中:

  • 1020f789是这条指令的线性地址
  • c78491c400000000000000是机器码
  • mov dword ptr [ecx+edx*4+0C4h],0是指令的助记符,MOV是操作码,dword ptr [ecx+edx*4+0C4h]是目标操作数,0是源操作数

晚上回到家里后,拿出IA手册来查,虽然手册很厚,但是手册里描述的还是非常清楚明了,很快就明白了11个机器码的意义

  • c7是“MOV r/m32, imm32”这种形式的MOV指令的操作码(Op Code),MOV指令可以说是形式最多的一条x86指令,根据操作数的类型的不同,又细分为很多种。比如“MOV r/m32, imm32”代表的是目标操作数是内存或者寄存器,而源操作数是立即数。也就是把一个立即数赋值给一个变量(在寄存器或者内存中)。
  • 84是所谓的ModR/M字节,简单说就是用来指定地址模式,有时也翻译为取址模式,其中的R代表寄存器,M代表内存。ModR/M字节的编码在IA手册中有一张表可以查,
  • 84代表的是[--][--]+disp32,表下的备注解释了[--][--]的意思:
  • The [--][--] nomenclature means a SIB follows the ModR/M byte
  • 通常方括号里是寄存器的名字,而这里,用这种形式表示,寄存器的使用方法是用接下来的一个字节单独描述的。这个字节有个专门的名字叫SIB。SIB代表的是Scale,Index和Base
  • 91便是SIB字节,它的编码也有一张表,查表得知,ECX是Base,Index和Scale[EDX*4](Scale是4,EDX是Index)。
  • 接下来的4个字节(32位)c4000000是“位移(displacement)”,也84所代表的[--][--]+disp32中的disp32
  • 最后的四个字节是立即数

那么这样的复杂指令用来做什么呢?一种典型的使用场合就是用来循环处理一个数组,ECX指向数组的基地址,EDX做循环变量,索引数组的元素,而数组元素的长度可以为2、4、8三种。设计的真是别具匠心啊!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值