滴水逆向学习...

【reverse】逆向5 标志寄存器

1、引言

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

image-20210731140054294

2、标志寄存器

image-20210731140842369

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

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

下面是6个状态标志位

1.进位标志CF(Carry Flag)

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

做个实验

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

image-20210731142651477

然后将c变成0

image-20210731142759056

运行这两句汇编

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

image-20210731142832797

我们再试一试al

image-20210731142946549

把所有标记寄存器归为0

运行这两句汇编

image-20210731143040684

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

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

2. 奇偶标志PF(Parity Flag)

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

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

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

我们运行下面的指令

image-20210731143709779

首先将al赋值0

然后让al+0x3

hex中0+3 = 3

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

image-20210731143857830

再执行+3的指令

hex中3+3 = 6

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

image-20210731144006559

再执行+2的指令

hex中6 + 2 = 8

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

image-20210731144054059

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

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

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

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

image-20210731144723871

image-20210731144758197

image-20210731144825801

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

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

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

mov指令不算运算

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

image-20210731150008058

image-20210731150053241

5.符号标志SF(Sign Flag)

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

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

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

第二句汇编,让al+2

image-20210731150405217

0111 1111 + 0000 0010 = 1000 0001

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

image-20210731150541600

6.溢出标志OF(Overflow Flag)

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

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

如何辨别CF和OF?

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

有符号数的范围:

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

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

image-20210731152807484

image-20210731152129980

举几个例子

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的前提是必须是有符号数

image-20210731210314891

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、本节练习

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

image-20210731190322629