0x07 汇编语言
1. 硬件基础
- 计算机的三大总线 mov eax, [0x1000]
- 地址总线:用于传输需要访问的地址
- 控制总线:用于传输表示指令的二进制编码
- 数据总线:用于传输设置和得到的数据
- 实模式与保护模式
- 实模式中寻址方式是段基址+段偏移, 例如 CS*0x10 + IP,能访问20位的物理地址
- 保护模式中的实际基址存储在段描述符中,访问到的是 虚拟的4GB空间
2. 寄存器
- 16位寄存器
- 通用寄存器: ax、cx、dx、bx、si、di、sp、bp
- 栈寄存器: sp、bp
- 变址寄存器: si、di
- 段寄存器: CS、DS、SS、ES
- 指令指针: ip,使用跳转指令可以修改 loop call jmp jxx
- 标志寄存器:ZF、CF、OF、PF、SF、DF、TF 、IF、AF
- ZF:零标志位,结果为0的时候置1
- PF:奇偶标志位,低8位1的个数为偶数个的时候置1,否则置0
- SF:符号标志位,符号位为1的时候置1,否则置0
- DF:方向标志位,1说明向高地址+1,否则向低地址-1,串操作
- CF:进位标志位,无符号数计算结果影响
- OF:溢出标志位,有符号运算结果影响其置位
- 两个正数相加的和是负数
- 两个负数相加的和是正数
- TF:陷阱标志位
- AF: 辅助进位标志位
- IF:中断允许标志位 中段门
- 32位寄存器
- EAX、ECX、EDX、EBX、ESI、EDI、ESP、EBP、
- EIP、CS、DS、SS、ES、FS(TEB\KPCR) 、GS 、EFLAG
- 64位寄存器
- RAX、RCX、RDX、RBX、RSI、RDI、RSP、R8-R15
- RBP、RIP、CS、DS、SS、ES、FS 、GS 、EFLAG
3. 寻址方式
- 立即数寻址 0x401000
- 寄存器寻址 eax
- 存储器寻址
- 存储器-直接寻址: [0x1000]
- 存储器-寄存器间接寻址: [esi]
- 存储器-相对寄存器寻址: [esi+4]
- 存储器-基址变址寻址 : [esi+ebx]
- 存储器-相对基址变址寻址 : [esi+ebx+4]
4. 汇编指令
- 数据传输指令
- mov, xchg,lea
- 算术运算指令
- add , inc ,sub, dec, div,mul(edx\eax)
- 位操作指令
- shr,shl,rol,ror,and,or,xor
- 串操作指令
- movs, loads(eax,esi),stos(eax,edi),scas
- 使用 cld 指令控制方向
- 隐含的执行次数需要放置于cx/ecx
- 通常和rep/repne相配合,记住结束的条件
- 隐含的目的操作数: edi、源操作数 : esi
- 会自动自增/自减目的操作数和源操作数
- 条件跳转指令(JCC)
- jz,jnz,jb,jg,jle,jge (了解是受到哪些标志位的影响)
- 控制转移指令
- call , ret , iret(了解怎么操作栈) ,jmp
- call(push 下一条指令,jmp 目标地址) ret (mov eip, [esp], add esp, 4)
- 逻辑运算指令
- AND、OR、XOR、NOT、TEST, cmp
- test 通常用于判断返回值是否为0
- cmp 通常用于比较两个数据的大小
- AND、OR、XOR、NOT、TEST, cmp
- 栈操作指令
- push (esp-)
- pop(esp+)
- push a
- pop a
5. 内联汇编和裸函数
- 使用 __asm { } 进行内联函数的编写
- x64 不支持内联汇编的编写
- 使用 __emit() 定义一个一字节的常量数值
- 在 VS 使用 __declspec(naked) 定义裸函数
- 裸函数内不能使用 return 指令
- 裸函数不会自动生成代码,需要用户开辟栈帧
- 如果要定义局部变量,不能初始化,并且要写在开头位置
6. Opcode
opcode前缀:
- 66 切换操作数大小
- 67 切换地址大小
- F2/F3 重复前缀 rep
- 2E/36/3E/26/64/65: 段超越前缀
ModR/M : Mod Reg-opcode R/M