滴水逆向学习笔记(一)

汇编部分

进制

进制的定义

十进制的定义:由十个符号组成,分别是0 1 2 3 4 5 6 7 8 9 逢十进一。

九进制的定义:由九个符号组成,分别是0 1 2 3 4 5 6 7 8 逢九进一。

十六进制的定义:由十六个符号组成,分别是0 1 2 3 4 5 6 7 8 9 A B C D E F

进制运算的本质是查表

例:

image.png

通用寄存器

在x86 32位系统的情况下,常见的寄存器如下

寄存器 编号(二进制)
32位 16位 8位
EAX AX AL 000
ECX CX CL 001
EDX DX DL 010
EBX BX BL 011
ESP SP AH 100
EBP BP CH 101
ESI SI DH 110
EDI DI BH 111

他们之间的关系如下:

所有的寄存器都可以看作是一个容器,当然,特定时候有特殊的用法

32位通用寄存器的指定用途如下:

寄存器 主要用途 编号 储存数据范围
EAX 累加器 0 0 - 0xFFFFFFFF
ECX 计数 1 0 - 0xFFFFFFFF
EDX I/O指针 2 0 - 0xFFFFFFFF
EBX DS段的数据指针 3 0 - 0xFFFFFFFF
ESP 栈顶指针 4 0 - 0xFFFFFFFF
EBP 栈底指针 5 0 - 0xFFFFFFFF
ESI 字符串操作的源指针,SS段的数据指针 6 0 - 0xFFFFFFFF
EDI 字符串操作的目标指针,ES段的数据指针 7 0 - 0xFFFFFFFF

标志寄存器

标志寄存器是一些特殊的寄存器,用来存放逻辑运算的结果标志,构成如下图:

image

几个比较重要的标志寄存器作用:

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

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

3、辅助进位标志AF(Auxiliary Carry Flag):

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

(1)、在字操作时,发生低字节向高字节进位或借位时;

(2)、在字节操作时,发生低4位向高4位进位或借位时。

4、零标志ZF(Zero Flag):零标志ZF用来反映运算结果是否为0。
如果运算结果为0,则其值为1,否则其值为0。在判断运算结果是否为0时,可使用此标志位。

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

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

寄存器与内存的关系

寄存器位于CPU内部,执行速度快,但比较贵。

内存速度相对较慢,但成本较低,所以可以做的很大。

寄存器和内存没有本质区别,都是用于存储数据的容器,都是定宽的。

寄存器常用的有8个:EAX、ECX、EDX、EBX、ESP、EBP、ESI、EDI。

计算机中的几个常用计量单位:BYTE WORD DWORD

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

内存编号如下图:

1
2
3
4
5
6
7
8
9
10
0x00000000	
0x00000001
0x00000002
....
....
....
....
....
....
0xFFFFFFFF

32位计算机的编号最大是32位,也就是32个1 换成16进制为FFFFFFFF,也就是说,32位计算机内存寻址的最大范围是FFFFFFFF+1

内存的单位是字节,那内存中能存储的信息最多为:FFFFFFFF+1 字节 即4G,这也是为什么我们在一个XP的系统上面如果物理内存超过4G是没有意义的原因。

但是不是所有的32位计算机最多识别的内存为4g,如果装了某种驱动或者其他情况,可以超过4g。

堆栈

堆栈优点:

1
堆栈的优点:临时存储大量的数据,便于查找.

什么是堆栈:

1
2
3
4
5
6
7
8
9
10
11
12
13
1、BASE,TOP是2个32位的通用寄存器,里面存储的是内存单元编号(内存地址).

2、BASE里面存储了一个地址,记录的起始地址.

3、TOP里面也存储了一个地址,记录的是结束的地址.

4、存入数据的时候,TOP的值减4(为方便演示,每次存取都是4个字节)

5、释放数据的时候,TOP的值加4(为方便演示,每次存取都是4个字节)

6、如果要读取中间的某个数据的时候可以通过TOP 或者 BASE 加上偏移的方式去读取

7、这种内存的读写方式有个学名:堆栈

根据上面的定义,不用push和pop一样可以实现堆栈的功能(取数据和存数据)

汇编指令

在x86 32位系统的环境下,常见汇编指令如下:

MOV 指令0x00000000

0x00000001
0x00000002
….
….
….
….
….
….
0xFFFFFFFF

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

用法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
MOV r/m8,r8 			    r 通用寄存器	

MOV r/m16,r16 m 代表内存

MOV r/m32,r32 imm 代表立即数

MOV r8,r/m8 r8 代表8位通用寄存器

MOV r16,r/m16 m8 代表8位内存

MOV r32,r/m32 imm8 代表8位立即数

MOV r8, imm8

MOV r16, imm16

MOV r32, imm32

往内存中写入数据具体用法如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
1、内存格式						

7 0
[0x00000000] 1、每个内存单元的宽度为8
...
2、[编号]称为地址
...
3、地址的作用:当我们想从内存中读取数据或者想向内存中写入数据,首先应该找到要读、写的位置。就像写信要写地址一样。
[0xFFFFFFFF]


2、从指定内存中写入/读取数据

mov dword ptr ds:[0x0012FF34],0x12345678

mov eax,dword ptr ds:[0x0012FF34]

dword :要读/写多少 此时是4字节 byte == 1字节 word == 2字节

ptr: Point 代表后面是一个指针 (指针的意思就是里面存的不是普通的值,而是个地址)

ds:段寄存器 先不用管 记住就行

0x0012FF34:内存编号,必须是32位的 前面0可以省略

注意:地址编号不要随便写,因为内存是有保护的,并不是所有的内存都可以直接读写(需要特别处理)

建议地址编号写成esp的值

ADD指令

作用:将源操作数和目标寄存器的值相加并保存到目标寄存器

用法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
ADD AL, imm8 

ADD AX, imm16

ADD EAX, imm32

ADD r/m8, imm8

ADD r/m16,imm16

ADD r/m32,imm32

ADD r/m16, imm8

ADD r/m32, imm8

ADD r/m8, r8

ADD r/m16, r16

ADD r/m32, r32

ADD r8, r/m8

ADD r16, r/m16

ADD r32, r/m32

SUB指令

作用:将源操作数和目标寄存器的值相减并保存到目标寄存器

用法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
SUB AL, imm8 

SUB AX, imm16

SUB EAX, imm32

SUB r/m8, imm8

SUB r/m16,imm16

SUB r/m32,imm32

SUB r/m16, imm8

SUB r/m32, imm8

SUB r/m8, r8

SUB r/m16, r16

SUB r/m32, r32

SUB r8, r/m8

SUB r16, r/m16

SUB r32, r/m32

AND指令

作用:将源操作数和目标寄存器的值进行与运算并保存到目标寄存器

用法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
AND AL, imm8

AND AX, imm16

AND EAX, imm32

AND r/m8, imm8

AND r/m16,imm16

AND r/m32,imm32

AND r/m16, imm8

AND r/m32, imm8

AND r/m8, r8

AND r/m16, r16

AND r/m32, r32

AND r8, r/m8

AND r16, r/m16

AND r32, r/m32

OR指令

作用:将源操作数和目标寄存器的值进行或运算并保存到目标寄存器

用法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
OR AL, imm8

OR AX, imm16

OR EAX, imm32

OR r/m8, imm8

OR r/m16,imm16

OR r/m32,imm32

OR r/m16, imm8

OR r/m32, imm8

OR r/m8, r8

OR r/m16, r16

OR r/m32, r32

OR r8, r/m8

OR r16, r/m16

OR r32, r/m32

XOR指令

作用:将源操作数和目标寄存器的值进行异或运算并保存到目标寄存器

用法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
XOR AL, imm8

XOR AX, imm16

XOR EAX, imm32

XOR r/m8, imm8

XOR r/m16,imm16

XOR r/m32,imm32

XOR r/m16, imm8

XOR r/m32, imm8

XOR r/m8, r8

XOR r/m16, r16

XOR r/m32, r32

XOR r8, r/m8

XOR r16, r/m16

XOR r32, r/m32

NOT指令

作用:将目标寄存器的值进行非运算并保存到目标寄存器

用法:

1
2
3
4
5
NOT r/m8

NOT r/m16

NOT r/m32

LEA指令

作用:获取目标内存地址编号并存到指定位置

用法:

1
2
3
4
5
LEA EAX,DWORD PTR DS:[EAX+ECX*4]

LEA EAX,DWORD PTR DS:[0X13FFC4]

LEA EAX,DWORD PTR DS:[ESP+8]

PUSH指令

作用: 压栈,将一个数或者寄存器中的值压入堆栈中

用法:

1
2
3
4
5
6
7
8
9
PUSH r32

PUSH r16

PUSH m16

PUSH m32

PUSH imm8/imm16/imm32

POP指令

作用: 出栈,将某个内存的zhi值取出放入某个寄存器中

用法:

1
2
3
4
5
6
7
POP r32

POP r16

POP m16

POP m32

jcc汇编指令

jcc指令的本质是修改EIP寄存器的值

JMP指令

作用:修改EIP的值

用法:

1
2
3
4
5
6
7
				
MOV EIP,寄存器/立即数 简写为 JMP 寄存器/立即数

```
### CALL指令
#### 作用:使EIP(即下一跳的值)修改成某个内存地址,和jmp的区别是,jmp只会直接跳到指定位置,call则会先把下一个汇编指令保存到堆栈中
#### 用法:

PUSH 地址B

MOV EIP,地址A/寄存器 简写为:CALL 地址A/寄存器

1
2
3
4
5
6
7
### RET指令
#### 作用:修改EIP值(和call差不多) 取之前call保存的地址,然后返回。
#### 用法:
```
LEA ESP,[ESP+4]

MOV EIP,[ESP-4] 简写为:RET

CMP指令

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

用法:

1
CMP  R/M,R/M/IMM			

TEST指令

作用:该指令在一定程序上和CMP指令时类似的,两个数值进行与操作,结果不保存,但是会改变相应标志位.

用法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
TEST  R/M,R/M/IMM			

与的操作表项如下:

1 and 1 = 1

1 and 0 = 0

0 and 1 = 0

0 and 0 = 0

常见用法:用这个指令,可以确定某寄存器是否等于0。

TEST EAX,EAX 观察Z位

但是如果EAX的二进制某些位为1的话,那么运算的结果就不为零。

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