逆向之汇编学习总结

数据宽度

或许你曾经有这样的疑惑,有符号数在二进制的表示中,以1开头的表示为负数,那么10000000是表示的-1还是128呢 ?

在这里引入数据宽度的概念,即8位二进制数能够存储的数据范围为-128~127,很显然,上面存储的数,在数据宽度为8位时,表示-1,同理-127表示为10000001-2表示为11111110,这里关于原码、补码的概念不加以赘述,其本质都是为了表示数值。

基于x86架构的CPU的数据宽度为32位,表示正负范围为:0~7FFFFFFF 80000000~FFFFFFFF

计量单位有:byte、word、dword、qword,分别表示字节,字,双字,四字,单字节表示8位。

逻辑运算

运算符说明实例
&(and)按位与,同时为1,才能得110110011 & 10110101 = 10110001
|(or)按位或,存在1时,结果为110110011 | 10110101 = 10110011
^(xor)按位异或,不同时,结果为110110011 ^ 10110101 = 00000110
!(not)按位非,单运算符,结果取反!10110011=01001100

异或加密解密

加密数据:00110001

密钥:00010101

加密结果:00110001 ^ 00010101 = 00100100

解密:00100100 ^ 00010101 = 00110001

基本指令

mov

格式:mov 目标操作数,源操作数

作用:拷贝源操作数到目标操作数。

注意:

1、源操作数可以是立即数、通用寄存器、段寄存器、或者内存单元. 
2、目标操作数可以是通用寄存器、段寄存器或者内存单元. 
3、操作数的宽度必须一样. 
4、源操作数和目标操作数不能同时为内存单元.
指令说明
MOV r/m8,r8将8位寄存器的内容拷贝到8位寄存器或8位的内存中。
MOV r/m16,r16将16位寄存器的内容拷贝到16位寄存器或16位的内存中。
MOV r/m32,r32将32位寄存器的内容拷贝到32位寄存器或32位的内存中。
MOV r8,r/m8将8位寄存器或8位的内存操作数拷贝到8位寄存器中。
MOV r16,r/m16将16位寄存器或16位的内存操作数拷贝到16位寄存器中。
MOV r32,r/m32将32位寄存器或32位的内存操作数拷贝到32位寄存器中。
MOV r8, imm8将8位立即数的内容拷贝到8位寄存器中。
MOV r16, imm16将16位立即数的内容拷贝到16位寄存器中。
MOV r32, imm32将32位立即数的内容拷贝到32位寄存器中。

以上指令取自Intel白皮书,释义如下:

r 通用寄存器           
m 代表内存                            
imm 代表立即数                           
r8 代表8位通用寄存器               
m8 代表8位内存
imm8 代表8位立即数

 

lea

LEA指令将存储器操作数mem的4位16进制偏移地址送到指定的寄存器,这里,源操作数必须是存储器操作数,目标操作数必须是通用寄存器。

格式:lea r,m。

功能:获取内存编号而非内存中的内容。

 

别问,问就是背

addandorxornotsub
ADD AL, imm8AND AL, imm8OR AL, imm8XOR AL, imm8NOT r/m8SUB AL, imm8
ADD AX, imm16AND AX, imm16OR AX, imm16XOR AX, imm16NOT r/m16SUB AX, imm16
ADD EAX, imm32AND EAX, imm32OR EAX, imm32XOR EAX, imm32NOT r/m32SUB EAX, imm32
ADD r/m8, imm8AND r/m8, imm8OR r/m8, imm8XOR r/m8, imm8 SUB r/m8, imm8
ADD r/m16,imm16AND r/m16,imm16OR r/m16,imm16XOR r/m16,imm16 SUB r/m16,imm16
ADD r/m32,imm32AND r/m32,imm32OR r/m32,imm32XOR r/m32,imm32 SUB r/m32,imm32
ADD r/m16, imm8AND r/m16, imm8OR r/m16, imm8XOR r/m16, imm8 SUB r/m16, imm8
ADD r/m32, imm8AND r/m32, imm8OR r/m32, imm8XOR r/m32, imm8 SUB r/m32, imm8
ADD r/m8, r8AND r/m8, r8OR r/m8, r8XOR r/m8, r8 SUB r/m8, r8
ADD r/m16, r16AND r/m16, r16OR r/m16, r16XOR r/m16, r16 SUB r/m16, r16
ADD r/m32, r32AND r/m32, r32OR r/m32, r32XOR r/m32, r32 SUB r/m32, r32
ADD r8, r/m8AND r8, r/m8OR r8, r/m8XOR r8, r/m8 SUB r8, r/m8
ADD r16, r/m16AND r16, r/m16OR r16, r/m16XOR r16, r/m16 SUB r16, r/m16
ADD r32, r/m32AND r32, r/m32OR r32, r/m32XOR r32, r/m32 SUB r32, r/m32

 

OD技巧

快捷键

ctrl+g : 跳转到指定输入地址

ctrl+f:搜索命令的位置

f2 : 设置断点,切换断点

f8: 单步步过

f9:运行

f12:暂停

窗口布局

 

  • 数据窗口和其他窗口的数据位置相反,为小端序,即高位数据存放在低位地址。
  • 命令接口常用命令:
    • dd、dw、db,按四字、双字、字节显示对应内存数据。

缓存清理

有时OD打开之后,会出现反汇编窗口一段代码变灰或者提示哪里下了断点的情况,这是OD同级目录下的udd文件夹下的缓存文件导致的,删掉里面的文件即可解决该问题。

寄存器

 通用寄存器 主要用途编号(二进制)
32位16位8位  
EAXAXAL累加器000
ECXCXCL计数001
EDXDXDLI/O指针010
EBXBXBLDS段的数据指针011
ESPSPAH堆栈指针100
EBPBPCHSS段的数据指针101
ESISIDH字符串操作的源指针;SS段的数据指针110
EDIDIBH字符串操作的目标指针;ES段的数据指针111
32位专用寄存器主要用途存储数据的范围
EIP保存当前下一条运行指针地址0 - 0xFFFFFFFF

 

辅以神兵OD,逆向美哉!

 

内存

基本概念

寄存器位于CPU内部,执行速度快,但比较贵;而内存通过引脚与CPU相连,速度相对较慢,但成本较低,所以可以做的很大。寄存器和内存没有本质区别,都是用于存储数据的容器,都是定宽的。

内存的数量特别庞大,无法每个内存单元都起一个名字,所以用编号来代替,我们称计算机CPU是32位或者64位,主要指的就是内存编号的宽度(寻址宽度),而不是寄存器的宽度。

计算机内存的每一个字节会有一个编号(即内存编号的单位是字节),编号从0开始,32位计算机的编号最大是32位,也就是FFFFFFFF,也就是说,32位计算机内存寻址的最大范围是FFFFFFFF+1 , 即4GB,这也是为什么我们在一个XP的系统上面如果物理内存超过4G是没有意义的原因。

[内存编号]表示地址,每个内存单元的宽度为8,超过8位的数据会溢出到下一个内存单元。

内存读写

  • 内存读:mov eax,dword ptr ds:[0x0012FF34]
  • 内存写:mov dword ptr ds:[0x0012FF34],0x12345678
  • ptr: Point 代表后面是一个指针 (指针的意思就是里面存的不是普通的值,而是个地址)
  • 注意:地址编号不要随便写,因为内存是有保护的,并不是所有的内存都可以直接读写(需要特别处理)

 

寻址公式

1. [立即数]

#内存读
mov eax,dword ptr ds:[0x19FF74]
#内存写
mov dword ptr ds:[0x19FF74],0xAABBCCDD
#获取内存编号
lea ecx,dword ptr ds:[0x19FF74]

 

2. [reg]

#内存读
mov ecx,0x19ff74
mov eax,dword ptr ds:[ecx]
#内存写
mov dword ptr ds:[ecx],0x87654321
#获取内存编号
lea eax,dword ptr ds:[ecx]

 

3. [reg+立即数]

#内存读
mov ecx,0x19ff74
mov eax,dword ptr ds:[ecx+4]
#内存写
mov dword ptr ds:[ecx+0xd],0x87654321
#获取内存编号
lea eax,dword ptr ds:[ecx+4]

 

*4. [reg+reg{1,2,4,8}]**注意,这里只能取1,2,3,4中的一个。

#内存读
mov ecx,0x19ff74
mov edx,2
mov eax,dword ptr ds:[ecx+edx*4]
#内存写
mov dword ptr ds:[ecx+edx*4],0x87654321
#获取内存编号
lea eax,dword ptr ds:[ecx+edx*4]

 

*5. [reg+reg{1,2,4,8}+立即数]**

#内存读
mov ecx,0x19ff74
mov edx,2
mov eax,dword ptr ds:[ecx+edx*4+4]
#内存写
mov dword ptr ds:[ecx+edx*4+4],0x87654321
#获取内存编号
lea eax,dword ptr ds:[ecx+edx*4+4]

 

堆栈操作

堆栈模型

 

压入数据

#模拟栈顶栈底
mov ebx,0x13ffdc  #base
mov edx,0x13ffdc  #top
#方式1
mov dword ptr ds:[edx-4],0xaaaaaaaa
sub edx,4
#方式2
sub edx,4
mov dword ptr ds:[edx],0xaaaaaaaa
#方式3
mov mov dword ptr ds:[edx-4],0xaaaaaaaa
lea edx,dword ptr ds:[edx-4]
#方式4
lea edx,dword ptr ds:[edx-4]
mov mov dword ptr ds:[edx],0xaaaaaaaa

读取数据

#通过base加偏移读取第n个压入的数,n需指定
mov esi,dword ptr ds:[ebx-4*n]
#通过top加偏移读取
mov esi,dword ptr ds:[ebx+4*(n-1)]

弹出数据

#方法1
mov ecx,dword ptr ds:[edx]
lea edx,dword ptr ds:[edx+4]
#方法2
mov esi,dword ptr ds:[edx]
add edx,4
#方法3
lea edx,dword ptr ds:[edx+4]
mov edi,dword ptr ds:[edx-4]

push指令:完成上述模拟的压入数据操作,ebx和esp分别为占地和栈顶,由cpu调配,随着压栈操作而自动变化,与容器宽度有关加减2或4。

  • push r32:esp-4
  • push r16:esp-2
  • push m16:esp-2
  • push m32:esp-4
  • push imm8/imm16/imm32:esp-4

 

pop指令:完成上述模拟的弹出数据操作,ebx和esp分别为占地和栈顶,由cpu调配,随着出栈操作而自动变化。

  • pop r32:esp+4
  • pop r16:esp+2
  • pop m16:esp+2
  • pop m32:esp+4


pushad指令:将8个通用寄存器的内容压栈,现场保护。

 

popad指令:pushad的逆操作,恢复现场。


标志寄存器

别问,问就是背

 

CF

进位标志(Carry Flag),如果运算结果的最高位产生了一个进位或借位,那么,其值为1,否则其值为0。

MOV AX,0xFF00
ADD AX,0x0101

 

PF

奇偶标志PF(Parity Flag):奇偶标志PF用于反映运算结果中最后一个字节中“1”的个数的奇偶性,如果“1”的个数为偶数,则PF的值为1,否则其值为0。

00010011 00010010 
mov ax,0x1312
00010011 00010011 偶数 ,最后一字节为奇数-->p=0
add ax,1
00010011 00010100 奇数,最后一字节为偶数-->p=1
add ax,1

 

 

  • 特别的,当最低有效字节为0时,PF=1

AF

辅助进位标志(Auxiliary Carry Flag),在发生下列情况时,辅助进位标志AF的值被置为1,否则其值为0:

  1. 在字操作时,发生低字节向高字节进位或借位时;
  2. 在字节操作时,发生低4位向高4位进位或借位时。
MOV AX,0x100f
ADD AX,0x4

 

ZF

零标志(Zero Flag):零标志ZF用来反映运算结果是否为0,如果运算结果为0,则其值为1,否则其值为0。

 

SF

符号标志(Sign Flag):符号标志SF用来反映运算结果的符号位,它与运算结果的最高位相同。

mov al,0x82
add al,1

 

OF

溢出标志(Overflow Flag):溢出标志OF用于反映有符号数加减运算所得结果是否溢;如果运算结果超过当前运算位数所能表示的范围,则称为溢出,OF的值被置为1,否则,OF的值被清为0。

最高位进位与溢出的区别:

  • 进位标志表示无符号数运算结果是否超出范围.
  • 溢出标志表示有符号数运算结果是否超出范围.

是否溢出的判别规律:

 

  • 正 + 正 = 正 如果结果是负数,则说明有溢出
  • 负 + 负 = 负 如果结果是正数,则说明有溢出
  • 正 + 负 永远都不会有溢出.

 

DF

方向标志位,默认从右操作数到左操作数,可以通过CLDSTD指令修改DF的值。

  • 清方向位指令CLD(Clear Direction Flag):DF←0
  • 置方向位指令STD(Set Direction Flag):DF←1

相关指令

ADC

带进位加法(C位参与运算),两边不能同时为内存,且数据宽度要一致。

格式:ADC  R/M,R/M/IMM

  • ADC AL,CL
  • ADC BYTE PTR DS:[19ff74],2
  • ADC BYTE PTR DS:[19ff74],AL

 

SBB

带借位减法(C位参与运算),两边不能同时为内存,且数据宽度要一致。

格式:SBB  R/M,R/M

  • SBB AL,CL
  • SBB BYTE PTR DS:[19ff74],2
  • SBB BYTE PTR DS:[19ff74],AL

 

XCHG

交换数据,两边不能同时为内存,且数据宽度要一致。

格式:XCHG  R/M,R/M

  • XCHG AL,CL
  • XCHG DWORD PTR DS:[19ff74],EAX
  • XCHG BYTE PTR DS:[19ff74],AL

 

MOVS

移动数据,把ESI存储的内存地址中的数据复制到EDI存储的内存地址中,每复制一次,两个操作数均向上或下偏移4/2/1个字节(地址递增或递减,便于复制下一串内容),当D=0时递增,D=1时递减。

  • MOVS BYTE PTR ES:[EDI],BYTE PTR DS:[ESI],简写为movsb
  • MOVS WORD PTR ES:[EDI],WORD PTR DS:[ESI],简写为MOVSW
  • MOVS DWORD PTR ES:[EDI],DWORD PTR DS:[ESI],简写为movsd

 

STOS

AL/AX/EAX的值存储到[EDI]指定的内存单元,D=0时地址递增,D=1时地址递减。

  • STOS BYTE PTR ES:[EDI]简写为STOSB
  • STOS WORD PTR ES:[EDI]简写为STOSW
  • STOS DWORD PTR ES:[EDI]简写为STOSD

 

REP

按计数寄存器 (ECX) 中指定的次数重复执行字符串指令。

 

JCC

比较指令

cmp

格式:CMP  R/M,R/M/IMM

该指令是比较两个操作数,实际上,它相当于SUB指令,但是相减的结果并不保存到第一个操作数中;只是根据相减的结果来改变零标志位的(其他标志位也可以更改),当两个操作数相等的时候,零标志位置1。

 

test

指令格式:TEST  R/M,R/M/IMM

该指令在一定程序上和CMP指令时类似的,两个数值进行操作,结果不保存,但是会改变相应标志位;用这个指令,可以确定某寄存器是否等于0。

 

jmp

无条件转移指令,仅可以修改EIP的值,相当于mov eip,立即数/寄存器

格式:jmp 寄存器/立即数

call

call指令用于调用子程序,先将当前的EIP压栈保存,然后jmp 目标地址,相当于:

PUSH eip
mov eip,地址A/寄存器

格式:call 地址A/寄存器

ret

ret指令用于回到程序调用点,与call配套使用,先将eip出栈,然后jmp eip,相当于:

lea esp,[esp+4]
mov eip,[esp-4]

格式:ret

别问,问就是背

指令解释条件例子
JE、JZ结果为0时跳转(相等时跳转)ZF=1cmp al,al jz 0x19ff74
JNE, JNZ结果不为零则跳转(不相等时跳转)ZF=0cmp al,cl jnz 0x19ff74
JS结果为负则跳转SF=1mov al,1 sub al,3 js 0x19ff74
JNS结果为非负则跳转SF=0mov al,2 sub al,1 jns 0x19ff74
JP, JPE结果中1的个数为偶数则跳转PF=1cmp al,al jp 0x19ff74
JNP, JPO结果中1的个数为偶数则跳转PF=0mov al,1 cmp al,0xff jnp 0x19ff94
JO结果溢出了则跳转OF=1mov al,07f add al,4 jo 0x19ff74
JNO结果没有溢出则跳转OF=0mov al,07f add al,0 jno 0x19ff74
JB, JNAE小于则跳转 (无符号数)CF=1mov al,2 mov cl,1 cmp cl,al jb 0x19ff90
JNB, JAE大于等于则跳转 (无符号数)CF=0mov al,2 mov cl,1 test cl,al jb 0x19ff90
JBE, JNA小于等于则跳转 (无符号数)CF=1 or ZF=1cmp al,al jbe 0x19ff90
JNBE, JA大于则跳转(无符号数)CF=0 and ZF=0mov al,2 mov cl,1 cmp al,cl jnbe 0x19ff90
JL, JNGE小于则跳转 (有符号数)SF≠ OFmov al,1 mov cl,2 cmp al,cl jl 0x19ff74
JNL, JGE大于等于则跳转 (有符号数)SF=OFmov al,1 mov cl,2 cmp cl,al jnl 0x19ff74
JLE, JNG小于等于则跳转 (有符号数)ZF=1 or SF≠ OFmov al,2 mov cl,1 cmp cl,al jle 0x19ff90
JNLE, JG大于则跳转(有符号数)ZF=0 and SF=OFmov al,2 mov cl,1 cmp cl,al jnle 0x19ff90

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值