汇编基础

位运算

与运算

image-20231226032344544

或运算

image-20231226032439239

异或

image-20231226032458930

非运算

image-20231226032523375

左移

image-20231226032848211

右移

各二进位全部右移若干位,低位丢弃,高位补0或者补符号位

shr是无符号的,高位用0补

sar是有符号的,高位用符号位补

在c语言中>>是包含了shr和sar的,怎么区分有符号和无符号要看类型,比如 unsigned int就是无符号的,右移会使用shr

image-20231226033015280

计算机做加法的过程

4 + 5 = ?

1、4和5,先异或 4xor5

2、4和5进行与运算,得出来的结果判断是否有进位,如果是0就是没有进位,如果是非0就是有进位。最后左移1位

(4 and 5 )<< 1

3、将步骤1和步骤2的结果异或

4、将步骤1和步骤2的结果相与,判断还有没有进位,如果有则继续重复上述步骤

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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
	4------ 0000 0100

5------ 0000 0101
加---------------------------
0000 1001


第一步 异或
0000 0100

0000 0101
异或---------------------------
0000 0001


第二步 与,判断是否有进位

0000 0100

0000 0101
与---------------------------
0000 0100

第三步,如果第二步与的结果非0表示有进位,需要左移1位

0000 0100 << 1 = 0000 1000

第四步 继续异或

0000 0001

0000 1000
异或---------------------------
0000 1001


第五步 将第一步和第三步的结果进行与运算判断是否还有进位

0000 0001

0000 1000
与---------------------------
0000 0000

发现是0 表示没有进位,运算结束

4-5=?

4-5 = 4 + (-5)

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
4 + (-5)

4 0000 0100

-5 1111 1011


1) 异或

0000 0100

1111 1011
异或---------------------------
1111 1111


2) 判断是否有进位

0000 0100

1111 1011
与---------------------------
0000 0000

结果是0,没有进位。1111 1111 就是最终结果

X / Y 表示 X 可以减去多少次Y

DTDebug

配置DTDebug

image-20231226045552087

image-20231226045613640

UDD path和Plugin path 写自己安装目录下的

通用寄存器

image-20231226045728248

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
MOV 目标操作数,源操作数

mov eax,12
mov eax,ecx

mov ax,12
mov ax,cx

mov ah,ch
mov ah,12

mov al,cl
mov al,2

mov指令 左右两边的操作数必须是等宽的
例如
ax 和 cx是等宽的
al 和 cl是等宽的
ah 和 cl是等宽的
eax 和 ax不是等宽的,因为eax是32位的,ax是16位的

内存

image-20231226050932498

每个进程都有4G的虚拟内存,当某一块虚拟内存需要用到的时候,会将这块虚拟内存映射到物理内存中,最后物理内存会将这块内存映射到内存条中

1
2
3
4
5
6
7
BYTE 字节 = 8(BIT)		
WORD 字 = 16(BIT)
DWORD 双字 = 32(BIT)

1KB = 1024 BYTE
1MB = 1024 KB
1GB = 1024 MB

mov指令使用内存

1
2
3
4
5
mov 类型 ptr ds:[内存编号],值

mov byte ptr ds:[00A90280],22
mov word ptr ds:[00A90280],22
mov dword ptr ds:[00A90280],22

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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的值

寻址公式

1
2
3
4
5
6
7
LEA 指令
作用: 取当前内存的地址编号

lea 寄存器,内存地址

LEA EAX,DWORD PTR DS:[0X13FFC4] 内存地址的编号存放到EAX中
将DS:[0X13FFC4] 内存地址的编号存放到EAX中
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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
寻址公式一:[立即数]	


读取内存的值:

MOV EAX,DWORD PTR DS:[0x13FFC4]
MOV EAX,DWORD PTR DS:[0x13FFC8]

向内存中写入数据:

MOV DWORD PTR DS:[0x13FFC4],eax
MOV DWORD PTR DS:[0x13FFC8],ebx

获取内存编号:

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


寻址公式二:[reg] reg代表寄存器 可以是8个通用寄存器中的任意一个


读取内存的值:

MOV ECX,0x13FFD0
MOV EAX,DWORD PTR DS:[ECX]

向内存中写入数据:

MOV EDX,0x13FFD8
MOV DWORD PTR DS:[EDX],0x87654321

获取内存编号:

LEA EAX,DWORD PTR DS:[EDX]
MOV EAX,DWORD PTR DS:[EDX]


寻址公式三:[reg+立即数]

读取内存的值:

MOV ECX,0x13FFD0
MOV EAX,DWORD PTR DS:[ECX+4]

向内存中写入数据:

MOV EDX,0x13FFD8
MOV DWORD PTR DS:[EDX+0xC],0x87654321

获取内存编号:

LEA EAX,DWORD PTR DS:[EDX+4]
MOV EAX,DWORD PTR DS:[EDX+4]


寻址公式四:[reg+reg*{1,2,4,8}]


读取内存的值:
MOV EAX,13FFC4
MOV ECX,2
MOV EDX,DWORD PTR DS:[EAX+ECX*4]

向内存中写入数据:
MOV EAX,13FFC4
MOV ECX,2
MOV DWORD PTR DS:[EAX+ECX*4],87654321

获取内存编号:
LEA EAX,DWORD PTR DS:[EAX+ECX*4]


寻址公式五:[reg+reg*{1,2,4,8}+立即数]


读取内存的值:
MOV EAX,13FFC4
MOV ECX,2
MOV EDX,DWORD PTR DS:[EAX+ECX*4+4]

向内存中写入数据:
MOV EAX,13FFC4
MOV ECX,2
MOV DWORD PTR DS:[EAX+ECX*4+4],87654321

获取内存编号:
LEA EAX,DWORD PTR DS:[EAX+ECX*4+2]

存储模式

大端模式:数据高位在低位,数据低位在高位

小端模式:数据低位在低位,数据高位在高位

大端0x12345678 小端0x12345678 地址
12 78 0x00000000
34 56 0x00000001
56 34 0x00000002
78 12 0x00000003

DTDEBUG内存窗口的使用

分别以字节/字/双字形式来查看内存(db dw dd)

image-20231228045203084

基本汇编指令

MOV指令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
MOV 的语法:					

1、MOV r/m8,r8 r 通用寄存器

2、MOV r/m16,r16 m 代表内存

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

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

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

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

7、MOV r8, imm8

8、MOV r16, imm16

9、MOV r32, imm32

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

ADC指令:带进位加法

1
2
3
4
5
6
7
8
格式:ADC  R/M,R/M/IMM   两边不能同时为内存  宽度要一样						


ADC AL,CL

ADC BYTE PTR DS:[12FFC4],2

ADC BYTE PTR DS:[12FFC4],AL

SBB指令:带借位减法

1
2
3
4
5
6
7
8
格式:SBB  R/M,R/M   两边不能同时为内存  宽度要一样							


SBB AL,CL

SBB BYTE PTR DS:[12FFC4],2

SBB BYTE PTR DS:[12FFC4],AL

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

XCHG指令:交换数据

1
2
3
4
5
6
7
8
格式:XCHG  R/M,R/M/IMM   两边不能同时为内存  宽度要一样							


XCHG AL,CL

XCHG DWORD PTR DS:[12FFC4],EAX

XCHG BYTE PTR DS:[12FFC4],AL

AND 指令

与指令,两个是1才是1,否则是0

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
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就是1,两个是0就是0

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,否则是0

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 指令

非指令,0变1,1变0

1
2
3
4
5
NOT r/m8

NOT r/m16

NOT r/m32

MOVS指令:移动数据 内存-内存

移动内存[ESI]]的数据到内存[EDI]中

每复制一次,ESI和EDI都会+1(具体加几或减几要看你一次移动多少个字节)或-1,具体是加还是减要看标志寄存器中DF的值,DF是0就+1,D是1就-1

1
2
3
4
5
6
7
BYTE/WORD/DWORD						

MOVS BYTE PTR ES:[EDI],BYTE PTR DS:[ESI] 简写为:MOVSB

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

MOVS DWORD PTR ES:[EDI],BYTE PTR DS:[ESI] 简写为:MOVSD

image-20231228060752810

STOS指令:

将Al/AX/EAX的值存储到[EDI]指定的内存单元
1
2
3
4
5
STOS BYTE PTR ES:[EDI]			简写为STOSB	

STOS WORD PTR ES:[EDI] 简写为STOSW

STOS DWORD PTR ES:[EDI] 简写为STOSD

image-20231228062418429

REP指令:

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

1
2
3
4
5
6
7
8
9
10
11
MOV ECX,10	

REP MOVSD

REP STOSD

将内存[esi]中的数据重复ecx次复制到内存[edi]中,每次重复esi和edi都加4
REP MOVS DWORD PTR ES:[EDI],DWORD PTR ES:[ESI]

将EAX中的值重复ECX次复制到内存[EDI]中,每重复一次,edi都加4
REP STOS DWORD PTR ES:[EDI]

堆栈

查看堆栈的大小

image-20231228072101553

image-20231228072209382

image-20231228072142171

ESP寄存器用来存放当前堆栈使用到哪里的地址

PUSH指令:

入栈指令

1
2
3
4
5
6
7
8
9
1、PUSH r32

2、PUSH r16

3、PUSH m16

4、PUSH m32

5、PUSH imm8/imm16/imm32

POP指令

出栈指令

1
2
3
4
5
6
7
1、POP r32

2、POP r16

3、POP m16

4、POP m32

通过其他指令实现堆栈的存取

image-20231228073758951

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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
步骤一:压入数据			


MOV EBX,13FFDC BASE
MOV EDX,13FFDC TOP

方式一:

MOV DWORD PTR DS:[EDX-4],0xAAAAAAAA
SUB EDX,4

方式二:

SUB EDX,4
MOV DWORD PTR DS:[EDX],0xBBBBBBBB

方式三:

MOV DWORD PTR DS:[EDX-4],0xDDDDDDDD
LEA EDX,DWORD PTR DS:[EDX-4]

方式四:

LEA EDX,DWORD PTR DS:[EDX-4]
MOV DWORD PTR DS:[EDX],0xEEEEEEEE



步骤二:读取第N个数

1、方式一:通过Base加偏移来读取

读第一个压入的数据:

MOV ESI,DWORD PTR DS:[EBX-4]

读第四个压入的数据:

MOV ESI,DWORD PTR DS:[EBX-0x10]


2、方式二:通过Top加偏移来读取

读第二个压入的数据:

MOV EDI,DWORD PTR DS:[EDX+4]

读第三个压入的数据:

MOV EDI,DWORD PTR DS:[EDX+8]

步骤三:弹出数据

MOV ECX,DWORD PTR DS:[EDX]
LEA EDX,DWORD PTR DS:[EDX+4]

MOV ESI,DWORD PTR DS:[EDX]
ADD EDX,4

LEA EDX,DWORD PTR DS:[EDX+4]
MOV EDI,DWORD PTR DS:[EDX-4]

修改EIP寄存器

EIP寄存器存放的是cpu下一条执行的指令

JMP指令:修改EIP的值

1
2
3
4
5
6
JMP 寄存器/立即数		
类似
MOV EIP,寄存器/立即数

jmp eax
jmp 0x11232244

CALL指令:

1
2
3
4
5
CALL 地址A/寄存器

类似
PUSH 地址B
MOV EIP,地址A/寄存器

RET指令:

1
2
3
4
5
6
7
8
9
10
RET [num]
[num] 可选

ret
ret 8

类似
LEA ESP,[ESP+4]

MOV EIP,[ESP-4]

堆栈平衡

进函数前esp和ebp是什么样的,执行函数之后就要还原什么样的

EFLAGS寄存器

image-20240106220148670

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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
查看DTDEBUG中的EFLAGS的值,然后转换成二进制的形式,并取出CF/PF/AF/ZF/SF/OF的值							

记住这几个寄存器的位置和名称

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

MOV AL,0xEF MOV AL,0xFE
ADD AL,2 ADD AL,2


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

MOV AL,3
ADD AL,3
ADD AL,2

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

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

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

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

MOV EAX,0x55EEFFFF MOV AX,5EFE MOV AL,4E
ADD EAX,2 ADD AX,2 ADD AL,2

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

XOR EAX,EAX

MOV EAX,2
SUB EAX,2


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

MOV AL,7F
ADD AL,2

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


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


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

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

溢出主要是给有符号运算使用的,在有符号的运算中,有如下的规律:

正 + 正 = 正 如果结果是负数,则说明有溢出

负 + 负 = 负 如果结果是正数,则说明有溢出

正 + 负 永远都不会有溢出.

image-20240106220407304

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
1、无符号、有符号都不溢出				

MOV AL,8
ADD AL,8

2、无符号溢出、有符号不溢出

MOV AL,0FF
ADD AL,2

3、无符号不溢出、有符号溢出

MOV AL,7F
ADD AL,2

4、无符号、有符号都溢出

MOV AL,0FE
ADD AL,80

CMP指令:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
	

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

该指令是比较两个操作数,实际上,它相当于SUB指令,但是相减的结构并不保存到第一个操作数中。

只是根据相减的结果来改变零标志位的,当两个操作数相等的时候,零标志位置1。

MOV EAX,100
MOV ECX,100
CMP EAX,ECX 观察Z位


MOV EAX,100
MOV ECX,200
CMP EAX,ECX 观察S位


CMP AX,WORD PTR DS:[405000]

CMP AL,BYTE PTR DS:[405000]

CMP EAX,DWORD PTR DS:[405000]

TEST指令:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
			

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

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

与的操作表项如下:

1 and 1 = 1

1 and 0 = 0

0 and 1 = 0

0 and 0 = 0

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

TEST EAX,EAX 观察Z位

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

JCC指令

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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
1、	JE, JZ       		结果为零则跳转(相等时跳转)						ZF=1


2、 JNE, JNZ 结果不为零则跳转(不相等时跳转) ZF=0


3、 JS 结果为负则跳转 SF=1


4、 JNS 结果为非负则跳转 SF=0


5、 JP, JPE 结果中1的个数为偶数则跳转 PF=1


6、 JNP, JPO 结果中1的个数为偶数则跳转 PF=0


7、 JO 结果溢出了则跳转 OF=1


8、 JNO 结果没有溢出则跳转 OF=0


9、 JB, JNAE 小于则跳转 (无符号数) CF=1


10、 JNB, JAE 大于等于则跳转 (无符号数) CF=0


11、 JBE, JNA 小于等于则跳转 (无符号数) CF=1 or ZF=1


12、 JNBE, JA 大于则跳转(无符号数) CF=0 and ZF=0


13、 JL, JNGE 小于则跳转 (有符号数) SF≠ OF


14、 JNL, JGE 大于等于则跳转 (有符号数) SF=OF


15、 JLE, JNG 小于等于则跳转 (有符号数) ZF=1 or SF≠ OF


16、 JNLE, JG 大于则跳转(有符号数) ZF=0 and SF=OF



有符号无符号的区别:

CMP AL,CL
JG 0x12345678
JA 0x12345678