缓冲区溢出攻击原理分析

  • A+
所属分类:知识科普

缓冲区溢出攻击实践》以实践者角度介绍了初级缓冲区溢出攻击方法,本文从原理上对该方法做原理性介绍。


函数帧结构

现在高级语言C(或者C++),在函数开头的几指令要建立好函数帧结构,而函数返回时要撤消函数帧。当前在不同的CPU体系加构或者ABI标准,这些函数帧结构有一些差别,但原理上是相通的。


我们还是以之前的示例代码作为分析对象,讨论在fread函数填数据到buf变量前的栈结构。


下面是机器上对stack1程序 main函数反编译的结果:


 view plain copy

  1. (gdb) disassemble main  

  2. Dump of assembler code for function main:  

  3.    0x08048484 <+0>:     push   %ebp  

  4.    0x08048485 <+1>:     mov    %esp,%ebp  

  5.    0x08048487 <+3>:     and    $0xfffffff0,%esp  

  6.    0x0804848a <+6>:     sub    $0x40,%esp  

  7.    0x0804848d <+9>:     mov    $0x80485e0,%edx  

  8.    0x08048492 <+14>:    mov    $0x80485e2,%eax  

  9.    0x08048497 <+19>:    mov    %edx,0x4(%esp)  

  10.    0x0804849b <+23>:    mov    %eax,(%esp)  

  11.    0x0804849e <+26>:    call   0x80483c0 <fopen@plt>  

  12.    0x080484a3 <+31>:    mov    %eax,0x3c(%esp)  

  13.    0x080484a7 <+35>:    cmpl   $0x0,0x3c(%esp)  

  14.    0x080484ac <+40>:    jne    0x80484c1 <main+61>  

  15.    0x080484ae <+42>:    movl   $0x80485ea,(%esp)  

  16.    0x080484b5 <+49>:    call   0x8048380 <perror@plt>  

  17.    0x080484ba <+54>:    mov    $0x1,%eax  

  18.    0x080484bf <+59>:    jmp    0x80484ff <main+123>  

  19.    0x080484c1 <+61>:    lea    0x1c(%esp),%eax  

  20.    0x080484c5 <+65>:    mov    0x3c(%esp),%edx  

  21.    0x080484c9 <+69>:    mov    %edx,0xc(%esp)  

  22.    0x080484cd <+73>:    movl   $0x1,0x8(%esp)  

  23.    0x080484d5 <+81>:    movl   $0x400,0x4(%esp)  

  24.    0x080484dd <+89>:    mov    %eax,(%esp)  

  25.    0x080484e0 <+92>:    call   0x8048390 <fread@plt>  

  26.    0x080484e5 <+97>:    mov    $0x80485f0,%eax  

  27.    0x080484ea <+102>:   lea    0x1c(%esp),%edx  

  28.    0x080484ee <+106>:   mov    %edx,0x4(%esp)  

  29.    0x080484f2 <+110>:   mov    %eax,(%esp)  

  30.    0x080484f5 <+113>:   call   0x8048370 <printf@plt>  

  31.    0x080484fa <+118>:   mov    $0x0,%eax  

  32.    0x080484ff <+123>:   leave  

  33.    0x08048500 <+124>:   ret  

  34. End of assembler dump.  


在函数体里面最先执行的几条指令,通常称为function prologue,它完成建立函数帧的功能。


0x08048484 <+0>  push %ebp 

0x08048485 <+1>  mov %esp,%ebp 

0x08048487 <+3> and $0xfffffff0,%esp 

0x0804848a <+6>  sub $0x40,%esp

它的功能是:先将调用者的ebp压到栈上,然后将此时的esp作为被调用者的ebp(栈顶),然后根据函数局部变量的大小,将esp将压地址扩展,作为被调用者的esp(栈底);这样ebp和esp这对寄存器描述的栈空间就函数帧的空间。

在函数返回时,它总执行以下两条指令,通常称为function epilogue

0x080484ff <+123>   leave

0x08048500 <+124>   ret

它的功能是:先将当前函数的ebp赋给esp,然后再从栈中弹出(pop)调用者的ebp值到ebp寄存器,然后再从栈中弹出EIP值到pc寄存器。指令执行完后,ebp和esp就是父函数的函数帧。

示例程序的栈帧结构

根据上面stack1中main的反编译结果,画出如图1的栈结构:


缓冲区溢出攻击原理分析

图1: fread函数调用函数,栈帧结构图

这里重点关注一下buf变量在栈中的位置,当buf变量发生溢出时,就会往高地址空间覆盖。先是覆盖main函数的其它局部变量(图1没有画出来),然后是父函数的ebp,再次重点是eip,最后是父函数的栈空间。我们不关心覆盖父函数的栈空间,因为我们根本不打算返回父函数执行。

缓冲区溢出后栈内容

当前fread从bad.txt读取文件内容到buf缓冲区并发生溢出后,整个栈空间内容如图2所示:


缓冲区溢出攻击原理分析

图2:fread从bad.txt文件读取数据产生溢出后的栈数据

当函数返回时,ret指令将0xffffd710弹给pc寄存,就开始执行shellcode了。

小结

本文以示例程序为蓝本,分析程序的栈帧结构,以及攻击方法如何利用该结构控制EIP,改变程序执行流程,从而让程序掉到shellcode的坑里面。

FROM:http://blog.csdn.net/linyt/article/details/43315429

  • 我的微信
  • 这是我的微信扫一扫
  • weinxin
  • 我的微信公众号
  • 我的微信公众号扫一扫
  • weinxin

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: