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个位被分成了三部分:
这三个部分生成表达式的过程如下:
具体对应关系查下表即可: