【reverse】逆向5 标志寄存器

【reverse】逆向5 标志寄存器

1、引言

通过一个creak.exe文件的爆破,引出现阶段需要学习的知识

【reverse】逆向5 标志寄存器

2、标志寄存器

【reverse】逆向5 标志寄存器

标志寄存器有上图这么多个

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

下面是6个状态标志位

1.进位标志CF(Carry Flag)

如果运算结果的最高位产生了一个进位或者借位,那么其值为1,否则为0

做个实验

我们先给eax一个5555FFFF的数据,然后再加1

【reverse】逆向5 标志寄存器

然后将c变成0

【reverse】逆向5 标志寄存器

运行这两句汇编

发现eax虽然进位了,但不是最高位进位,因为eax是32位的

【reverse】逆向5 标志寄存器

我们再试一试al

【reverse】逆向5 标志寄存器

把所有标记寄存器归为0

运行这两句汇编

【reverse】逆向5 标志寄存器

al是FF,加1之后溢出,但是实际上最高位也就是第八位,进位了,所以c为1

所以,一定要注意是最高位

2. 奇偶标志PF(Parity Flag)

奇偶标志PF用于反映运算结果中最低有效字节中“1”的个数的奇偶性

注意是最低有效字节,也就是只看最后两位

如果“1”的个数为偶数,则PF的值为1,反之为0(一定转为二进制来看)

我们运行下面的指令

【reverse】逆向5 标志寄存器

首先将al赋值0

然后让al+0x3

hex中0+3 = 3

转为2进制,3 = 0011,有两个1,所以p为1

【reverse】逆向5 标志寄存器

再执行+3的指令

hex中3+3 = 6

转为2进制,6 = 0110,有两个1,所以p为1

【reverse】逆向5 标志寄存器

再执行+2的指令

hex中6 + 2 = 8

转为2进制,8 = 1000,只有1个1,所以p=0

【reverse】逆向5 标志寄存器

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

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

  • 在字操作时,发生低字节向高字节进位或者借位时
  • 再字节操作时,发生低4位向高4位进位或者借位时

看我绿笔画的圈,这个位置的数进不进位,进位就是1,否则是0

【reverse】逆向5 标志寄存器

【reverse】逆向5 标志寄存器

【reverse】逆向5 标志寄存器

4.零进位标志ZF(Zero Flag)

零标志位ZF用来反映运算结果是否为0

如果运算结果为0,ZF=1,否则为0

mov指令不算运算

看这句指令,让eax和自己异或,两个相同的数字异或=0,所以计算结果为0,所以ZF= 1

【reverse】逆向5 标志寄存器

【reverse】逆向5 标志寄存器

5.符号标志SF(Sign Flag)

符号标志SF用来反映运算结果的符号位,它与运算结果的最高位相同

首先确定一点,mov指令不影响标志寄存器

第一句汇编,让al存0x7F (0111 1111)

第二句汇编,让al+2

【reverse】逆向5 标志寄存器

0111 1111 + 0000 0010 = 1000 0001

符号位(也就是从左向右第一位)运算后是1,所以SF=1

【reverse】逆向5 标志寄存器

6.溢出标志OF(Overflow Flag)

溢出标志OF用于反映有符号数加减运算所得结果是否溢出

如果运算结果超过当前运算位数所能表示的范围,则称为溢出,OF的值置为1,否则OF的值被清为0

如何辨别CF和OF?

CF是最高位进位,而OF时有符号数的溢出

有符号数的范围:

  • 正数:0~7F
  • 负数:FF~80

有无符号是程序员代码规定的,不是计算机规定的,计算机内相同的数——FF,如果是有符号,那就是-1,如果无符号,那就是15

【reverse】逆向5 标志寄存器

【reverse】逆向5 标志寄存器

举几个例子

8位,无符号范围是0~FF

有符号数的范围:正数:0~7F;负数:FF~80

  • 无符号、有符号都不溢出

    mov al,8
    add al,8
    
  • 无符号溢出,有符号不溢出(-1+2)

    mov al,0xff
    add al,2
    
  • 无符号不溢出(小于FF),有符号溢出(最大的正数还+2,溢出,成为负数)

    mov al,7f
    add al,2
    
  • 无符号(大于FF)、有符号(最小的负数还加负数,两负数相加得到正数)都溢出

    mov al,0xfe
    add al,0x80
    

然后计算机最底层的处理OF标志其实是这样的:

  1. 判断符号位是否有进位,有进位,标志1,无进位,标志0
  2. 判断最高有效数值位向符号位产生进位否,有进位,标志1,无进位,标志0
  3. 将第一步和第二部得到的数字xor一下,得到的数字就是OF标志位的数字

我们看下面这个例子(OF的前提是必须是有符号数

【reverse】逆向5 标志寄存器

3、指令

1.ADC指令

adc指令就是带进位的加法(这个进位就看CF进位标志,是1就进位,0就不进)

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

R是寄存器,M是内存,IMM是立即数

两边不能同时为内存,且宽度要一样

adc al,cl
adc byte ptr ds:[12ffc4],2
adc byte ptr ds:[12ffc4],al

2.SBB指令

sbb就是带借位的减法(借位也是看CF标志,是1就借位,反之不借)

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

R是寄存器,M是内存,IMM是立即数

两边不能同时为内存,且宽度要一样

sbb al,cl
sbb byte ptr ds:[12ffc4],2
sbb byte ptr ds:[12ffc4],al

3.XCHG指令

xchg指令是交换数据的指令

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

xchg al,cl
xchg dword ptr ds:[12ffc4],eax
xchg byte prt ds:[12ffc4],al

4.MOVS指令

movs指令是移动数据的指令,这个指令必须对edi和esi使用

这个指令有点特殊,我们之前学习的指令都是不能两边同时为内存的

但是这个指令,他必须两边都是内存,且都是edi和esi使用的!

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

movsb:移动esi中地址数据到edi中,同时esi、edi都加1

movsw:移动esi中地址数据到edi中,同时esi、edi都加2

movsd:移动esi中地址数据到edi中,同是esi、edi都加4

esi和edi的加和减是由DF标志寄存器决定的,DF=0就是加,DF=1就是减

5.STOS指令

stos指令是将al/ax/eax的值存到[edi]指定的内存单元

stos byte ptr es:[edi]		简写为stosb
stos word ptr es:[edi]		简写为stosw
sots dword ptr es:[edi]		简写为stosd

存哪个寄存器由是数据宽度决定的

byte是al

word是ax

dword是eax

同样的

edi的加和减是由DF标志寄存器决定的,DF=0就是加,DF=1就是减。

加减的值也是和位数相关

byte +- 1

word +- 2

dword +- 4

6.REP指令

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

mov ecx,10
rep movsd
rep stosd

这里给ecx存10是hex形式,所以循环了16次

rep movsd就是循环16次将esi的值赋给edi,当然,因为刚刚我们提到了DF标志位,所以会根据DF的值来自增或自减。这里是dword,所以是+-4

rep stosd就是将eax中的值存入edi中16次,这里的edi的+-也是通过DF标志位来的。DF=1是减,DF=0是加

4、本节练习

海哥布置的作业,有机会补上!

【reverse】逆向5 标志寄存器

上一篇:【reverse】逆向3 寻找地址


下一篇:js函数组合