堆栈溢出技术从入门到精通
堆栈溢出技术从入门到精通 本讲的预备知识: 一方面你应当了解intel汇编语言,熟悉寄存器的组成和功能。你必须有堆栈和存储分派方面 的基础知识,有关这方面的计算机书籍很多,我将只是简朴阐述原理,着重在应用。另一方面, 你应当了解linux,本讲中我们的例子将在linux上开发。 1:一方面复习一下基础知识。 从物理上讲,堆栈是就是一段连续分派的内存空间。在一个程序中,会声明各种变量。静态 全局变量是位于数据段并且在程序开始运营的时候被加载。而程序的动态的局部变量则分派 在堆栈里面。 从操作上来讲,堆栈是一个先入后出的队列。他的生长方向与内存的生长方向正好相反。我 们规定内存的生长方向为向上,则栈的生长方向为向下。压栈的操作push=ESP-4,出栈的 操作是pop=ESP+4.换句话说,堆栈中老的值,其内存地址,反而比新的值要大。 请牢牢记住这一点,由于这是堆栈溢出的基本理论依据。 在一次函数调用中,堆栈中将被依次压入:参数,返回地址,EBP。假如函数有局部变量, 接下来,就在堆栈中开辟相应的空间以构造变量。函数执行结束,这些局部变量的内容将被 丢失。但是不被清除。在函数返回的时候,弹出EBP,恢复堆栈到函数调用的地址,弹出返回 地址到EIP以继续执行程序。 在C语言程序中,参数的压栈顺序是反向的。比如func(a,b,c)。在参数入栈的时候,是: 先压c,再压b,最后a.在取参数的时候,由于栈的先入后出,先取栈顶的a,再取b,最后取c。 (PS:假如你看不懂上面这段概述,请你去看以看关于堆栈的书籍,一般的汇编语言书籍都 会具体的讨论堆栈,必须弄懂它,你才干进行下面的学习) 2:好了,继续,让我们来看一看什么是堆栈溢出。 2.1:运营时的堆栈分派 堆栈溢出就是不顾堆栈中分派的局部数据块大小,向该数据块写入了过多的数据,导致数据 越界。结果覆盖了老的堆栈数据。 比如有下面一段程序: 程序一: #include int main ( ) { char name[8]; printf(“Please type your name: “); gets(name); printf(“Hello, %s!“, name); return 0; } 编译并且执行,我们输入ipxodi,就会输出Hello,ipxodi!。程序运营中,堆栈是怎么操作的呢? 在main函数开始运营的时候,堆栈里面将被依次放入返回地址,EBP。 我们用gcc -S 来获得汇编语言输出,可以看到main函数的开头部分相应如下语句: pushl %ebp movl %esp,%ebp subl $8,%esp 一方面他把EBP保存下来,,然后EBP等于现在的ESP,这样EBP就可以用来访问本函数的 局部变量。之后ESP减8,就是堆栈向上增长8个字节,用来存放name[]数组。现在堆栈 的布局如下: 内存底部 内存顶部 name EBP ret <------ [ ][ ][ ] ^ name[0] = “/bin/sh“ name[1] = NULL; cve(name[0], name, NULL); } ------------------------------------------------------------------------ ------ cve函数将执行一个程序。他需要程序的名字地址作为第一个参数。一个内容为 该程序的argv[i](argv[n-1]=0)的指针数组作为第二个参数,以及(char*) 0作为 第三个参数。 我们来看以看cve的汇编代码: [nkl10]$Content$nbsp;gcc -o shellcode -