第一节
先来看看intel文档的经典图示:
解释:
就是说,intel指令可以在长度上不同,但是都是由以上六组构成的:
(1)optional instruction prefixes (in any order)
(2)one or two primary opcode bytes
(3)an addressing-form specifier (if required) consisting of the ModR/M byte
(4)the SIB (Scale-Index-Base) byte
(5)a displacement (if required)
(6)an immediate data field (if required)
1.指令前缀,这个是可选的,可以没有,就是说可以有0,1,2,3,4个前缀,每一个前缀只占用一个字节,也就是说,最多有4个字节的前缀。着五种选择有:
1)。段寄存器前缀(segment):2E,36,3E,26,64,65——CS,SS,DS,ES,FS,GS 2)。操作数长度前缀(operand-size):可以改变操作数长度 66
3)。地址长度前缀(address-size):可以改变地址长度 67 4)。重复前缀(rep/repne):F3 F2 5)。总线加锁前缀(LOCK):控制处理器总线 F0 这样的五种,下面作出详细的说明:
1)例子:
8B00 MOV EAX,DWORD PTR DS:[EAX] 2E:8B00 MOV EAX,DWORD PTR CS:[EAX] 36:8B00 MOV EAX,DWORD PTR SS:[EAX] 可以看到默认情况下是使用了DS的
2)操作数前缀,允许一个程序在16/32位操作数长度之间转换,默认下市32位的,就是说,如果加前缀66H,就会转换成16位的指令:
89 C0 MOV EAX,EAX 66 89 C0 MOV AX,AX
3)地址长度前缀,也是和2)一样的,表示16/32位的寻址方式,在win32下编程一般是不用管的:
8B00 MOV EAX,DWORD PTR DS:[EAX]——32bit寻址模式 67:8B00 MOV EAX,DWORD PTR DS:[BX+SI]——16bit寻址模式 4)重复前缀,将会重复操作字符串的每一个元素。
只有MOVS,CMPS,SCAS,LODS,STOS,INS,OUTS等字符串操作或I/O指令才能使用这些前缀,举例子:
AD LODS DWORD PTR DS:[ESI]
F3 AD REP LODS DWORD PTR DS:[ESI] F2 AD REPNE LODS DWORD PTR DS:[ESI]
5)。总线加锁,这一部分目前还没有涉及,但是如果想知道intel的所有秘密来反汇编,就需要仔细的了解了,还有病毒什么的。。。。(不明)
总之,prefix主要起了三个作用:调整、加强、附加,要彻底了解x86 prefix,必须清楚了解3个很重要的上下文环境:缺省operand-size和缺省 addess-size环境,编译器上下文环境以及当前执行上下文环境。
2.操作码,opcode就是这儿了,这个就是解码的关键部分了,从字长上分为:
1)首先是1字节操作码: 2)然后是双字节操作码: 3)最后是三字节操作码:
之所以说这儿是核心,是因为Opcode、ModRM以及SIB,这三者的已经是紧密结合,无论分开谁单独来讲都不能透切的了解x86的指令编码体系,这三部分就是对于一般看见的诸如:
MOV EAX,ECX
这样的汇编代码进行恢复的关键要素了!通过查找相对应的表,再对这三个部分综合分析,就可以从机器码中得到确切的汇编代码了。
这个部分有四个表格:
One-byte Opcode Map: (00H — FFH)
Two-byte Opcode Map: 00H — FFH (First Byte is 0FH)
Three-byte Opcode Map: 00H — FFH (First Two Bytes are 0F 38H) Three-byte Opcode Map: 00H — FFH (First two Bytes are 0F 3AH)
但是三字节的表格还没有填满,说明intel以后还会有新的指令添加,而且一般而言三字节指令也是基本不会涉及的。
还需要注意的有,标记有1A上标的指令需要把ModR/M中的第3,4,5位作为opcode extension使用,在查表的时候需要仔细的注意了,同时也说明了Opcode、ModRM以及SIB这三个部分紧密的联系!
(再有就是opcode表的分组了,现在还是不是很清楚这个作用!第三节中会详细的讲解。)
3.ModR/M,这个是告诉处理器哪一个寄存器或者内存地址被使用了,只有一个字节。许多涉及内存操作数的指令都有一个紧挨着主操作码的寻址格式说明字节,这就是ModR/M字节,ModR/M字节包含3个域信息(在一个字节中的不同位):
1)mod域与r/m域组合有32个可能的值:8个寄存器和24个寻址模式。 其中的mod只有2位:6-7 R/m位有三个:0-2
所以组合有5位,2^5=32
2)reg/opcode域确定寄存器号或者附加的3位操作码。reg/opcode域的用途由主操作码确定。在其中的:3-5位。
这个字段被认为是代码扩展字段或者作为寄存器字段,处理器知道哪一个右侧编码相对于这个字段:
——如果为代码扩展字段(code extension),有的指令需要一个操作数,而有的需要两个操作数
——如果是寄存器字段
3)r/m域确定一个寄存器为操作数或者和mod域一起编码寻址模式。有时候有些指令使用特定的mod域和r/m域组合来表示操作码信息。
所以这一部分的内容就需要仔细的加以区分了,详细情况完了补充一下:
这个部分有2个表格需要仔细的参考:
16-Bit Addressing Forms with the ModR/M Byte 32-Bit Addressing Forms with the ModR/M Byte
一般而言,现在X86编程只需要32位的这个图表了。
4.SIB字节,Scale-Index-Base,他的作用是在ModRM 无法提供更多内存寻址方式时,使用SIB进行协助寻址,对base+index*scale+disp这种寻址模式下的内存操作数寻址提供补充定义。
一般的格式是:Scale*Index+Base,也是有一个字节,分不同的位来起作用: 7——6——5—4—3——2——1——0 Scale index base
就是说:0-2是base,3-5是index,6-7是scale Scale被认为是index寄存器的乘数
<1>00:2^0=1 < = > *1 <2>01:2^1=2 < = > *2 <3>10:2^2=4 < = > *4 <4>11:2^3=8 < = > *8
Index是一个寄存器(除了ESP),如果索引寄存器是ESP就会被忽略,scale也就被忽略了 Base是基础寄存器(base register)
这个部分也有1个图表需要参考:
32-Bit Addressing Forms with the SIB Byte
5.偏移量
6.立即数
以上就是一个基本的intel指令的格式要求了,具体的内容还有待于进一步的完善,自己学一些就写一些了,难度还是有的,所以需要分阶段的学习了20110124凌晨
学习完成第二课,回过头来补充资料完成,于20110124凌晨
第二节
20110124中午继续
现在来看看一个例子:
在当前32位机器,32位系统下,有如下汇编指令: mov word ptr es:[eax + ecx * 8 + 0x11223344], 0x12345678
分析这条汇编码:
这是一条 mov 指令,目标操作数是 mem, 源操作数是 imme,
注意:我特地将操作数的大小定为是word(2个字节),而不是 dword,源操作数故意定为0x12345678,这个dword大小的立即。
对应的机器编码是:26 66 c7 84 c8 44 33 22 11 78 56
现在,我对这个机器码略为解释一下:
26: 在指令序列里是:prefix部分,作用是调整内存操作数的段选择子 66: 在指令序列里是:prefix 部分,作用是调整操作数的缺省大小 C7: 在指令序列里是:Opcode部分,是mov指令是操作码 84: 在指令序列里是:ModRM值,定义操作数的属性 C8: 在指令序列里:SIB值定义内存操作数的属性 44332211: 在指令序列里是: displacement 值 7856: 在指令序列里是:immediate值
疑问:optional instruction prefixes (in any order)就像官方文档的说明一样,是可以任何顺序的吗? 这个是可以的,前缀是不区分顺序的!
现在来看一看编码序列:
如图,这个编码序列分为Legacy Prefix、REX prefix、Opcode、ModRM、SIB、Displacement以及 Immediate 7个部分。这个顺序就是实现反汇编引擎的核心了! 实际上,将功能组别,我将这个指令序列分为4个部分,分别为:Prefix、Opcode、ModRM/SIB、Disp/Imme,解释如下:
● Prefix(前缀):
AMD推出x86扩展64位技术时,增加了一个用于扩展访问64位数据的 REX prefix,而x86的prefix 是 Legacy prefix。
在x86模式下,REX prefix是无效的。但是,在x64的64位下 Legacy prefix 是有效的。
● Opcode(操作码):
大多数通用指令Opcode是单字节,最多是2字节,但是对有些Float指令和SSEx midea指令来说是3个字节的。
● ModRM/SIB:
ModRM字节实际意义为:mod-reg-rm,按 2-3-3 比例划分字节,SIB 意即:Sacle-Index-Base 也是按2-3-3比例划分字节。
这两个字节用来修饰指令操作数。
● Disp/Imme:
Displacement最大可为8个字节64位,当然8个字节的displacment只有在x64平台下才会有,displacement也可理解为 offset。同样immediate最大可为8个字节,同样在x64下台才会有的。 需要注意的一点是:displacement 和 immediate都是符号数(single),在32位下,小于32位被符号扩展至32位,在64位下,小于64位会被符号扩展64位。
下面分析一个机器码反汇编的例子来仔细研究一下intel的反汇编核心内容,opcode。
例子:26 c7 84 c8 44 33 22 11 78 56 34 12 分析这个机器码序列,如下:
(1) 26是prefix,这是segment-override prefix,指明是ES段选择子 (2) c7是Opcode,表明这个指令是 mov reg/mem, imme (3) 84是ModRm,即:10-000-100。 (4) c8 是 SIB,即:11-001-000
(5) 44332211 是disp,是32位displacement值 (6) 78563412 是 imme,是32位immediate值 我们先按照字面意思翻译就是:
mov dword ptr es:[eax + ecx * 8 + 0x11223344], 0x12345678
可是这样还是有问题的,虽然指令对了,但是我们还没有理解这其中的细节信息!
所以这里有一个问题,就是opcode的属性是什么啊?
首先来仔细看看Opcode属性的关键字:
(1)寻址方式关键字:
A Direct address. The instruction has no ModR/M byte; the address of the operand is en- coded in the instruction; and no base register, index register, or scaling factor can be applied (for example, far JMP (EA)).
百度搜索“77cn”或“免费范文网”即可找到本站免费阅读全部范文。收藏本站方便下次阅读,免费范文网,提供经典小说综合文库intel汇编指令格式学习 - 图文在线全文阅读。
相关推荐: