手动解析指令
现在有一个指令为:0x88 0x01,用如上那张表和我们所学的ModR/M的知识对该指令进行一步步解析。
首先我们知道第一个字节是0x88,再根据官方文档知道其有Gx或Ex这样的参数,那就表示它有ModR/M这个字节,也就表示它是一个变长指令,所以Opcode和ModR/M如下所示:
|
Opcode |
ModR/M |
|
0x88 - MOV Eb, Gb |
0x01 |
接着我们要拆分ModR/M为三个部分,先将其转为2进制:0000 0001,然后拆分:
|
Mod |
Reg/Opcode |
R/M |
|||||
|
0 |
0 |
0 |
0 |
0 |
0 |
0 |
1 |
接着我们对照着表来进行解析就得出了汇编代码:MOV BYTE PTR DS:[ECX], AL

Reg/Opcode
之前我们了解到ModR/M结构可以拆分为三部分,其中Reg/Opcode的描述了G的意义(通用寄存器),但其并不仅仅用来表示寄存器,有时候也可以用来表示Opcode。
在官方文档的Table A-2中,有0x80、0x81、0x82、0x83这几个编码没有给出具体的指令,我们可以看见在原来指令的位置变成了Immediate Grp 1(1A):

首先这个1A我们可以查文档的Table A-1中有描述:

其表示在ModR/M字节的3、4、5位可以作为Opcode的拓宽,也就可以认为其不用来表示通用寄存器了。
而当你看见Immediate Grp的时候就需要带入ModR/M字节的3、4、5位去看Table A-6这张表的内容,才能知道具体的指令是什么:

手动解析指令
现在有一个指令为:0x80 0x65 0x08 0xFF,用如上那张表和我们所学的ModR/M的知识对该指令进行一步步解析。
首先我们知道第一个字节是0x80,再根据官方文档知道其有Gx或Ex这样的参数,那就表示它有ModR/M这个字节,也就表示它是一个变长指令,所以Opcode和ModR/M如下所示:
|
Opcode |
ModR/M |
|
0x80 - XXX Eb, Ib |
0x65 |
接着我们要拆分ModR/M为三个部分,先将其转为2进制:0110 0101,然后拆分:
|
Mod |
Reg/Opcode |
R/M |
|||||
|
0 |
1 |
1 |
0 |
0 |
1 |
0 |
1 |
Mod与R/M字段查Table 2-2得到对应的结构:[EBP+DIS8(8位偏移量)],Reg/Opcode字段根据上文所示那张表就可以得到对应的指令为:AND。
所以最终我们变成了这样的指令:AND [EBP+DIS8], Ib,再带入最后的两个字节(这也是最开始我们了解硬编码结构中的最后2部分)替换DIS8和Ib变成:AND BYTE PTR SS:[EBP+0x08], 0xFF。
SIB
根据之前的了解我们可以知道ModR/M字段是用来进行内存寻址的,可当地址形如DS:[EAX + ECX*2 + 12345678]时,仅仅靠ModR/M字段,是描述不出来的,这时就在ModR/M后面增加一个SIB字节,其与ModR/M字段共同描述。
当你手动解析某一个指令的时候发现出现如下这三种情况,有“[--]”的存在就表示ModR/M字段无法描述出来这段地址,你就需要SIB字节来填充这些“[--]”,也就表示在ModR/M字段之后一定存在SIB。
|
Effetive Address |
Mod |
R/M |
||
|
[--][--] |
00 |
100 |
||
|
[--][--]+disp8 |
01 |
100 |
||
|
[--][--]+disp32 |
10 |
100 |
||
SIB字节的8个位被分成了三部分:

在例子 DS:[EAX + ECX*2 + 12345678] 中,Scale描述2的1次方,Index描述ECX, Base描述EAX,而12345678由ModR/M字段决定,所以SIB字段的描述方式为:
Base + Index * 2的Scale次方 (只能为 *1 *2 *4 *8)
而你要想查询三部分每个对应着什么内容就要去查看Table 2-3:

手动解析指令
现在有一个指令为:0x88 0x84 0x48,其对应的Opcode、ModR/M、SIB如下:
|
Opcode |
ModR/M |
SIB |
|
0x88 - MOV Eb, Gb |
0x84 |
0x48 |
ModR/M转为二进制:1000 0100,拆分如下:
|
Mod |
Reg/Opcode |
R/M |
|||||
|
1 |
0 |
0 |
0 |
0 |
1 |
0 |
0 |
Mod与R/M字段查Table 2-2得到对应的结构:[--][--]+disp32,这就表示需要SIB来进行补充。
SIP转为二进制:0100 1000,拆分如下:
|
Scale |
Index |
Base |
|||||
|
0 |
1 |
0 |
0 |
1 |
0 |
0 |
0 |
接着查Table 2-3,Base对应着EAX,Base和Index就是[ECX*2],最终得到[EAX + ECX*2]。
最终指令就是:MOV [EAX + ECX * 2 + disp32], AL。