1.windows硬编码简介
od中中间这一栏就是所谓的硬编码,这是计算机能够识别的真正代码,计算机不能直接执行汇编和c语言代码,这个才是操作系统识别的指令。

1.1 硬编码结构
指令编码的结构如下图所示:

指令说明如下:
- 0、每一条指令,最短1字节,最长15字节
- 1、Intel对指令参数的设计了一种表示方式,格式是Zz一个大写字母加上一个小写字母。
- 2、大写字母表示寻找方式编码(寄存器,ModR/M,跳转相对地址,16:32地址格式等等),从A-Z共26种.
- 3、小写字母表示操作数的类型(byte,word,dword,fword等等不定,根据cpu模式或改写指令决定)。z有大约十几种表示方式。
- 4、他们的组合再加上纯寄存器表示了intel的所有操作对象。
2.经典定长指令上(修改寄存器)
2.1 push系列
| 指令码 | 汇编码 |
|---|---|
| 0x50 | PUSH EAX |
| 0x51 | PUSH ECX |
| 0x52 | PUSH EDX |
| 0x53 | PUSH EBX |
| 0x54 | PUSH ESP |
| 0x55 | PUSH EBP |
| 0x56 | PUSH ESI |
| 0x57 | PUSH EDI |
2.2 pop系列
| 指令码 | 汇编码 |
|---|---|
| 0x58 | POP EAX |
| 0x59 | POP ECX |
| 0x5A | POP EDX |
| 0x5B | POP EBX |
| 0x5C | POP ESP |
| 0x5D | POP EBP |
| 0x5E | POP ESI |
| 0x5F | POP EDI |
2.3 INC/DEC系列
| 指令码 | 汇编码 |
|---|---|
| 0x40 | INC EAX |
| 0x41 | INC ECX |
| 0x42 | INC EDX |
| 0x43 | INC EBX |
| 0x44 | INC ESP |
| 0x45 | INC EBP |
| 0x46 | INC ESI |
| 0x47 | INC EDI |
| 0x48 | DEC EAX |
| 0x49 | DEC ECX |
| 0x4A | DEC EDX |
| 0x4B | DEC EBX |
| 0x4C | DEC ESP |
| 0x4D | DEC EBP |
| 0x4E | DEC ESI |
| 0x4F | DEC EDI |
2.4 MOV Rb, Ib系列
| 指令码 | 汇编码 |
|---|---|
| 0xB0 | MOV AL, 一byte立即数 |
| 0xB1 | MOV CL, 一byte立即数 |
| 0xB2 | MOV DL, 一byte立即数 |
| 0xB3 | MOV BL, 一byte立即数 |
| 0xB4 | MOV AH, 一byte立即数 |
| 0xB5 | MOV CH, 一byte立即数 |
| 0xB6 | MOV DH, 一byte立即数 |
| 0xB7 | MOV BH, 一byte立即数 |
2.5 MOV ERX, Id系列
| 指令码 | 汇编码 |
|---|---|
| 0xB8 | MOV EAX, 两byte立即数 |
| 0xB9 | MOV ECX, 两byte立即数 |
| 0xBA | MOV EDX, 两byte立即数 |
| 0xBB | MOV EBX, 两byte立即数 |
| 0xBC | MOV ESP, 两byte立即数 |
| 0xBD | MOV EBP, 两byte立即数 |
| 0xBE | MOV ESI, 两byte立即数 |
| 0xBF | MOV EDI, 两byte立即数 |
2.6 XCHG EAX, ERX系列
| 指令码 | 汇编码 |
|---|---|
| 0x90 | NOP |
| 0x91 | XCHG EAX,ECX |
| 0x92 | XCHG EAX,EDX |
| 0x93 | XCHG EAX,EBX |
| 0x94 | XCHG EAX,ESP |
| 0x95 | XCHG EAX,EBP |
| 0x96 | XCHG EAX,ESI |
| 0x97 | XCHG EAX,EDI |
3.经典定长指令(修改EIP)
3.1 0x70 - 0x7F系列条件跳转
- 条件跳转后跟一个字节立即数的偏移(有符号),共两个字节。
- 如果条件成立,跳转到 当前指令地址 + 当前指令长度 + Ib
- 最大值:向前跳7f,向后跳80
| 指令码 | 汇编码 |
|---|---|
| 0x70 | JO |
| 0x71 | JNO |
| 0x72 | JB/JNAE/JC |
| 0x73 | JNB/JAE/JNC |
| 0x74 | JZ/JE |
| 0x75 | JNZ/JNE |
| 0x76 | JBE/JNA |
| 0x77 | JNBE/JA |
| 0x78 | JS |
| 0x79 | JNS |
| 0x7A | JP/JPE |
| 0x7B | JNP/JPO |
| 0x7C | JL/JNGE |
| 0x7D | JNL/JGE |
| 0x7E | JLE/JNG |
| 0x7F | JNLE/JG |
3.2 0x0F0x80 - 0x0F0x8F系列条件跳转
- 条件跳转,后跟四个字节立即数的偏移(有符号),共五个字节。
- 如果条件成立,跳转到 当前指令地址 + 当前指令长度 + Id
- 最大值:向前跳7FFFFFFFF,向后跳80000000
| -指令码的十六进制- | -对应的汇编代码- |
|---|---|
| 0x0F0x80 | JO |
| 0x0F0x81 | JNO |
| 0x0F0x82 | JB/JNAE/JC |
| 0x0F0x83 | JNB/JAE/JNC |
| 0x0F0x84 | JZ/JE |
| 0x0F0x85 | JNZ/JNE |
| 0x0F0x86 | JBE/JNA |
| 0x0F0x87 | JNBE/JA |
| 0x0F0x88 | JS |
| 0x0F0x89 | JNS |
| 0x0F0x8A | JP/JPE |
| 0x0F0x8B | JNP/JPO |
| 0x0F0x8C | JL/JNGE |
| 0x0F0x8D | JNL/JGE |
| 0x0F0x8E | JLE/JNG |
| 0x0F0x8F | JNLE/JG |
4.经典变长指令_ModR/M
经典的变长指令主要包括如下几个指令:
0x88 MOV Eb, Gb G:通用寄存器
0x89 MOV Ev, Gv E:寄存器/内存
0x8A MOV Gb, Eb b:字节
0x8B MOV Gv, Ev v:Word, doubleword or quadword
当指令中出现内存操作对象的时候,就需要在操作码后面附加一个字节来进行补充说明,这个字节被称为ModR/M。
4.1 ModR/M解析
这一个字节(八位)可以被分为如下图所示的三个部分:

4.1.1 Reg/Opcode
Reg/Opcode(第3、4、5位)描述指令中的G部分,即寄存器,寄存器的对应关系如下图所示:

4.1.2 Mod和R/M
Mod(第6、7位)和R/M(第0、1、2位)共同描述指令中的E部分,即寄存器/内存。使用方法查下表即可:

例,查询8801的过程如下图,首先根据88得知操作宽度MOV Eb, Gb,存在对内存操作且宽度为byte,ModR/M内容查上表即可:

4.1.3 特殊情况
- 1、ESP指向栈顶,是浮动的,不确定的,Inter将这个编码废弃,由另外的格式来说明。
- 2、EBP指向栈底,而[EBP]通常存储上一个EBP,所以[EBP]无数据操作意义,Inter将这个编码废弃,改为立即数寻址。例如
88 05 12 34 56 78的汇编指令为MOV BYTE PTR DS:[78563412], AL.
5.经典变长指令_Reg/Opcode
在第四节当中学的3-5位是用来标志寄存器的,有时其实也用来表示Opcode,比如指令白皮书中表A-2中发现80、81、82、83这几个编码并没有指定明确的操作码,如下图:
这里显示的操作码是Grp1 /1A,此时应该查表A-6,如下图:

例,80 65 08 FF查表过程如下:
- 1、第一个字节为80 查Table-2表,得到对应结构:Eb,Ib
- 2、第二个字节为ModR/M字段,所以拆分65变为(01 100 101)
- 3、Mod 与 R/M字段 查Table2-2 得到对应的结构:[EBP+DIS8]
- 4 、100 字段 查表TableA-6 得到对应操作码为:AND
- 5、最终指令为
AND BYTE PTR SS:[EBP+08],0xFF
6.经典变长指令SIB字段
ModR/M字段是用来进行内存寻址的,可当地址形如DS:[EAX + ECX*2 + 12345678]时,仅仅靠ModR/M字段,是描述不出来的,所以就有了这个SIB字段,如下图所示是之前根据mod字段、R/M字段查表时ESP所对应的选项。

上图中的三种情况在ModR/M字节后,还紧跟着一个SIB字节。SIB字节的8个位被分成了三部分:

这三个部分生成表达式的过程如下:

具体对应关系查下表即可:
