首页
学习
活动
专区
圈层
工具
发布
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.2节函数的逆向之顺序结构

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

先看一下例子:

代码语言:javascript
复制
#include <stdio.h>

int main()
{
     int a = 0, b = 0, c = 0, d = 0;
     scanf( "%d,%d", &a,&b );
     a += b;
     scanf( "%d", &c );
     a += c;
     scanf( "%d", &d );
     a += d;
 
     return a;
}

看一下main函数的汇编:

代码语言:javascript
复制
(gdb) disassemble main
Dump of assembler code for function main:
   0x08048570 <+0>:     push   %ebp
   0x08048571 <+1>:     mov    %esp,%ebp
   0x08048573 <+3>:     and    $0xfffffff0,%esp
   0x08048576 <+6>:     sub    $0x20,%esp
   0x08048579 <+9>:     movl   $0x0,0x1c(%esp)
   0x08048581 <+17>:    movl   $0x0,0x18(%esp)
   0x08048589 <+25>:    movl   $0x0,0x14(%esp)
   0x08048591 <+33>:    movl   $0x0,0x10(%esp)
   0x08048599 <+41>:    lea    0x18(%esp),%eax
   0x0804859d <+45>:    mov    %eax,0x8(%esp)
   0x080485a1 <+49>:    lea    0x1c(%esp),%eax
   0x080485a5 <+53>:    mov    %eax,0x4(%esp)
   0x080485a9 <+57>:    movl   $0x80486b4,(%esp)
   0x080485b0 <+64>:    call   0x8048440 <scanf@plt>
   0x080485b5 <+69>:    mov    0x1c(%esp),%edx
   0x080485b9 <+73>:    mov    0x18(%esp),%eax
   0x080485bd <+77>:    add    %edx,%eax
   0x080485bf <+79>:    mov    %eax,0x1c(%esp)
   0x080485c3 <+83>:    lea    0x14(%esp),%eax
   0x080485c7 <+87>:    mov    %eax,0x4(%esp)
   0x080485cb <+91>:    movl   $0x80486ba,(%esp)
   0x080485d2 <+98>:    call   0x8048440 <scanf@plt>
   0x080485d7 <+103>:   mov    0x1c(%esp),%edx
   0x080485db <+107>:   mov    0x14(%esp),%eax
   0x080485df <+111>:   add    %edx,%eax
   0x080485e1 <+113>:   mov    %eax,0x1c(%esp)
   0x080485e5 <+117>:   lea    0x10(%esp),%eax
   0x080485e9 <+121>:   mov    %eax,0x4(%esp)
   0x080485ed <+125>:   movl   $0x80486ba,(%esp)
   0x080485f4 <+132>:   call   0x8048440 <scanf@plt>
   0x080485f9 <+137>:   mov    0x1c(%esp),%edx
   0x080485fd <+141>:   mov    0x10(%esp),%eax
   0x08048601 <+145>:   add    %edx,%eax
   0x08048603 <+147>:   mov    %eax,0x1c(%esp)
   0x08048607 <+151>:   mov    0x1c(%esp),%eax
   0x0804860b <+155>:   jmp    0x8048615 <main+165>
   0x0804860d <+157>:   mov    %eax,(%esp)
   0x08048610 <+160>:   call   0x8048460 <_Unwind_Resume@plt>
   0x08048615 <+165>:   leave  
   0x08048616 <+166>:   ret    
End of assembler dump.

区区十来行代码,就变成了非常多的汇编语句,非常令人害怕。实际上,不需要那么害怕。

先看一下call指令的地方,由于call指令是调用函数的,所以,用它可以大致定一下这样的范围。

先看一下三个call指令的地址:

代码语言:javascript
复制
   0x080485b0 <+64>:    call   0x8048440 <scanf@plt>
   0x080485d2 <+98>:    call   0x8048440 <scanf@plt>
   0x080485f4 <+132>:   call   0x8048440 <scanf@plt>

可以知道,

代码语言:javascript
复制
   0x08048570 <+0>:     push   %ebp
   0x08048571 <+1>:     mov    %esp,%ebp
   0x08048573 <+3>:     and    $0xfffffff0,%esp
   0x08048576 <+6>:     sub    $0x20,%esp
   0x08048579 <+9>:     movl   $0x0,0x1c(%esp)
   0x08048581 <+17>:    movl   $0x0,0x18(%esp)
   0x08048589 <+25>:    movl   $0x0,0x14(%esp)
   0x08048591 <+33>:    movl   $0x0,0x10(%esp)
   0x08048599 <+41>:    lea    0x18(%esp),%eax
   0x0804859d <+45>:    mov    %eax,0x8(%esp)
   0x080485a1 <+49>:    lea    0x1c(%esp),%eax
   0x080485a5 <+53>:    mov    %eax,0x4(%esp)
   0x080485a9 <+57>:    movl   $0x80486b4,(%esp)

这一段汇编的地址少于第一个call指令地址0x080485b0,所以,它们大概对应于代码:

代码语言:javascript
复制
int a = 0, b = 0, c = 0, d = 0;

代码语言:javascript
复制
   0x080485b5 <+69>:    mov    0x1c(%esp),%edx
   0x080485b9 <+73>:    mov    0x18(%esp),%eax
   0x080485bd <+77>:    add    %edx,%eax
   0x080485bf <+79>:    mov    %eax,0x1c(%esp)
   0x080485c3 <+83>:    lea    0x14(%esp),%eax
   0x080485c7 <+87>:    mov    %eax,0x4(%esp)
   0x080485cb <+91>:    movl   $0x80486ba,(%esp)

这一段汇编由于地址大于0x080485b0,小于0x080485d2,所以,它们大致对应于代码:

代码语言:javascript
复制
a += b;

代码语言:javascript
复制
   0x080485d7 <+103>:   mov    0x1c(%esp),%edx
   0x080485db <+107>:   mov    0x14(%esp),%eax
   0x080485df <+111>:   add    %edx,%eax
   0x080485e1 <+113>:   mov    %eax,0x1c(%esp)
   0x080485e5 <+117>:   lea    0x10(%esp),%eax
   0x080485e9 <+121>:   mov    %eax,0x4(%esp)
   0x080485ed <+125>:   movl   $0x80486ba,(%esp)

这一段汇编地址大于0x080485d2,小于0x080485f4,所以,它们大致对应于代码:

代码语言:javascript
复制
a += c;

代码语言:javascript
复制
   0x080485f9 <+137>:   mov    0x1c(%esp),%edx
   0x080485fd <+141>:   mov    0x10(%esp),%eax
   0x08048601 <+145>:   add    %edx,%eax
   0x08048603 <+147>:   mov    %eax,0x1c(%esp)
   0x08048607 <+151>:   mov    0x1c(%esp),%eax
   0x0804860b <+155>:   jmp    0x8048615 <main+165>
   0x0804860d <+157>:   mov    %eax,(%esp)
   0x08048610 <+160>:   call   0x8048460 <_Unwind_Resume@plt>
   0x08048615 <+165>:   leave  
   0x08048616 <+166>:   ret    

这一段汇编地址大于0x080485f4,所以,它们对应于代码:

代码语言:javascript
复制
a += d;

return a;

看,分析汇编,并不是那么让人恐怖。但上面由于有一些指令是编译器生成的,有一些是函数调用时把参数入栈的指令,所以,要筛选出这些指令,仅以第一段汇编为例(即第一个scanf调用前的汇编):

代码语言:javascript
复制
   0x08048570 <+0>:     push   %ebp
   0x08048571 <+1>:     mov    %esp,%ebp
   0x08048573 <+3>:     and    $0xfffffff0,%esp
   0x08048576 <+6>:     sub    $0x20,%esp
   0x08048579 <+9>:     movl   $0x0,0x1c(%esp)
   0x08048581 <+17>:    movl   $0x0,0x18(%esp)
   0x08048589 <+25>:    movl   $0x0,0x14(%esp)
   0x08048591 <+33>:    movl   $0x0,0x10(%esp)
   0x08048599 <+41>:    lea    0x18(%esp),%eax
   0x0804859d <+45>:    mov    %eax,0x8(%esp)
   0x080485a1 <+49>:    lea    0x1c(%esp),%eax
   0x080485a5 <+53>:    mov    %eax,0x4(%esp)
   0x080485a9 <+57>:    movl   $0x80486b4,(%esp)

由第三章可知,

代码语言:javascript
复制
   0x08048570 <+0>:     push   %ebp
   0x08048571 <+1>:     mov    %esp,%ebp

是属于函数开头的特征指令,所以,这是由编译器自动生成的。

代码语言:javascript
复制
   0x08048573 <+3>:     and    $0xfffffff0,%esp
   0x08048576 <+6>:     sub    $0x20,%esp

则是用来调整esp和分配局部变量空间的,也是编译器自动生成的。所以,第一段汇编只剩下

代码语言:javascript
复制
   0x08048579 <+9>:     movl   $0x0,0x1c(%esp)
   0x08048581 <+17>:    movl   $0x0,0x18(%esp)
   0x08048589 <+25>:    movl   $0x0,0x14(%esp)
   0x08048591 <+33>:    movl   $0x0,0x10(%esp)
   0x08048599 <+41>:    lea    0x18(%esp),%eax
   0x0804859d <+45>:    mov    %eax,0x8(%esp)
   0x080485a1 <+49>:    lea    0x1c(%esp),%eax
   0x080485a5 <+53>:    mov    %eax,0x4(%esp)
   0x080485a9 <+57>:    movl   $0x80486b4,(%esp)

是和

代码语言:javascript
复制
 int a = 0, b = 0, c = 0, d = 0;

对应。由于

代码语言:javascript
复制
scanf( "%d,%d", &a,&b );

是有三个参数,根据第三章内容,

代码语言:javascript
复制
   0x08048599 <+41>:    lea    0x18(%esp),%eax
   0x0804859d <+45>:    mov    %eax,0x8(%esp)
   0x080485a1 <+49>:    lea    0x1c(%esp),%eax
   0x080485a5 <+53>:    mov    %eax,0x4(%esp)
   0x080485a9 <+57>:    movl   $0x80486b4,(%esp)

刚好是把scanf的三个参数入栈的操作,可以通过运行时得到0x80486b4指向的内容:

代码语言:javascript
复制
gdb) tbreak *0x080485b0
Temporary breakpoint 1 at 0x80485b0
(gdb) r
Starting program: /home/buckxu/work/4/1/xuzhina_dump_c4_s1 

Temporary breakpoint 1, 0x080485b0 in main ()
(gdb) x /s 0x80486b4
0x80486b4 <__dso_handle+4>:      "%d,%d"

也就是说,只有

代码语言:javascript
复制
   0x08048579 <+9>:     movl   $0x0,0x1c(%esp)
   0x08048581 <+17>:    movl   $0x0,0x18(%esp)
   0x08048589 <+25>:    movl   $0x0,0x14(%esp)
   0x08048591 <+33>:    movl   $0x0,0x10(%esp)

才是和

代码语言:javascript
复制
int a = 0, b = 0, c = 0, d = 0;

对应的。

小结:

由于顺序结构的逆向非常考验汇编基础,但如果是有函数调用的话,先找call指令,根据call指令来划分范围,筛选出编译器自动生成的指令。

下一篇
举报
领券