滴水逆向--01-19 标志寄存器
标志寄存器

在哪看?OD 已经把 32 位拆分好列出来了,C就是表示CF,P就表示PF…最下面那个 EFL 就是拆开前的样子,需要自己拆的时候就把这个 16 进制数展开成 32 位二进制就行

记住这几个寄存器的位置和名称:
-
进位标志 CF(Carry Flag):如果运算结果的最高位产生了一个进位或借位,那么,其值为 1,否则 0
- 研究进位时,要先确定数字的宽度,知道了宽度才能确定最高位
1
2
3MOV AL, 0xEF MOV AL, 0xFE MOV 指令不影响标志寄存器
ADD AL, 2 ADD AL, 2
CF=0 CF=1 -
奇偶标识为 PF(Parity Flag):用于反映运算结果中 1的个数的奇偶性,“1”的个数为偶数,PF 的值为1,否则 0,只看低八位,不管数据宽度是多少
1
2
3MOV AL, 3
ADD AL, 3 PF=0
ADD AL, 2 PF=1 -
辅助进位标志 AF(Auxiliary Carry Falg):
在发生下列情况时,辅助进位标志 AF 的值被置为 1,否则 0(加醋的部分发生进位,就会是 1):
(1)在字操作时,发生低字节向高字节进位或借位时 FFFFFFFF
(2)在字节操作时,发生低 4 位向高 4 位进位或借位时 FFFF
1
2MOV EAX, 0x55EEFFFF MOV AX, 0x5EFE MOV AL, 4E
ADD EAX, 2 ADD AX, 2 ADD AL, 2 -
零标志 ZF(Zero Flag):零标志 ZF 用来反映运算结果是否为 0,是 0 则被置为 1,否则 0。用于判读啊结果是否为 0
1
XOR EAX, EAX
-
符号标志 SF(Sign Flag):用来反映运算结果的符号位,与运算结果的最高位相同
1
2MOV AL, 7F
ADD AL, 2 -
溢出标志 OF(Overflow Flag):用于反映有符号数加减运算所得结果是否溢出。如果运算结果超过当前运算位数所能表示的范围,则置 1,否则 0
最高位进位(CF)与溢出(OF)的区别:
-
进位标志表示无符号数运算结果是否超出范围
-
溢出标志表示有符号数运算结果是否超出范围
-
溢出主要是给有符号数运算用的,在有符号的运算中,有如下的规律:
- 正 + 正 = 正 如果结果是负数,则说明有溢出
- 负 + 负 = 负 如果结果是正数,则说明有溢出
- 正 + 负 永远都不会有溢出
做有符号数运算关注 OF,做无符号数运算关注 CF
-
小练习:
-
无符号、有符号都不溢出
1
2MOV AL, 8
ADD AL, 8 -
无符号溢出,有符号不溢出
1
2MOV AL, 0xFF
ADD AL, 2 -
无符号不溢出,有符号溢出
1
2MOV AL, 0x7F
ADD AL, 2 -
无符号、有符号都溢出
1
2MOV AL, 0xFE
ADD AL, 80
-
-
拓展:几个指令
-
ADC 指令:带进位加法(不仅仅计算两个数相加,还把 CF 位也一起加上了)
格式:ADC R/M, R/M/IMM 两边不能同时为内存,宽度要一样


-
SBB 指令:带借位减法(同加法)
格式:SBB R/M, R/M/IMM 两边不能同时为内存,宽度要一样
-
XCHG 指令:交换数据
格式:XCHG R/M, R/M(没有立即数,得是俩容器) 两边不能同时为内存,宽度要一样
-
MOVS 指令:移动数据,内存-内存
BYTE/WORD/DWORD
1
2
3MOVSB: MOVS BYTE PTR ES:[EDI], BYTE PTR DS:[ESI]
MOVSW: MOVS WORD PTR ES:[EDI], WORD PTR DS:[ESI]
MOVSD: MOVS DWORD PTR ES:[EDI], DWORD PTR DS:[ESI]

注意:
- 将后面 ESI 中存的内存地址编号中的值(按照给定的数据宽度来取),存入到前面的 EDI 中存的内存地址编号中
- 指令执行后,ESI 和 EDI 都加了 4,方便下一个值的赋值,这里加 4 还是加 2 取决于 movsd 还是 movsw,加还是减取决于 DF 标志位(DF=1的时候是减)
- 如果遇到 MOVS 指令,很可能是字符串的复制
-
STOS 指令:将 AL/AX/EAX 的值存储到 [EDI] 指定的内存单元
1
2
3STOS BYTE PTR ES:[EDI] 简写为 STOSB
STOS WORD PTR ES:[EDI] 简写为 STOSW
STOS DWORD PTR ES:[EDI] 简写为 STOSDAL/AX/EAX 取决于给的数据宽度是 byte、word 还是 dword,EDI 依据 DF 标志位为 0 or 1 以及数据宽度,加 1/2/4 或者减 1/2/4

-
REP 指令:按计数寄存器(ECX)中指定的次数重复执行字符串执行
每执行一次,ECX的值会减1,最终减为0结束执
课后作业
-
熟练记住 CF/PF/AF/ZF/SF/OF 的位置
-
写汇编指令只影响 CF 位的值(不能影响其他标志位!)
1
2
3
4
5
6
7
8
9
10等价条件:
1-CF (Carry Flag):最高位发生进位
0-ZF (Zero Flag):结果不能为 0
0-SF (Sign Flag):结果的最高位不能为 1
0-OF (Overflow Flag):不能发生有符号溢出
0-AF (Auxiliary Flag):低半部分不能发生进位
0-PF (Parity Flag):低 8 位中 1 的个数要是奇数
汇编指令:
mov al, 0xF0
add al, 11 -
写汇编指令只影响 PF 位的值
1
2
3
4
5
6
7
8
9
10等价条件:
0-CF (Carry Flag):最高位不能发生进位
0-ZF (Zero Flag):结果不能为 0
0-SF (Sign Flag):结果的最高位不能为 1
0-OF (Overflow Flag):不能发生有符号溢出
0-AF (Auxiliary Flag):低半部分不能发生进位
1-PF (Parity Flag):低 8 位中 1 的个数要是偶数
汇编指令:
mov ax, 0x6AAA
add ax, 0x02 -
写汇编指令只影响 AF 位的值
1
2
3
4
5
6
7
8
9
10等价条件:
0-CF (Carry Flag):最高位不能发生进位
0-ZF (Zero Flag):结果不能为 0
0-SF (Sign Flag):结果的最高位不能为 1
0-OF (Overflow Flag):不能发生有符号溢出
1-AF (Auxiliary Flag):低半部分发生进位
0-PF (Parity Flag):低 8 位中 1 的个数要是奇数
汇编指令:
mov ax, 0x6AFF
add ax, 0x02 -
写汇编指令只影响 SF 位的值
1
2
3
4
5
6
7
8
9
10等价条件:
0-CF (Carry Flag):最高位不能发生进位
0-ZF (Zero Flag):结果不能为 0
1-SF (Sign Flag):结果的最高位为 1
0-OF (Overflow Flag):不能发生有符号溢出
0-AF (Auxiliary Flag):低半部分不能发生进位
0-PF (Parity Flag):低 8 位中 1 的个数要是奇数
汇编指令:
mov ax, 0xAAAA
add ax, 0x01 -
写汇编指令只影响 OF 位的值
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18等价条件:
0-CF (Carry Flag):最高位不能发生进位
0-ZF (Zero Flag):结果不能为 0
0-SF (Sign Flag):结果的最高位不能为 1
1-OF (Overflow Flag):发生有符号溢出
0-AF (Auxiliary Flag):低半部分不能发生进位
0-PF (Parity Flag):低 8 位中 1 的个数要是奇数
思路:
有符号运算结果溢出,ADD 指令有两种情况:
1、正数 + 正数 = 负数 (SF=1,舍弃)
2、负数 + 负数 = 正数 (CF=1,不能用)
都不能用,但是还有 SUB,也是分为两种情况:
1、正数 - 负数 = 负数 (正减负应该更正,结果变负了,溢出)
2、负数 - 正数 = 正数 (负减正应该更负,结果变正了,溢出)
但是情况一是不可以选择的,CF 它不管你正负,它看的是两个无符号数之间谁大谁小,在它的眼里,情况一就是一个小数减去了一个大数,CF 必为 1,所以不可以选择。于是我们选择情况二,构造一个负数减去一个正数,并使得结果为正
汇编指令:
mov ax, 0x90
add ax, 0x20 -
用 MOVS 指令分别移动 5 个字节、5 个字、5 个双字
-
用 STOS 指令分别移动 5 个字节、5 个字、5 个双字
-
使用 REP 指令重写 7、8 题