当前位置: 代码迷 >> Linux/Unix >> 《coredump有关问题原理探究》Linux x86版4.4节函数的逆向之循环结构
  详细解决方案

《coredump有关问题原理探究》Linux x86版4.4节函数的逆向之循环结构

热度:4333   发布时间:2013-02-26 00:00:00.0
《coredump问题原理探究》Linux x86版4.4节函数的逆向之循环结构

在x86里,循环指令有:

LOOP:ECX不为零时循环LOOPE/LOOPZ:ECX不为零且标志Z=1时循环LOOPNE/LOOPNZ:ECX不为零且标志Z=0时循环

但实质上,由于上面指令适用范围太窄,只能用于循环体非常简单的。所以往往是用条件跳转指令来实际循环。用例子来体现一下:

 #include <stdio.h> int loop_for( int n ) {     int sum = 0;     for ( int i = 0; i < n; i++ )     {         sum += i;     }      return sum; }  int loop_while( int n ) {     int sum = 0;     int i = 0;      while ( i < n )     {         sum += i;         i++;     }      return sum; }  int loop_do( int n ) {     int sum = 0;     int i = 0;	      do     {         sum += i;         i++;     } while ( i < n );      return sum; }  int main() {     int n = 0;     scanf( "%d", &n );     return loop_for( n ) + loop_while( n )         + loop_do( n ); }

看一下loop_do,loop_for, loop_while的汇编:

(gdb) disassemble loop_doDump of assembler code for function _Z7loop_doi:   0x080485d4 <+0>:     push   %ebp   0x080485d5 <+1>:     mov    %esp,%ebp   0x080485d7 <+3>:     sub    $0x10,%esp   0x080485da <+6>:     movl   $0x0,-0x4(%ebp)   0x080485e1 <+13>:    movl   $0x0,-0x8(%ebp)   0x080485e8 <+20>:    mov    -0x8(%ebp),%eax   0x080485eb <+23>:    add    %eax,-0x4(%ebp)   0x080485ee <+26>:    addl   $0x1,-0x8(%ebp)   0x080485f2 <+30>:    mov    -0x8(%ebp),%eax   0x080485f5 <+33>:    cmp    0x8(%ebp),%eax   0x080485f8 <+36>:    setl   %al   0x080485fb <+39>:    test   %al,%al   0x080485fd <+41>:    jne    0x80485e8 <_Z7loop_doi+20>   0x080485ff <+43>:    mov    -0x4(%ebp),%eax   0x08048602 <+46>:    leave     0x08048603 <+47>:    ret    End of assembler dump.

(gdb) disassemble loop_forDump of assembler code for function _Z8loop_fori:   0x08048570 <+0>:     push   %ebp   0x08048571 <+1>:     mov    %esp,%ebp   0x08048573 <+3>:     sub    $0x10,%esp   0x08048576 <+6>:     movl   $0x0,-0x4(%ebp)   0x0804857d <+13>:    movl   $0x0,-0x8(%ebp)   0x08048584 <+20>:    jmp    0x8048590 <_Z8loop_fori+32>   0x08048586 <+22>:    mov    -0x8(%ebp),%eax   0x08048589 <+25>:    add    %eax,-0x4(%ebp)   0x0804858c <+28>:    addl   $0x1,-0x8(%ebp)   0x08048590 <+32>:    mov    -0x8(%ebp),%eax   0x08048593 <+35>:    cmp    0x8(%ebp),%eax   0x08048596 <+38>:    setl   %al   0x08048599 <+41>:    test   %al,%al   0x0804859b <+43>:    jne    0x8048586 <_Z8loop_fori+22>   0x0804859d <+45>:    mov    -0x4(%ebp),%eax   0x080485a0 <+48>:    leave     0x080485a1 <+49>:    ret    End of assembler dump.

(gdb) disassemble loop_whileDump of assembler code for function _Z10loop_whilei:   0x080485a2 <+0>:     push   %ebp   0x080485a3 <+1>:     mov    %esp,%ebp   0x080485a5 <+3>:     sub    $0x10,%esp   0x080485a8 <+6>:     movl   $0x0,-0x4(%ebp)   0x080485af <+13>:    movl   $0x0,-0x8(%ebp)   0x080485b6 <+20>:    jmp    0x80485c2 <_Z10loop_whilei+32>   0x080485b8 <+22>:    mov    -0x8(%ebp),%eax   0x080485bb <+25>:    add    %eax,-0x4(%ebp)   0x080485be <+28>:    addl   $0x1,-0x8(%ebp)   0x080485c2 <+32>:    mov    -0x8(%ebp),%eax   0x080485c5 <+35>:    cmp    0x8(%ebp),%eax   0x080485c8 <+38>:    setl   %al   0x080485cb <+41>:    test   %al,%al   0x080485cd <+43>:    jne    0x80485b8 <_Z10loop_whilei+22>   0x080485cf <+45>:    mov    -0x4(%ebp),%eax   0x080485d2 <+48>:    leave     0x080485d3 <+49>:    ret    End of assembler dump.

由于loop_for,loop_while的代码逻辑一样,连生成的汇编都是一样。loop_do和两者不大一样,所以,汇编不一样。现在只以loo_do进行分析:

(gdb) disassemble loop_doDump of assembler code for function _Z7loop_doi:   0x080485d4 <+0>:     push   %ebp   0x080485d5 <+1>:     mov    %esp,%ebp   0x080485d7 <+3>:     sub    $0x10,%esp   0x080485da <+6>:     movl   $0x0,-0x4(%ebp)   0x080485e1 <+13>:    movl   $0x0,-0x8(%ebp)   0x080485e8 <+20>:    mov    -0x8(%ebp),%eax   0x080485eb <+23>:    add    %eax,-0x4(%ebp)   0x080485ee <+26>:    addl   $0x1,-0x8(%ebp)   0x080485f2 <+30>:    mov    -0x8(%ebp),%eax   0x080485f5 <+33>:    cmp    0x8(%ebp),%eax   0x080485f8 <+36>:    setl   %al   0x080485fb <+39>:    test   %al,%al   0x080485fd <+41>:    jne    0x80485e8 <_Z7loop_doi+20>   0x080485ff <+43>:    mov    -0x4(%ebp),%eax   0x08048602 <+46>:    leave     0x08048603 <+47>:    ret    End of assembler dump.

由指令地址0x080485fd这一条指令可知,执行流程会回到0x080485e8,这个地址是比跳转指令地址更小,直到满足eax的值和ebp+8的内容相等才会停止。也就是说,从0x080485e8到0x080485fd就构成了一个循环。由于

   0x080485f5 <+33>:    cmp    0x8(%ebp),%eax

是用来设置标志位的,所以应该是对应于i < n子句

也就是说,

   0x080485e8 <+20>:    mov    -0x8(%ebp),%eax   0x080485eb <+23>:    add    %eax,-0x4(%ebp)   0x080485ee <+26>:    addl   $0x1,-0x8(%ebp)

对应于

36	         sum += i;37	         i++;

如果同样分析loop_for,loop_while也会发现,跳转指令是跳到比当前指令地址更小的地址来执行。

 

从这里可以看出,如果在分析函数的汇编时,遇到跳转指令,如果它并不是跳到比当前指令地址更大的地址执行,那么它有可能是一个循环,否则就是一个普通的条件跳转结构