缓冲区溢出入门

来源:互联网 发布:凤姐美国现状知乎 编辑:程序博客网 时间:2024/06/05 07:44

                              缓冲区溢出入门

从接触C语言的数组开始,就提到过缓冲区溢出问题。一般是往数组中写入数据长度超过了数组的大小,C语言常用的库函数strcpysprintfstrcat等都非常容易导致缓冲区溢出。还记得教科书告诉我们当程序溢出后会发生不可预料的后果,但是一些有意的缓冲区溢出利用可以让“不可预料的结果”变成我们所期望的结果。

先来个演示程序吧! buf.c

#include <stdio.h>

 

void fun()

{

   printf("why here!!!/n");

   exit(0);

}

int main(int argc, char *argv[])

{

   int a[1]={0};

   a[2]=(int)fun;

 

   return 0;

}

我用的是VC6的编译器在命令行下

C/K>cl /FA buf.c

运行程序;

why  here!!!

 

仔细分析程序发现我们并没有调用fun函数,但是函数确实被执行了,唯一可能的就是调用就是在a[2]=(int)fun;

要搞清楚是怎么回事,需要一些C语言的底层和汇编的知识,主要是关于堆栈和汇编的call/ret.类似上面程序中的int a[1]等局部变量是在堆栈中分配的,地址从高到低;而想malloc或者new动态申请分配的内存在堆中分配,地址才低到高。在汇编中call指令用来调用函数,并将call下面的指令的地址压入堆栈中,

也就是通常说的保存现场,在去执行调用的函数,当函数执行完以后,通过ret指令将压入堆栈的保存的地址返回给EIP寄存器,程序在根据EIP的内容继续执行。

         下面再来看看程序buf的汇编代码

在命令行输入type buf.asm

可见变量$SG336是我们定义的字符串”why here!!!”

这个是函数fun的定义

这是main()函数

通过对比main()fun()不难发现在函数开头都会有这么两句

通常称之为栈帧,EBP用来保存当前的栈基址,ESP为栈顶指针,在目前的系统中每当有数据入栈,ESP就减4,上面两句的意思就是保存当前BEP,并将BEP的内容传给ebp

而当函数执行完以后

则通过上面的方式回复EBP的值,ret将返回地址给EIP作为函数调用后的下一条指令的地址。

 

对应的源文件的 int a[1]={0};

此时堆栈中的结构大致如下:

a[0]  】【   ebp   】【  eip  】地址从右往左递减;

pop/push指令每次操作进出的是双字的大小,而整型数组每个元素的大小也为4个字节,刚好相等。

因为只定义了变量int a[1],编译器在堆栈上只为其分配了4个字节的空间,即指令push ecx;而越界的a[2]

的地址比a[0]8个字节,刚好位于堆栈中保存eip值的地址;

a[2]=(int)fun;

以上为源程序中覆盖eip值的语句及其对应的汇编代码,在c语言中函数名不是变量,a[2]=(int)fun

a[2]=(int)&fun的作用是一样的,就是将函数的起始地址赋值给a[2],也就是说main()执行完后,ret

返回的EIP中的值被替换成了fun()的起始地址,如前面所演示的fun函数就这样被执行了。

这只是一个简单的堆栈缓冲区溢出的利用,当然缓冲区溢出也可能发生在其他内存段中,例如堆和bss,

通过利用这些漏洞,一些不怀好意的人可以改变程序的控制流程,以完成其不可告人的目的!

 

 

 

 

                                                

原创粉丝点击