利用基于帧栈的缓冲区溢出执行任意代码

来源:互联网 发布:java 多态 有什么作用 编辑:程序博客网 时间:2024/05/16 09:49
本人小菜,最近学了点缓冲区溢出,有点小收获,特把自己的心得体会写成日志,希望老鸟们不要见笑,如果有什么建议或意见,欢迎发表,共同学习。呵呵~~~~

要理解什么是缓冲区以及如何利用缓冲区溢出执行任意代码,需要有以下2个方面的知识:

1、知道什么是缓冲区

2、知道汇编级别的函数调用过程以及相应的堆栈变化

下面我会慢慢详细地介绍这两方面的知识。

问:什么是缓冲区?

答:缓冲区就是程序员开辟的一块内存空间,用于存放数据,一般这样的缓冲区是临时的,除非你定义的是全局缓冲区,不过全局缓冲区不是我今天要讨论的对象。比如下面的代码将在内存中开辟一块200*4字节的缓冲区:

char buffer[200];

问:汇编级别的函数调用过程以及相应的堆栈变化?

答:函数调用在程序中非常频繁,理解函数调用过程对理解缓冲区溢出很重要。每个线程都有一个私有的线程堆栈,它和函数调用密切相关。在汇编层次,函数调用大多使用call address这条指令,这条指令的执行过程是这样的:首先将函数参数依照调用约定依次压入线程栈中,接着将call address的下一条指令地址压入线程栈中(也就是函数的返回地址压入栈,当函数调用完毕,会返回到这个地址上),最后是改变CS和IP,将他们指向被调用函数的首地址,从被调用函数首地址开始运行代码直到该函数执行结束。最后将函数返回地址弹出栈,回到call address的下一条指令,当然还要平衡堆栈,这取决于调用约定是怎么约定的。到此,整个函数调用结束。在进入被调用函数中但还没有执行代码时,线程栈的结构如下图所示。

 

注:图中EBP的值究竟是什么跟本文讨论的话题无关,也不影响结果,读者在此不必深究,如果感兴趣,可以参看相关书籍。

所有在函数内部定义的变量,只要不是用new开辟空间,一定是在栈上开辟空间的,也就是说局部变量的缓冲区将位于栈上,如下图所示。

 

我们知道,C函数scanf是不会自行检查缓冲区边界的,如果程序员没有手动进行缓冲区边界检查并且用户输入的数据的长度超过了缓冲区大小的话,输入的数据将溢出缓冲区,覆盖缓冲区后面的数据,也就是说将覆盖返回地址,参数1,参数2,等。不难想象这将会发生什么后果,如果输入的数据是用户精心设计过的,它覆盖了函数的返回地址,当函数返回时将返回到用户指定的地址继续执行代码,呵呵~~~继续执行什么代码呢?尽情发挥你的想象吧。。。。。。

这就是缓冲区溢出执行任意代码的原理

原创粉丝点击