逆向笔记
逆向
计算机中的正负数
-1是FF,0是00
7F是最大的正数,80是最小的负数
32位通用寄存器的指定用途如下: | 寄存器 | 主要用途 | 编号 | 存储数据的范围 | |
---|---|---|---|---|---|
EAX | 累加器 | 0 | 0 – 0xFFFFFFFF | ||
ECX | 计数 | 1 | 0 – 0xFFFFFFFF | ||
EDX | I/O指针 | 2 | 0 – 0xFFFFFFFF | ||
EBX | DS段的数据指针 | 3 | 0 – 0xFFFFFFFF | ||
ESP | 堆栈指针 | 4 | 0 – 0xFFFFFFFF | ||
EBP | SS段的数据指针 | 5 | 0 – 0xFFFFFFFF | ||
ESI | 字符串操作的源指针;SS段的数据指针 | 6 | 0 – 0xFFFFFFFF | ||
EDI | 字符串操作的目标指针;ES段的数据指针 | 7 | 0 – 0xFFFFFFFF |
Property | 寄存器 | 1 | 3 |
---|---|---|---|
32位 | 16位 | 8位 | 0 |
EAX | AX | AL | 0 |
ECX | CX | CL | 1 |
EDX | DX | DL | 2 |
EBX | BX | BL | 3 |
ESP | SP | AH | 4 |
EBP | BP | CH | 5 |
ESI | SI | DH | 6 |
EDI | DI | BH | 7 |
标志寄存器
1.PE结构
2.下断点
3.WIN32 API
4.什么是函数调用
5.熟悉堆栈——画过堆栈图
6.call JCC 标志寄存器
断点小理解:程序跑到MessageBox的时候就停下来一个函数刚开始执行的时候,这个栈顶存储的就是调用这个函数时候函数的返回地址JE根本不管你们上面是什么,他只看标志寄存器,标志寄存器符合他的条件了就跳,不符合了就不跳JE他如果发现这个zero flag控制是1的话他就跳否则他就不跳
所有的JCC都是由标志寄存器控制的
鼠标的位置不是0吗,然后我们双击变成1
只要找到关键的点,不跳的改成跳就ok,叫爆破,找到关系跳转(有基础的!看那个滴水逆向三期的标志寄存器这期-。-由于我上面的知识点也不太熟悉,就无法很好解释啦!大家去自行理解啦!)
标志寄存器
标志寄存器32位的 CF PF AF ZF SF OF这几个位要背下来的(第几位)
1.进位标志寄存器(carry flag):如果运算结果的最高位产生了一个进位或者借位(比如两个数相加往前面加了一个值叫进位,同样两个数相减不够减需要管前面的数借个值叫借位)(在我们眼中是不存在什么进位和借位的,减法是什么是一个正数加一个负数,所有数的加减都是一样的都是加法),那么,值为1,否则为0
(最高位)要记住,是最高位产生了一个进位或者借位
标志寄存器中可以看到了EFL是所有数的一个汇总 上面的是常用的一个标志寄存器,是od已经帮我们拆好的,因为方便可以看出变化所以提前把那些1改成了0
上面的那个mov eax,0x5555FFFF add eax,1 加完后最高位并没有变 所以标志寄存器c的位置没有变化
试一下8位寄存器的 mov al,0xFF add al,1研究这些位的时候一定要去确定这些的数据宽度,数据宽度都不确定的话,最高位哪里找,F8后发现c的位置变成了1所以c位看的是最高位,最高位由数据的宽度决定的FF+1就越位了
看图来说,有人会有疑问说,EAX不应该是55560100 为什么是55560000因为刚才我们只看8位,实际上我们1已经进去了,但是进到了c中,所以这个1其实没有丢,为什么不放到前面,因为这样是不允许的,因为只看8位,所以事先一定要确定数据宽度是多少,如果不确定数据宽度其他都没有意义
2.奇偶标志PF(Parity Flag),奇偶标志PF用于反映运算结果中1的个数的奇偶性,如果1的个数为偶数,则PF的值为1,否则为0
目的操作数最低有效字节中1的个数为偶数时,奇偶(PF)标志位置1
mov al,3并不是说是3这个数,而是我们要把他改成2进制,然后去看1的个数
F8第一个的时候看eax的后两位因为al是8位寄存器,6代表的是0110看到了p的位置变成了1,然后再加2的时候变成了8变成了1000,可以看到p的位置变成了0
3.辅助进位标志AF(Auxiliary Carry Flag):
在发生下列情况时,辅助进位标志AF的值为1,否则其值为0
在字操作时,发生低字节向高字节进位或者借位时
在字节操作时,发生低4位向高4位
mov eax,0x55EEFFFF add eax,2
F8之后发现变化了,以此类推类推32位的 16位的等
4.零标志位ZF(Zero Flag),零标志ZF用来反映运算结果是否为0
如果运算结果为0,则值为1,否则值为0,在判断运算结果是否为0时,可以用此标志位
mov不算运算
XOR是异或运算,所以EAX和EAX异或都是为0的,还有个功能就是EAX清零功能同样还有改变标志寄存器的作用 F8后可以看到 zero flag为1了,mov eax,0和这个xor eax,eax的区别就是,mov这个指令是不改变标志寄存器的,所以不能说不能说这个两个是一样的
5.符号标志位SF(Sign Flag),符号标志SF用来反映运算结果的符号位,他与运算结果的最高位相同
可以看到s的位置变成了1
6.溢出标志位OF(Overflow Flag):比如有一个杯子,放水放满了再放就出去了,叫溢出,但是怎么区别看起来都是最高位的问题
CF是我们在做无符号运算的时候应该注意的寄存器,假设做的运算是有符号的运算那我们就去看O位
正+负永远都不会溢出
正+正如果等于负数,说明有溢出
负+负如果是正数,那么就溢出了
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
看这些的时候都要去看是不是有符号的还是无符号的,正负肯定不溢出
加减法中ZF,OF位设置方法
CF位是进位标志位,OF是溢出标志位。
CF可表示无符号数的溢出,
OF可表示有符号数的溢出。
加法中:
最高有效位进位时CF=1,无进位CF=0。
两个操作数符号相同,结果符号与之相反OF=1,其他情况均为OF=0。即加法只有同号才有可能会溢出。
正数+正数=负数
负数+负数=正数
减法中:
最高有效位借位时CF=1,无借位CF=0。
两个操作数符号相反,结果符号与减数相同OF=1,其他情况均为OF=0。即减法只有异号才会溢出。
(ps:被减数-减数,这个我也经常弄混淆。我初学汇编,其实是在准备考试?,还有很多不懂的地方,如有错误,希望多多指点,多包涵!)
正数-负数=负数
负数-正数=正数
JCC
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
函数调用栈
VA: 虚拟内存地址(Virtual Address)PE 文件被操作系统加载进内存后的地址。
RVA: PE文件的相对虚拟地址(Relative Virual Address)是PE文件中的数据、模块等运行在内存中的实际地址相对PE文件装载到内存的基址之间的距离。举例说明,如果PE文件装入虚拟地址(VA)空间的400000h处,且进程从虚址401000h开始执行,我们可以说进程执行起始地址在RVA 1000h。
FOA: 文件偏移地址(File Offset Address),和内存无关,它是指某个位置距离文件头的偏移。
FileBuffer和ImageBuffer的区别不在数据而在空白区
ImageBuffer就是将FileBuffer的空白区拉长
相对地址(相对PE起始位置imagebase) :
virtualAddress (内存偏移)
PointerToRawData(文件偏移)
硬编码:
6A 00 :push 0
call 要跳转的地址: E8 4字节数字 : E8+要跳转的地址-E8这条指令的下一行地址
jmp 要跳转的地址: E9 4字节数字 : E9 +要跳转的地址-E8这条指令的下一行地址
以上的所有地址都是内存地址;