《coredump问题原理探究》Linux x86版4.3节函数的逆向之条件结构
来源:互联网 发布:美工专业培训 编辑:程序博客网 时间:2024/05/16 15:01
在x86里,条件跳转的指令有:
JMP:无条件跳转JAE/JNB:大于或等于跳转,用于无符号整数运算JA/JNBE:不小于或不等于跳转,用于无符号整数运算JB/JNAE:小于跳转,用于无符号整数运算JBE/JNA:小于或等于跳转,用于无符号整数运算JG/JNLE:大于跳转,用于有符号整数运算JGE/JNL:大于或等于跳转,用于有符号整数运算JL/JNGE :小于跳转,用于有符号整数运算JLE/JNG:小于或等于跳转,用于有符号整数运算JE/JZ:等于跳转JNE/JNZ:不等于跳转JC:有进位跳转JNC:无进位跳转JNO:不溢出跳转JNP/JPO:奇偶性为奇数跳转JNS:符号位为 "0"跳转JO:溢出跳转JP/JPE:奇偶性为偶数跳转JS:符号位为 "1" 跳转
上面这些指令,大多会检测EFLAGS寄存器相应的标志位来再决定是否跳转。而这些指令之前,往往会有一些设置这些标志位的指令。最常见的是cmp, test指令。那么,就可以根据上面指令快速构建条件结构的骨架。
下面通过例子来验证一下,由于在C/C++里,条件语句有if…elseif…else和switch两种,所以在例子会对两者都有探究。
先看一下例子:
#include <stdio.h> int cond_if( int a, int b, int c ) { if ( a == 0 ) { return b + c; } else if ( a > 0 ) { return b - c; } else { return b*c; } } int cond_switch( int a, int b, int c ) { switch( a ) { case 0: return b + c; case 1: return b - c; default: return b*c; } } int main() { int a = 0, b = 0, c = 0; scanf( "%d,%d,%d", &a, &b,&c ); return cond_if( a,b,c ) + cond_switch( a, b, c );}
先看一下cond_if的汇编:
(gdb) disassemble cond_ifDump of assembler code for function _Z7cond_ifiii: 0x08048570 <+0>: push %ebp 0x08048571 <+1>: mov %esp,%ebp 0x08048573 <+3>: cmpl $0x0,0x8(%ebp) 0x08048577 <+7>: jne 0x8048583 <_Z7cond_ifiii+19> 0x08048579 <+9>: mov 0x10(%ebp),%eax 0x0804857c <+12>: mov 0xc(%ebp),%edx 0x0804857f <+15>: add %edx,%eax 0x08048581 <+17>: jmp 0x804859e <_Z7cond_ifiii+46> 0x08048583 <+19>: cmpl $0x0,0x8(%ebp) 0x08048587 <+23>: jle 0x8048597 <_Z7cond_ifiii+39> 0x08048589 <+25>: mov 0x10(%ebp),%eax 0x0804858c <+28>: mov 0xc(%ebp),%edx 0x0804858f <+31>: mov %edx,%ecx 0x08048591 <+33>: sub %eax,%ecx 0x08048593 <+35>: mov %ecx,%eax 0x08048595 <+37>: jmp 0x804859e <_Z7cond_ifiii+46> 0x08048597 <+39>: mov 0xc(%ebp),%eax 0x0804859a <+42>: imul 0x10(%ebp),%eax 0x0804859e <+46>: pop %ebp 0x0804859f <+47>: ret End of assembler dump.
由
0x08048573 <+3>: cmpl $0x0,0x8(%ebp) 0x08048577 <+7>: jne 0x8048583 <_Z7cond_ifiii+19>
可知,这是判断cond_if的第一个参数a,是否等于0。如果不等于则跳转。那么,
0x08048579 <+9>: mov 0x10(%ebp),%eax 0x0804857c <+12>: mov 0xc(%ebp),%edx 0x0804857f <+15>: add %edx,%eax
应该对应a等于0时要执行的语句,即
7 return b + c;
由
0x08048583 <+19>: cmpl $0x0,0x8(%ebp) 0x08048587 <+23>: jle 0x8048597 <_Z7cond_ifiii+39>
可知,这是判断a是否小于等于0,如果是则跳转。那么,
0x08048589 <+25>: mov 0x10(%ebp),%eax 0x0804858c <+28>: mov 0xc(%ebp),%edx 0x0804858f <+31>: mov %edx,%ecx 0x08048591 <+33>: sub %eax,%ecx 0x08048593 <+35>: mov %ecx,%eax
应该对于a大于0的语句,即
11 return b - c;
同时由
0x08048583 <+19>: cmpl $0x0,0x8(%ebp) 0x08048587 <+23>: jle 0x8048597 <_Z7cond_ifiii+39>
可知, 0x08048597开始的指令是对应a小于0的情况,即
0x08048597 <+39>: mov 0xc(%ebp),%eax 0x0804859a <+42>: imul 0x10(%ebp),%eax
对应于
15 return b*c;
再看一下cond_switch的汇编:
(gdb) disassemble cond_switch Dump of assembler code for function _Z11cond_switchiii: 0x080485a0 <+0>: push %ebp 0x080485a1 <+1>: mov %esp,%ebp 0x080485a3 <+3>: mov 0x8(%ebp),%eax 0x080485a6 <+6>: test %eax,%eax 0x080485a8 <+8>: je 0x80485b1 <_Z11cond_switchiii+17> 0x080485aa <+10>: cmp $0x1,%eax 0x080485ad <+13>: je 0x80485bb <_Z11cond_switchiii+27> 0x080485af <+15>: jmp 0x80485c9 <_Z11cond_switchiii+41> 0x080485b1 <+17>: mov 0x10(%ebp),%eax 0x080485b4 <+20>: mov 0xc(%ebp),%edx 0x080485b7 <+23>: add %edx,%eax 0x080485b9 <+25>: jmp 0x80485d0 <_Z11cond_switchiii+48> 0x080485bb <+27>: mov 0x10(%ebp),%eax 0x080485be <+30>: mov 0xc(%ebp),%edx 0x080485c1 <+33>: mov %edx,%ecx 0x080485c3 <+35>: sub %eax,%ecx 0x080485c5 <+37>: mov %ecx,%eax 0x080485c7 <+39>: jmp 0x80485d0 <_Z11cond_switchiii+48> 0x080485c9 <+41>: mov 0xc(%ebp),%eax 0x080485cc <+44>: imul 0x10(%ebp),%eax 0x080485d0 <+48>: pop %ebp 0x080485d1 <+49>: ret End of assembler dump.
由
0x080485a6 <+6>: test %eax,%eax 0x080485a8 <+8>: je 0x80485b1 <_Z11cond_switchiii+17>
可知,0x080485b1到0x080485b9这一段代码是属于参数a为0的情况(eax的值是从8(%ebp)即a得来的),所以,
0x080485b1 <+17>: mov 0x10(%ebp),%eax 0x080485b4 <+20>: mov 0xc(%ebp),%edx 0x080485b7 <+23>: add %edx,%eax
对应于
24 return b + c;
由
0x080485aa <+10>: cmp $0x1,%eax 0x080485ad <+13>: je 0x80485bb <_Z11cond_switchiii+27>
可知,0x080485bb到0x080485c7是对应于a为1的情况,所以,
0x080485bb <+27>: mov 0x10(%ebp),%eax 0x080485be <+30>: mov 0xc(%ebp),%edx 0x080485c1 <+33>: mov %edx,%ecx 0x080485c3 <+35>: sub %eax,%ecx 0x080485c5 <+37>: mov %ecx,%eax
对应
26 return b - c;
而
0x080485c9 <+41>: mov 0xc(%ebp),%eax 0x080485cc <+44>: imul 0x10(%ebp),%eax
是由
0x080485af <+15>: jmp 0x80485c9 <_Z11cond_switchiii+41>
跳转的,0x080485af是判断完a不为0,1之后才会执行的,所以这段汇编对应于
28 return b*c;
从上面来看,通过对跳转语句进行分析,能够很快还原代码原先的逻辑,也很容易定位到哪一行代码。也可以看到,if…else if…else和switch实际上在汇编里是没什么区别。
- 《coredump问题原理探究》Linux x86版4.3节函数的逆向之条件结构
- 《coredump问题原理探究》Linux x86版4.2节函数的逆向之顺序结构
- 《coredump问题原理探究》Linux x86版4.4节函数的逆向之循环结构
- 《coredump问题原理探究》Linux x86版4.5节函数的逆向之coredump例子
- 《coredump问题原理探究》Linux x86版4.1节函数的逆向之序言
- 《coredump问题原理探究》Linux x86版6.5节虚函数的coredump例子
- 《coredump问题原理探究》Linux x86版3.2节栈布局之函数桢
- 《coredump问题原理探究》Linux x86版3.4节栈布局之函数参数
- 《coredump问题原理探究》Linux x86版3.4节栈布局之函数参数 .
- 《coredump问题原理探究》Linux x86版3.8节栈布局之栈溢出coredump例子
- 《coredump问题原理探究》Linux x86版6.3节有成员变量的类coredump例子
- 《coredump问题原理探究》Linux x86版5.7节C风格数据结构内存布局之结构体数组
- 《coredump问题原理探究》Linux x86版5.8节C风格数据结构内存布局之结构体数组结构体coredump
- 《coredump问题原理探究》Linux x86版5.5节C风格数据结构内存布局之基本数据类型构成的结构体
- 《coredump问题原理探究》Linux x86版5.6节C风格数据结构内存布局之复合类型构成的结构体
- 《coredump问题原理探究》Linux x86版6.4节虚函数
- 《coredump问题原理探究》Linux x86版3.1节栈布局之概述
- 《coredump问题原理探究》Linux x86版3.3节栈布局之局部变量
- 2012年终回顾:一期一会
- Objective-C中的协议使用举例
- IoMarkIrpPending
- 行为模式:State(状态)
- js
- 《coredump问题原理探究》Linux x86版4.3节函数的逆向之条件结构
- LS 2 Xor(数论)
- 判断括号是否匹配
- 行为模式:Iterator(迭代器)
- 行为模式: Template Method(模板方法)
- Android DOM解析XML
- 初识p-code (pcode)
- 我的2012:暴雨和企业政治
- 总结:使用IoMarkPending的原因及原理