首页
社区
课程
招聘
[原创]X86汇编之指令格式解析
发表于: 2014-8-31 12:36 44991

[原创]X86汇编之指令格式解析

2014-8-31 12:36
44991
X86汇编之指令格式解析
前言:
以前在学校编译原理老师总会提到的一句话,在编译器的后端由汇编代码转换为机器码很容易,容易是容易,但是,how??
在编写shellcode的时候,有时候我们需要特定限制的机器码,比如在制造缓冲区溢出的时候strcpy不能出现0这个字节的机器码,这个时候我们需要精挑细选我们的汇编指令让它的机器码不出现0,但是,汇编指令和机器码是怎么转换的??
在破解软件的时候,找到了关键的crack点,需要修改机器码,我们或许可以通过编译器编译一个我们需要的汇编指令以得到机器码,但是我们发现我们选择的汇编指令或长或短总是不尽人意,这就需要我们自己掌握汇编和机器码的转换密码。
偶然在看雪论坛上看到以前的一篇精华贴讲述了这个问题,
http://bbs.pediy.com/showthread.php?t=113402
但是作为小白没太看明白,帖子也不再提供回复功能,所以只有自己动手,丰衣足食了。

正文:
讲述x86指令格式的官方文档intel公司的指令手册,我们有理由相信所有的编译器最终将汇编代码转换为机器码的时候都会参考这个手册。
Intel Manual:下载地址:http://pan.baidu.com/s/1kTp6Qxh

使用vs2008默认编译选项编译一个计算1加到100的小程序
http://pan.baidu.com/s/1pJLmLrt  工程和可执行程序
源码:
int _tmain(int argc, _TCHAR* argv[]) {
  INT i = 0, sum = 0;
  for (i; i <= 100; i++) {
    sum += i;
  }
  printf("%d\n", sum);
  return 0;
}
使用ida打开debug/tmp.exe




我们分析给i赋初值的汇编代码,它的二进制机器码为
C7  45  f8  00  00  00  00      mov  [ebp + i], 0
分析汇编机器码之前我们先了解一下intel 指令格式。打开Intel Manual第二章31页,我们可以看见指令格式如下:

图1
Instruction prefixes: 指令前缀,可选项,每个前缀一个字节,可选0个前缀到4个不等。详细信息参考intel manual 2.2节
Opcode: 操作码,这是唯一不可省略的项,1到2个字节,在某些情况下会有额外的三个位作为补充opcode,这三个位是ModR/M中的Reg/Opcode,稍后会讲述什么情况下reg/opcode作为opcode的补充操作码
ModR/M :一共有三个域,mod,reg/opcode, r/m, reg/opcode 在特定情况下作为opcode的补充操作码,特定情况下作为第二个操作数寄存器,(这里的特定情况容稍后解释)。
Mod域和R/M域总共5个位,定义了32种寻址方式。可选项。
SIB:定义ModR/M的寻址方式的补充寻址方式,可选项,什么时候选后面再说。
Displacement:偏移,可选,0,1,2,4个字节
Immediate: 立即数,可选,0,1,2,4个字节。

好,有了这些准备知识,我们查看手册3.2节指令格式,mov指令格式 442页

图2
第一列是opcode机器码,第二列是汇编指令,第三列是描述
解释:
imm是立即数的意思,而imm8就是指8个比特大小的立即数,
r:寄存器,如r16就代表ax、cx等,r32就代表eax、ebx等
m:内存地址,如[01]、[123]、[0FFFF]等
r/m:寄存器或内存
ib:代表OpCode后面跟着一个byte型数值
iw:代表OpCode后面跟着一个word型数值
id:代表OpCode后面跟着一个dword型数值
/digit:代表此OpCode存在ModR/M结构,且ModR/M结构的reg/opcode域为opcode:opcode的补充操作码
/r:代表此OpCode存在ModR/M结构,且ModR/M结构的reg/opcode域为reg,表示第二个操作码寄存器

1.  找到指令参考,匹配指令的模式
我们的例子:mov  [ebp + i], 0,
是将一个立即数0移动到一个[ebp + i]这样一个内存里,属于指令的最后一种情况
Mov  r/m32,  imm32
这里的0如何判断是32位立即数而不是8位或者16位呢?我们观察[ebp+i]是32位的,而指令格式中并没有出现mov r/m32, imm8或者mov r/m32, imm16,所以可以看出为了适配指令可能的情况,编译器将0认为是32位立即数。
2.  计算opcode
计算这个词可能用的不恰当,因为我们不需要任何计算的步骤,所需要的只是去查表。我们看到匹配上的指令模式的第一列为c7 /0
回顾图1,我们可以得知该指令没有前缀,opcode为c7,由于有/0,所以有ModR/M选项,不确定是否有SIB和displacement,Immediate为4个字节的0。
3.  分析ModR/M
还是只有查看intel manual手册,在2.4节对ModR/M 和 SIB bytes有详细的描述,请参考。笔者着重介绍计算方法,参考36页的表格,如下

图3
对于这个图,intel手册有详细说明,笔者也介绍下,Mod两个字节和R/M三个字节总共5个字节,总共编码32种寻址方式,effective address那一列列出了32种方式,mod为00标识的为寄存器间接寻址,01标识的寄存器相对寻址,且偏移为8位,10标识的寄存器相对寻址,且偏移为32位,11为寄存器直接寻址。
mov  [ebp + i], 0 的寻址方式为寄存器相对寻址,且i为-8,所以8位偏移即可,
所以选择mod为01,R/M为101这行;
另外mov  [ebp + i]查出来的指令为c7 /0, 开始说过了/0 表示reg/opcode域表示为扩展opcode,在图中

 /digit  digit为0,所以opcode为0,它为10进制表示。所以在行列交叉的位置,我们查表得出了ModR/M的值为45
也可以通过计算得到:
mod:01
reg/opcode:000
R/M:101
01 000 101 = 0x45 和查表数据吻合。
(顺便再次说明如果通过指令查出来89 /r ,那么reg/opcode这个域为reg,选择哪一个就根据第二个操作码寄存器来选择具体REG等于多少
比如:的机器码为89 45 f8, 指令为89 /r, 且第二个操作码寄存器为eax,所以reg = 0,查表得到ModR/M为45)

4.  分析displacement
在图2中我们可以发现 ,这个表示寄存器相对寻址,disp8或者disp32表示偏移量为8位或者32位,同时请看note的第2条和第3条

 表明图一中displacement为1个字节或者4个字节,这里的i等于-8,

所以deplacement为一个字节f8,
至此:我们的mov [ebp+i], 0  就全部分析完了。
没有前缀
opcode 为c7
ModR/M 为45 
没有SIB字节
Displacement 为f8
Immediate为 00 00 00 00 ,
整个指令为:c7 45 f8 00 00 00 00 ,哈哈,成功了!!!

5.  SIB字节
我们的示例中没有出现SIB字节,那么它什么时候出现呢??
我们注意图3的note1,

       当出现这种寻址方式的时候需要用到SIB字节来对ModR/M进行补充。在2.4节中对SIB进行了描述,当基址加变址寻址(base-plus-index)和比例寻址(scale-plus-index)的时候需要用到SIB.
示例:(以下部分摘抄看雪帖子http://bbs.pediy.com/showthread.php?t=113402)

01048E  ADD DWORD PTR DS:[ESI+ECX*4], EAX
    我们重新回顾一下所学知识,首先我们分析它的指令格式如下:
引用:
01 /r    ADD r/m32,r32  Add r32 to r/m32
    根据“/r”我们可以得知这是一个有“ModR/M”结构的OpCode,因此查表得出其“ModR/M”信息 
ModR/M 为 04h
    根据“Effective Address”的“[--][--]”可知此OpCode还存在“SIB”结构,于是继续查位于Intel指令手册第37页的表格。
    这里我们要着重分解目的操作数“[ESI+ECX*4]”里的内容,我们可以将其分为两部分,既索引与倍率因子(或叫做比率因子)。
    索引指的是基址,本例中就是ESI了,而倍率因子在本例中则是“ECX*4”,我们先从横排取得倍率因子信息如下:
引用:
Scaled Index  SS  Index
[ECX*4]       10  001

    而后由竖排取得索引信息如下:

r32  ESI
Base=  6
Base=  110

    将其组合起来就是:

SS  Index  Base
10  001    110  = 10001110 = 8Eh

结束语
学习完了x86汇编指令opcode以后我们可以解决前言所提及的问题了,也可以揣测编译器工程师在后端将汇编代码转换为机器码的时候也是捧着这样一本书册仔细研读,做很多的笔记和备注,也知道了为什么大神们会喜爱写xor eax, eax,而不使用mov eax, 0 也明白了为何有的指令长有的指令短,为何汇编代码改变了一点点编译出来的机器码差别很大等等问题。感谢 http://bbs.pediy.com/showthread.php?t=113402 作者 A1Pass

[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

上传的附件:
收藏
免费 6
支持
分享
最新回复 (31)
雪    币: 3407
活跃值: (1237)
能力值: ( LV13,RANK:335 )
在线值:
发帖
回帖
粉丝
2
word格式的版本   http://pan.baidu.com/s/1mgqQLZE
2014-8-31 12:39
0
雪    币: 55
活跃值: (934)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
太感谢了,非常好,不过是不是不完整啊
2014-8-31 12:49
0
雪    币: 3407
活跃值: (1237)
能力值: ( LV13,RANK:335 )
在线值:
发帖
回帖
粉丝
4
对,只是抛砖引玉,完整的信息还是要查看intel manual
2014-8-31 14:06
0
雪    币: 28
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
讲的非常详细啊!楼主辛苦了
2014-8-31 14:53
0
雪    币: 290
活跃值: (68)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
谢谢楼主...!
2014-8-31 17:28
0
雪    币: 6
活跃值: (1104)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
很简洁易懂,感谢楼主
2014-8-31 20:30
0
雪    币: 10867
活跃值: (17252)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
8
来学习一下经验,楼主辛苦了
2014-8-31 21:02
0
雪    币: 245
活跃值: (93)
能力值: ( LV6,RANK:80 )
在线值:
发帖
回帖
粉丝
9
opcode并非1~2个字节,事实上,就算不考虑SIMD,opcode也是1~3个字节。
2014-8-31 22:08
0
雪    币: 3407
活跃值: (1237)
能力值: ( LV13,RANK:335 )
在线值:
发帖
回帖
粉丝
10
算上ModR/M 的reg/opcode确实是1到3个字节,intel手册上描述为1到2个字节,就不要纠结这个小细节了.
2014-8-31 22:30
0
雪    币: 245
活跃值: (93)
能力值: ( LV6,RANK:80 )
在线值:
发帖
回帖
粉丝
11
Intel 手册从来也没描述为1到2个字节。原话是A primary opcode can be 1, 2, or 3 bytes in length。
抛开SIMD,opcode分为:
1)1个字节
2)0x0f+1个字节
3)0x0f 0x38 +1个字节 或者 0x0f 0x3a + 1个字节

我想知道你从哪本intel手册看的描述为1到2个字节?
2014-9-1 00:22
0
雪    币: 3407
活跃值: (1237)
能力值: ( LV13,RANK:335 )
在线值:
发帖
回帖
粉丝
12
文中百度云盘所给的下载地址
Intel Manual:下载地址:http://pan.baidu.com/s/1kTp6Qxh

2.3节
摘抄如下:

The primary opcode is either 1 or 2 bytes. An additional 3-bit opcode field is sometimes encoded
in the ModR/M byte. Smaller encoding fields can be defined within the primary opcode. These
fields define the direction of the operation, the size of displacements, the register encoding,
condition codes, or sign extension. The encoding of fields in the opcode varies, depending on
the class of operation.

也许我所查资料版本过旧,不妨你也将你的文档分享出来
2014-9-1 09:09
0
雪    币: 3407
活跃值: (1237)
能力值: ( LV13,RANK:335 )
在线值:
发帖
回帖
粉丝
13
这位同学,bibibiubiu~~~
2014-9-1 09:14
0
雪    币: 245
活跃值: (93)
能力值: ( LV6,RANK:80 )
在线值:
发帖
回帖
粉丝
14
事实上你那玩意早已经老掉牙了,这才是最新的手册2:http://pan.baidu.com/s/1o6Bf2Fg
2014-9-1 17:04
0
雪    币: 3407
活跃值: (1237)
能力值: ( LV13,RANK:335 )
在线值:
发帖
回帖
粉丝
15
收下了,感谢~~
2014-9-1 22:29
0
雪    币: 245
活跃值: (93)
能力值: ( LV6,RANK:80 )
在线值:
发帖
回帖
粉丝
16
请叫我红领巾
2014-9-1 22:30
0
雪    币: 44229
活跃值: (19965)
能力值: (RANK:350 )
在线值:
发帖
回帖
粉丝
17
传分论坛本地收藏~
上传的附件:
2014-9-2 21:33
0
雪    币: 204
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
18
最近好多人在弄这个反汇编引擎
2014-9-3 00:41
0
雪    币: 163
活跃值: (45)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
19
Mark
2014-9-5 01:47
0
雪    币: 346
活跃值: (25)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
20
好文章!  学习了!
2014-9-5 08:40
0
雪    币: 8
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
21
谢谢分享!
2014-9-8 21:28
0
雪    币: 0
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
22
你用的什么软件编译,连接运行的啊
2014-9-10 11:52
0
雪    币: 3407
活跃值: (1237)
能力值: ( LV13,RANK:335 )
在线值:
发帖
回帖
粉丝
23
vs2010
2014-9-11 17:56
0
雪    币: 346
活跃值: (25)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
24
好贴!!!!
2015-1-3 21:30
0
雪    币: 188
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
25
好帖,学习啦
2015-1-4 00:14
0
游客
登录 | 注册 方可回帖
返回
//