Windows 逆向-标志寄存器

Oyst3r 于 2023-11-27 发布

前言

这节课讲的内容还是很重要的,直接影响了后面的 JCC 能不能顺利的拿下,而 JCC 又影响了循环判断的反汇编代码

课堂

EFLAGS 寄存器,主要用于反映处理器的状态和寄存器运算结果的某些特征及控制指令的执行。通俗来说:标志寄存器与 CPU 中的其他寄存器不一样:它是按位起作用的,也就是说,它的每一位都有专门的含义,记录特定的信息

OD 中标志寄存器怎么查看:也在寄存器区域,OD 已经帮我们把标志寄存器的 32 位拆分好了,C 就是表示 CF,P 就表示 PF,等等。最下面的 EFL 就表示标志寄存器,用十六位表示 32 位数。有些软件如果没有帮我们拆分成各个标志位,则我们需要自己会把十六进制表示的标志寄存器中的值化成 32 位二进制数,然后去对应的位上找标志

标志寄存器常用的标志

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

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

MOV AL,3
ADD AL,3
ADD AL,2
辅助进位标志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
零标志ZF(Zero Flag):零标志ZF用来反映运算结果是否为0。
如果运算结果为0,则其值为1,否则其值为0。在判断运算结果是否为0时,可使用此标志位。

XOR EAX,EAX

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

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

CF 溢出与 OF 溢出区别

总结:进位标志 CF 表示无符号数运算结果是否超出范围;溢出标志 OF 表示有符号数运算结果是否超出范围。简单来说就是如果你把做运算的数当成无符号数则判断是否溢出(进位)看 CF 位;如果你把做运算的数当成有符号数则判断是否溢出看 OF 位,计算机是只管存数的,它可不知道如果第一位是 1 了的话,那就代表负数

CF 溢出的话就不说了,之所以有这个的原因就是不能说 FF 再加一个 2,那结果就变成 1 了,所以就有了 CF,而同样的,如果已经是带符号的加法了,不能说 7F+2 就变成一个负数了,所以才会拿一个 OF 去记录这种不合理的变化

ADD 可以看成逆时针,SUB 可以看成顺时针,然后无符号数就正常旋转,有符号数,化成原来的数(比如-1 是 FF)然后旋转

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

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

正 + 负 永远都不会有溢出(这个很好理解,比如 5-12,可以看成-12+5,结果肯定不会溢出)

MOV AL,8
ADD AL,8
MOV AL,0xFF
ADD AL,2
MOV AL,7F
ADD AL,2
MOV AL,0xFE
ADD AL,80

一些小问题

sub 5,12		cf变	of不变
add 5 -12		cf不变	of不变

所以还是上面说的那句话,sub就是顺时针旋转,add就是逆时针旋转

详情看上方图片的链接,过了好久的笔记现在还能找回来,我都佩服我自己了

其他的汇编指令

ADC

ADC指令:带进位加法

	格式:ADC  R/M,R/M/IMM   两边不能同时为内存  宽度要一样

	ADC AL,CL

	ADC BYTE PTR DS:[12FFC4],2

	ADC BYTE PTR DS:[12FFC4],AL

SBB

SBB指令:带借位减法

	格式:SBB  R/M,R/M   两边不能同时为内存  宽度要一样

	SBB AL,CL

	SBB BYTE PTR DS:[12FFC4],2

	SBB BYTE PTR DS:[12FFC4],AL

有没有好奇他俩是怎么诞生出来的,举个栗子:你要计算十进制 3389+443 ,但是你只会计算和记录两位数,于是你先计算了 89+43=132 , 但是你只能记住两位数,所以你记下了 32 ,然后把进位出的 1 扔进了 CF 暂存;然后你再计算 33+4=37 ,顺便加上 CF 的进位得到 38 ,跟刚才的 32 组合起来得到结果 3832

XCHG

XCHG指令:交换数据

	格式:XCHG  R/M,R/M/IMM   两边不能同时为内存  宽度要一样

	XCHG AL,CL

	XCHG DWORD PTR DS:[12FFC4],EAX

	XCHG BYTE PTR DS:[12FFC4],AL

MOVS 指令

内存和内存之间移动数据(这是比较少有的源操作数与目标操作数都可以为内存的命令)

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
mov esi,0x19ff74     #esi寄存器中存的值为内存地址0x19ff74,且已知此内存地址中存的值为0x11111111
mov edi,0x19ff80     #edi寄存器中存的值为内存地址0x19ff80,且已知此内存地址中存的值为0x22222222

#当DF标志位为0时
movsb   #执行后,edi中的存的内存地址0x19ff80中的值变化为0x22222211,且esi和edi中的值都加1,则esi中值为			0x19ff75,edi中的值为0x19ff81

#当DF标志位为1时
movsb   #执行后,edi中的存的内存地址0x19ff80中的值变化为0x22222211,且esi和edi中的值都减1,则esi中值为			0x19ff73,edi中的值为0x19ff7f

STOS

STOS指令:讲Al/AX/EAX的值存储到[EDI]指定的内存单元


	STOS BYTE PTR ES:[EDI]			简写为STOSB

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

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

举例:

MOV EAX,0x12345678
MOV EDI,0x19FF74     #将内存地址编号0x19ff74存入edi中,且已知此内存地址中的值为0x75b5fa29

#当DF标志位为0时
STOS BYTE PTR ES:[EDI]   #edi指定的0x19ff74内存单元中的值变为0x75b5fa78,并且edi中的值加1,变为							  0x19ff75
----------------------------
#当DF标志位为1时
STOS BYTE PTR ES:[EDI]   #edi指定的0x19ff74内存单元中的值变为0x75b5fa78,并且edi中的值减1,变为							  0x19ff73

REP

按计数寄存器 (ECX) 中指定的次数重复执行字符串指令(STOS、MOVS),每执行一次,ECX 的值会减 1,最终减为 0 结束执行

举例:

MOV ECX,0x10        #重复的次数为16次
MOV EAX,0x12345678      #存入EDI中的值为0x12345678,根据数据宽度来取

#如果DF标志位为0
REP STOS DWORD PTR ES:[EDI]   #将EAX中的值0x12345678取DWORD--32位存入EDI中存的内存地址中,并且EDI								 中存的值会自动+4。接着将上述过程循环16次
-----------------------------------------------------------------------
#如果DF标志位为1
REP STOS DWORD PTR ES:[EDI]   #将EAX中的值0x12345678取DWORD--32位存入EDI中存的内存地址中,并且EDI								 中存的值会自动-4。接着将上述过程循环16次

作业

1.前面几个就用这个图片解答了,懒得去 CV 了

2.

mov ecx,0x5
rep movsb
mov eax,0x11111111
mov ecx,0x5
rep stosd