汇编

汇编语言

简介

工具

  • DTDebug

位运算

  • 进制

操作符

位运算
and
or
not
xor 异或
shl 左移
shr 右移,高位补0,C语言使用unsigned类型时,就会补0
sar 右移,高位补符号位,signed

存储

通用寄存器

  • 计算机可以在三个地方存储数据,cpu、内存、硬盘。寄存器就是用于cpu存储数据的。

寄存器组成

  • 包含8个通用寄存器可以存储任意数据。
  • 16位、32位的寄存器都指向了同一个地址,只是赋值时,影响的位数不同。
  • 8位寄存器,近用了ABCD四个寄存器,将高8位和第八位拆成了AL、BL、CL、DL、AH、BH、CH、DH,8个寄存器。
32位通用寄存器 16位通用寄存器 8位通用寄存器 用途
EAX AX AL 作为返回值
EBX BX BL
ECX CX CL 计数寄存器
EDX DX DL
ESP SP AH 栈指针寄存器,栈顶指针
EBP BP BH 栈底指针
ESI SI CH 串赋值的源地址
EDI DI DH 出赋值的目的地址

寄存器读写

指令
立即数到寄存器 MOV EAX,1
寄存器到寄存器 MOV EAX,EBX

内存

  • 对于32位寻址空间的计算机,内存最大可支持4GB
  • 由于内存太大了,没办法起名字,只能用地址编号代替

内存读写

  • 汇编指令中,绝大多数指令,不允许从内存到内存。可以通过寄存器进行存储。
  • MOVS指令可以实现内存到内存的移动。
指令
立即数到内存 MOV BYTE ptr ds:[0018FFF0], 1
寄存器到内存 MOV DWORD ptr ds:[0018FFF0], EAX
内存到寄存器 MOV EAX,DWORD ptr ds:[0018FFF0]
写入的宽度
BYTE 一字节
WORD 二字节
DWORD 四字节

内存地址的表示

  • 5中形式
表达形式
立即数 0x13FFC4 MOV EAX,DWORD PTR DS:[0x13FFC4]
[reg] 八个寄存器的任意一个,读取里面的地址 MOV EAX,DWORD PTR DS:[ECX]
[reg+立即数] 寄存器+立即数,立即数表示了偏移量 MOV EAX,DWORD PTR DS:[ECX+4]
[reg+reg*{1,2,4,8}] 寄存器+寄存器*2的倍数,后者也代表偏移量 MOV EAX,DWORD PTR DS:[ECX+EAX*4]
[reg+reg*{1,2,4,8}]+立即数 寄存器+寄存器*2的倍数+立即数 MOV EAX,DWORD PTR DS:[ECX+EAX*4+4]

内存存储模式

  • 大端模式:数据高位在低位,数据低位在高位
>>> 0x1A2C   高位-->低位
0x0001 2C 高位
0x0000 1A 低位
  • 小端模式:数据高位在高位,数据低位在低位
>>> 0x1A2C
0x0001 1A
0x0000 2C

常用指令

写指令

指令
MOV a,b b存储到a
ADD a,b 加法,a += b
SUB a,b 减法,a -= b
AND a,b 与,a &= b
OR a,b 或,a = b
NOT a,b 非,a != b
XOR a,b 异或,a ^= b
MOVS a,b 内存b存储到内存a,并a和b的指针自动+1或者-1(取决于标志位D),适合拷贝MOVS DWORD PTR ES:[EDI],DWORD PTR DS:[ESI]
MOVSB a,b 简写形式,移动目标为byte
MOVSW a,b 简写形式,移动目标为word
MOVSD a,b 简写形式,移动目标为dword
STOS BYTE PTR ES:[EDI] 将AI、AX、EAX的值存储到EDI指定内存单元,指针自动+1或者-1
STOSB 简写形式,移动目标为byte
STOSW 简写形式,移动目标为word
STOSD 简写形式,移动目标为dword
REP 重复执行,执行次数取决于ECX的值,16进制:MOV ECX 10
REP MOVSD a,b
CMP a,b 相当于SUB,判断是否为0,只是CMP不对a进行更改
TEST a,b 相当于AND,判断是否为0,只是TEST不对a进行更改

堆栈

  • 程序开启后,系统会分配堆栈空间,用于存储中间状态的值。这块空间如果程序用完,就会发生栈溢出异常。
  • 堆栈从高地址开始使用,直到低地址。
  • ESP寄存器保存了栈指针。
指令
PUSH mem/reg/立即数 将reg或者立即数存入堆栈,ESP减4,根据压入的是什么
POP reg/mem 弹出,ESP加4

EIP寄存器

  • cpu下一次执行的地址,EIP修改只能通过JMP、CALL修改
指令
JMP reg、立即数、mem EIP更改值,mem必须是dword
CALL reg、立即数、mem EIP更改值,并保护现场,放入堆栈,栈顶-4
RET EIP更改为堆栈,恢复现场,栈顶+4

反调试

Fake F8

  • 调式中F7单步步入,F8是单步步过

  • 调试原理:

    • 在某一行下断点,实际是将对应的语句改为了int 3,对应的十六进制是CC,中断,停到调试器
    • 单步执行的原因是在EFL的TF标志位为1,cpu就会进入单步执行模式
  • F7是单步执行,而F8在遇到CALL指令时,会在下一个语句改为int 3,并将当前指令存到堆栈中。

  • Fake F8欺骗的是进入到CALL中时,修改了ESP的值,此时返回时,F8就失效了

  • 在程序中CALL比较多的时候,想跳过CALL就无法实现了,这样给反调试带来困难。

函数

函数调用

  • 一般不用JMP,无法返回原来的位置
指令
CALL reg、立即数、mem EIP更改值,并保护现场,放入堆栈,栈顶-4
RET EIP更改为堆栈,恢复现场,栈顶+4

函数参数

  • 参数放到寄存器中,返回值放在EAX中
  • 参数也可以放到堆栈中,要注意堆栈平衡

ESP寻址

  • 数据放入堆栈后的寻址,由于存储的栈指针,所以计算相对麻烦

EBP寻址

  • 通过改变栈底指针,可以避免新增数据导致的地址便宜计算。
PUSH 1
PUSH 2
CALL XXXXX
ADD ESP,8
---------XXXXX---------
PUSH EBP
MOV EBP ESP
SUB ESP,10
MOV EAX,DWORD PTR SS:[EBP+8]
ADD EAX,DWORD PTR SS:[EBP+C]
MOV ESP,EBP
POP EBP
RETN

JCC指令

标记寄存器

  • 标记寄存器状态的变化是由于数据计算引起的。

标记寄存器

  • CF:最高有效位发生借位,则置1。用于判断无符号数运算是否溢出
  • PF:结果的最低有效字节包含偶数个1,则置1。用于奇偶校验检查
  • AF:辅助进位操作,在结果的第3位发生进位或借位时置1。在BCD算数运算中使用
  • ZF:运算结果为0,则置1。与CMP和TEST指令一起使用,查看是不是0
  • SF:符号位,有符号整型的最高位
  • OF:溢出标志位。用于判断有符号数运算是否溢出。
  • DF:方向标志位,地址由低向高,则为0

JCC指令

指令 说明 判断条件
JE JZ 结果为零则跳转(相等时跳转) ZF=1
JNE JNZ 结果不为零则跳转(不相等时跳转) ZF=0
JS 结果为负则跳转 SF=1
JNS 结果不为负则跳转 SF=0
JP JPE 结果中1的个数为偶数则跳转 PF=1
JNP JPO 结果中1的个数为奇数则跳转 PF=0
JO 结果溢出了则跳转 OF=1
JNO 结果没有溢出则跳转 OF=0
JB JNAE 小于则跳转(无符号数) CF=1
JNB JAE 大于等于则跳转(无符号数) CF=0
JBE JNA 小于等于则跳转(无符号数) CF=1 OR ZF=1
JNBE JA 大于则跳转(无符号数) CF=0 AND ZF=0
JL JNGE 小于则跳转(有符号数) SF!=OF
JNL JGE 大于等于则跳转(有符号数) SF=OF
JLE JNG 小于等于则跳转(有符号数) ZF=1 OR SF!=OF
JNLE JG 大于则跳转(有符号数) ZF=0 AND SF=OF