首页
学习
活动
专区
圈层
工具
发布
30 篇文章
1
《coredump问题原理探究》Linux x86版6.4节虚函数
2
《coredump问题原理探究》Linux x86版7.3节List对象
3
《coredump问题原理探究》Linux x86版4.4节函数的逆向之循环结构
4
《coredump问题原理探究》windows版8.5节堆布局空闲堆块遍历
5
《coredump问题原理探究》windows版9.1节栈溢出
6
《coredump问题原理探究》Linux x86版3.2节栈布局之函数桢
7
《coredump问题原理探究》Linux x86版3.4节栈布局之函数参数
8
《coredump问题原理探究》Linux x86版4.1节函数的逆向之序言
9
《coredump问题原理探究》Linux x86版4.2节函数的逆向之顺序结构
10
《coredump问题原理探究》Linux x86版4.3节函数的逆向之条件结构
11
《coredump问题原理探究》windows版3.4节coredump例子
12
《coredump问题原理探究》windows版第四章函数的逆向
13
《coredump问题原理探究》windows版5.1节基本数据类型
14
《coredump问题原理探究》windows版5.2节数组
15
《coredump问题原理探究》windows版5.3节结构体
16
《coredump问题原理探究》windows版5.4节联合体
17
《coredump问题原理探究》windows版6.1节无成员变量的类
18
《coredump问题原理探究》windows版6.2节有成员变量的类
19
《coredump问题原理探究》windows版6.3节虚函数
20
《coredump问题原理探究》windows版6.4节单继承
21
《coredump问题原理探究》windows版6.5节多继承
22
《coredump问题原理探究》windows版7.1节vector
23
《coredump问题原理探究》windows版7.2节list
24
《coredump问题原理探究》windows版7.3节map
25
《coredump问题原理探究》windows版7.4节set
26
《coredump问题原理探究》windows版7.5节iterator
27
《coredump问题原理探究》windows版7.6节string
28
《coredump问题原理探究》windows版8.1节堆布局背景
29
《coredump问题原理探究》windows版8.2节堆布局堆块结构
30
《coredump问题原理探究》windows版3.1节函数桢

《coredump问题原理探究》Linux x86版4.3节函数的逆向之条件结构

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://cloud.tencent.com/developer/article/1344433

在x86里,条件跳转的指令有:

代码语言:javascript
复制
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两种,所以在例子会对两者都有探究。

先看一下例子:

代码语言:javascript
复制
 #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的汇编:

代码语言:javascript
复制
(gdb) disassemble cond_if
Dump 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.

代码语言:javascript
复制
   0x08048573 <+3>:     cmpl   $0x0,0x8(%ebp)
   0x08048577 <+7>:     jne    0x8048583 <_Z7cond_ifiii+19>

可知,这是判断cond_if的第一个参数a,是否等于0。如果不等于则跳转。那么,

代码语言:javascript
复制
   0x08048579 <+9>:     mov    0x10(%ebp),%eax
   0x0804857c <+12>:    mov    0xc(%ebp),%edx
   0x0804857f <+15>:    add    %edx,%eax

应该对应a等于0时要执行的语句,即

代码语言:javascript
复制
7	         return b + c;

代码语言:javascript
复制
   0x08048583 <+19>:    cmpl   $0x0,0x8(%ebp)
   0x08048587 <+23>:    jle    0x8048597 <_Z7cond_ifiii+39>

可知,这是判断a是否小于等于0,如果是则跳转。那么,

代码语言:javascript
复制
   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的语句,即

代码语言:javascript
复制
11	         return b - c;

同时由

代码语言:javascript
复制
   0x08048583 <+19>:    cmpl   $0x0,0x8(%ebp)
   0x08048587 <+23>:    jle    0x8048597 <_Z7cond_ifiii+39>

可知, 0x08048597开始的指令是对应a小于0的情况,即

代码语言:javascript
复制
   0x08048597 <+39>:    mov    0xc(%ebp),%eax
   0x0804859a <+42>:    imul   0x10(%ebp),%eax

对应于

代码语言:javascript
复制
15	         return b*c;

再看一下cond_switch的汇编:

代码语言:javascript
复制
(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.

代码语言:javascript
复制
   0x080485a6 <+6>:     test   %eax,%eax
   0x080485a8 <+8>:     je     0x80485b1 <_Z11cond_switchiii+17>

可知,0x080485b1到0x080485b9这一段代码是属于参数a为0的情况(eax的值是从8(%ebp)即a得来的),所以,

代码语言:javascript
复制
   0x080485b1 <+17>:    mov    0x10(%ebp),%eax
   0x080485b4 <+20>:    mov    0xc(%ebp),%edx
   0x080485b7 <+23>:    add    %edx,%eax

对应于

代码语言:javascript
复制
24	             return b + c;

代码语言:javascript
复制
   0x080485aa <+10>:    cmp   $0x1,%eax
   0x080485ad <+13>:    je    0x80485bb <_Z11cond_switchiii+27>

可知,0x080485bb到0x080485c7是对应于a为1的情况,所以,

代码语言:javascript
复制
   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

对应

代码语言:javascript
复制
26	             return b - c;

代码语言:javascript
复制
   0x080485c9 <+41>:    mov    0xc(%ebp),%eax
   0x080485cc <+44>:    imul   0x10(%ebp),%eax

是由

代码语言:javascript
复制
   0x080485af <+15>:    jmp    0x80485c9 <_Z11cond_switchiii+41>

跳转的,0x080485af是判断完a不为0,1之后才会执行的,所以这段汇编对应于

代码语言:javascript
复制
28	             return b*c;

从上面来看,通过对跳转语句进行分析,能够很快还原代码原先的逻辑,也很容易定位到哪一行代码。也可以看到,if…else if…else和switch实际上在汇编里是没什么区别。

下一篇
举报
领券