提到编码,只要学过一点汇编的人都应该知道一些常用的汇编指令的编码,比如:B8 78 56 34 12,一看到B8就知道对应的汇编指令是MOV EAX,0X12345678 占用5字节,一看到E8就知道是E8后面跟的是JMP的4字节偏移,一见90就知道是NOP,因为这些指令都很常用,编码也都很简单,想必大家对这些指令编码都熟记于心了。如果提到 MOV EBX,XXXXXXXX  MOV ECX,XXXXXXX这些指令也许大家对指令编码就不怎么记得了,因为X86的编码太多了,要把他全记住那可不是件容易的事。其实要把X86的编码指令记住并不是件难事,因为X86编码指令看似复杂庞大,其实这大部分编码有是有规律可寻的。
在这里先说组寄存器:
0    1    2    3    4    5    6     7
EAX  ECX  EDX  EBX  ESP  EBP  ESI   EDI
0    1    2    3    4    5    6     7
AL   CL   DL   BL   AH  CH   DH    BH
不知道各位同学当年学汇编的时候寄存器是不是按这个顺序记的,如果是按这个顺序记住的话,接下来讲的编码你可能一看就记住了
B8是MOV EAX 大家都很清楚的记得,那么B9呢?B9就是MOV ECX ,BA  MOV EDX 聪明的同学应该很快的看出规律出来了吧!BB 是MOV EBX ,BC是MOV ESP 一直到BF 是MOV EDI
B0是MOV AL,XX 2字节立即数,对照上面的表格,大家应该很容易的说出B1是MOV CL,XX,一直到B7是MOV BH,XX
90是NOP大家都知道,其实他的真正编码指令是XCHG EAX,EAX,91 XCHG EAX,ECX 一直到97 XCHG EAX,EDI
40到47是INC EAX 到 INC EDI ,48到4F是DEC EAX到DEC EDI
50到57是PUSH EAX 到 PUSH EDI ,58到 5F是 POP EAX 到 POP EDI
现在对于这一类的指令编码,大家是不是感觉记起来轻松了
对内存访问的指令在汇编中也经常出现,现在在说说这些指令的编码格式
ADD  OR  ADC  SBB  AND  SUB  XOR  CMP
ES   CS  SS   DS
DAA  DAS  AAA  AAS
就跟上面我说的寄存器一样先按顺序记下这些东西再说
要讲对内存访问的编码就不得不先说说X86通用的编码指令格式




上图参考INTEL开发手册卷二,想具体了解的可以去参考下,看不懂英文的,论坛的翻译版块有部分章节的翻译。大家可以去找找 
Opcode(操作码),之前所说的B8 XX XX XX XX指令B8就代表Opcode(操作码),之后跟的是4字节的Immediate (立即数),一看到B8开头的编码,就要知道B8代表Opcode,后面带有4字节Immediate的属性
在举个列子,B0 XX,B0代表 Opcode,后面带有1字节Immediate的属性
00 是ADD EB,GB (EB代表1字节内存,GB代表8位寄存器)
碰到00编码,00代表着Opcode(操作码),后面的第2个1字节编码就代表着ModR/M
编码    对应的汇编指令
ModR/M字节的二进制6 7位MOD为0
00 00   ADD BYTE PTR DS:[EAX],AL
00 01   ADD BYTE PTR DS:[ECX],AL
。。。。。
00 07   ADD BYTE PTR DS:[EDI],AL 
00 08   ADD BYTE PTR DS:[EAX],CL
。。。。
00 0F   ADD BYTE PTR DS:[EDI],CL
00 10   ADD BYTE PTR DS:[EAX],DL
。。。。
00 3F   ADD BYTE PTR DS:[EDI],BH
ModR/M字节的二进制6 7位MOD为1,第三个编码为1字节Displacement
00 40 XX ADD BYTE PTR DS:[EAX+XX],AL 
00 41 XX ADD BYTE PTR DS:[ECX+XX],AL
。。。。
00 7F XX ADD BYTE PTR DS:[EDI+XX],BH
ModR/M字节的二进制6 7位MOD为2, 从第三个编码开始为4字节Displacement
00 80 XX XX XX XX ADD BYTE PTR DS:[EAX+XXXXXXXX],AL
00 81 XX XX XX XX ADD BYTE PTR DS:[ECX+XXXXXXXX],AL
00 BF XX XX XX XX ADD BYTE PTR DS:[EDI+XXXXXXXX],BH
ModR/M字节的二进制6 7位MOD为3
00 C0   ADD AL,AL
00 C1   ADD CL,AL
。。。。
00 FF   ADD BH,BH
相信大家很轻易的就在上面的列子中找到规律了吧
现在如果写条编码 00 04 大家肯定都会脱口而出ADD BYTE PTR DS:[ESP],AL 
00 05 ADD BYTE PTR DS:[EBP],AL,如果是这样那就不对了,现在我就在来讲下这种特殊情况
当 ModR/M字段的MOD等于 0 1 2的时候,出现[ESP]就接着ModR/M字段后扩展出SIB字段,
这时[ESP]就扩展成SIB的[Base+Index*2^Scale+Displacement] ,Base和Index的值也是代表着EAX到EDI,2^Scale代表比例因子1 2 4 8,当Base等于 ESP EBP的时候就会以SS 为段前辍,其他情况默认为DS
当MOD等于0时,出先[EBP]从第三个字节开始为4字节的Displacement [XXXXXXXX],一般全局变量的访问就是采用这种寻址方式
当MOD等于0时,出现[ESP],SIB的BASE等于5,即EBP,[Base+Index*2^Scale+Displacement]就会变成[Index*2^Scale+Displacement] Displacement这时为4字节
如果还有不明白的,大家可以在调式器直接写编码试试各种情况
00  ADD EB,GB (EB代表1字节内存,GB代表8位寄存器)
01  ADD EV,GV (EV代表4字节内存,GV代表32或8位寄存器)
02  ADD GB,EB (内存到8位寄存器)
03  ADD GV,EV (内存到32位寄存器)
04  XX        ADD AL,IB   (IB代表1字节立即数)
05  XX XX XX XX ADD EAX,ID  (ID代表4字节立即数)
操作码08到0C对应着00到05的格式,只不过ADD指令换成OR指令
相同的10到15为ADC,18到1C为SBB,20到25为AND,28到2C为SUB,30到35为XOR,
38到3C为CMP
到此00到40的编码除了个位为6 7 E F的之外都讲了
06  PUSH ES
07  POP ES
0E  PUSH CS
0F大家一定会脱口而出是POP CS,这样大家又错了,0F这条编码被废弃做为扩展编码,为什么要废弃0F呢?我想因为X86指令提供了RET的指令,而单独的修改CS没啥作用,就废弃掉做为扩展指令,扩展指令这里就不细谈了,因为那又是一片漫长的编码。
16 PUSH SS
17 POP SS
1E PUSH DS
1F POP DS

26表示前缀为ES,编码指令格式中好象就剩下Instruction Prefixes这个字节没讲了
如果从26开始解释一个编码,编码的第一个字节为26,第二个字节才为Opcode(操作码)
举个列子 编码00 00 本来表示指令ADD BYTE PTR DS:[EAX],AL
但如果编码为26 00 00 指令就表示 ADD BYTE PTR ES:[EAX],AL
Instruction Prefixes的作用就是用来修改段寄存器的
2E CS
26 SS
3E DS

27 DAA
37 AAA
2F DAS
3F AAS
这组4个指令关于BCD码的
至此00到40的编码都讲,加上之前的编码都快讲完三分之一,我在这里只启带头的引子作用,有兴趣的同学可以参照INTEL手册的表格把剩余编码全攻克了,一般别人说自己C和汇编学的好时,都说:看C如看汇编,看汇编如看C,如果把剩下的攻克的话就离看编码如看汇编和C的境界差不多了,万层高楼平地起,地基越大扎实了,剩下楼房就随便盖了。小菜第一次写技术文章,加上只有才初中毕业几年的水平,可能写BUG百出,有什么不对的地方,望各位大牛指导,希望此文对跟我一样奋斗的小菜有所帮助

  • 标 题:答复
  • 作 者:dkxzl
  • 时 间:2011-05-08 19:22:19


在上传个反汇编引擎的代码给大家参考下,代码不全,只写了文中讲过的编码指令

上传的附件 disasm.rar