栈溢出基本原理的简单讲解
(新手上路,大牛还请自行跳过,不足之处,欢迎批评指正)
一 、预备知识:
缓冲区溢出:简单的说,缓冲区溢出就是超长的数据向小缓冲区复制,导致数据超出了小缓冲区,导致缓冲区其他的数据遭到破坏,这就是缓冲区溢出。而栈溢出是缓冲区溢出的一种,也是最常见的。只不过栈溢出发生在栈,堆溢出发生在堆,其实都是一样的。
栈:栈是一种计算机系统中的数据结构,它按照先进后出的原则存储数据,先进入的数据被压入栈底,最后的数据在栈顶,需要读数据的时候从栈顶开始弹出数据(最后一个数据被第一个读出来),是一种特殊的线性表。栈的操作常用的有进栈(PUSH),出栈(POP),还有常用的标识栈顶和栈底。
可以把栈想象成一摞扑克牌一样,一张一张叠加起来。(如下图的a1,a2,……,an)。
进栈(PUSH):将一个数据放入栈里叫进栈(PUSH),相当于在扑克牌的在最上面放了一张新的扑克牌。
出栈(POP):将一个数据从栈里取出叫出栈(POP),相当于在扑克牌的在最上面拿走了一张扑克牌。
栈顶:常用寄存器ESP,ESP是栈指针寄存器,其内存放着一个指针,该指针永远指向系统栈最上面一个栈帧的栈顶。
栈底:常用寄存器EBP,EBP是基址指针寄存器,其内存放着一个指针,该指针永远指向系统栈最上面一个栈帧的底部。
二 、操作环境:
操作系统:Microsoft Windows XP Professional Service Pack 3
辅助工具:VC++ 6.0 、 OllyDbg
三 、 代码部分:
这个代码十分简单,先是定义了一本全局密码(PASSWORD:),如果用户输入的数字和密码相等显示:Success ! You are right !,否则显示:incorrect password !
值得注意的是,在 test 函数中开辟了一个8字节的局部数组空间,然后再将用户输入的数据复制到这个数组空间中,这就为栈溢出创造了条件,看下结果:
发现了一个有趣的结果,密码12345是正确的密码,这是我们自己定义的,但是当我输入“qqqqqqqq”时,显示的也是正确的结果,下面用OD进行进一步的分析。
四 、 代码分析:
将VC生成的exe放入OD:
OD暂停在了程序的入口点,但是值得我们注意的是,这个不是main函数的入口点,而是编译器预先处理函数的暂停之处,往下拉,进入真正函数开始的地方:
接着进入主函数:
往下走,输入“qqqqqq”,然后来到此处:
发现地址004010E0往后代码部分是进行判断由此推测函数TEST_1.0040100A就是我们的test函数,还需要记住这时的EBP寄存器值:0012FF80和函数下一条地址:004010E5,进入TEST_1.0040100A
然后向下单步,来到00401059处,它的上一步就是strcpy函数,也就是造成溢出的函数,此时观察EAX寄存器在堆栈图中的数据
其中0012FEC0地址处的数据71就是q的ASCII码表现形式,一共输入了6个q所以看到6个71,又因为代码部分是先将ret_num变量进行入栈,且作为strcmp函数的返回值,strcmp(C/C++函数,比较两个字符串,设这两个字符串为str1,str2,若str1==str2,则返回零;若str1
我们输入的qqqqqq不是正确的密码,所以大胆推测0012FEC8处的值就是ret_num,往下看0012FECC和0012FED0处储存的值了吗?就是要求大家注意的EBP和EIP(cpu将要执行的下一条指令地址),详细关于调用函数时候的堆栈入栈步骤还请大家自行查阅,叙述起来篇幅过长,此文只为简单讲解栈溢出的基本原理,所以不做过多说明。
刚刚是输入qqqqqq的情况,如果我们输入qqqqqqqqq试一下
发现0012FEC8处的值是71,这就证明了此处存在栈溢出漏洞,下面我们简单利用一下。
由上文可知,当ret_num的值为0的时候,此时程序就会判定我们输入的密码正确,还需知道,由于intel系统设计原因,其实就是内存中的数据按照4字节(DWORD)逆序存储,所以ret_num为1时,内存中存的是0x01000000,如果我们输入包含8个字符的错误密码,如“qqqqqqqq”,那么字符串截断符0x00将写入ret_num变量,这时溢出数组的一个字节0x00将恰好把逆序存放的ret_num变量改为0x00000000。
函数返回,main函数中一看ret_num是0,就会判断结果正确,下面我们看下输入qqqqqqqq情况的堆栈图
发现0012FEC8的值变为了0x00000000,此时判断正确
注意,如果我们的密码当初是定义为1234567时,当我们输入01234567的时候是不行的,虽说0123457也是8位数,但是01234567小于1234567,返回值是-1,在内存里将按照补码存负数,那么字符串截断后符0x00淹没后,变成0x00ffffff,还是非0,这样密码则错误!
六 、 总结:
这只是基本的栈溢出漏洞的讲解,对于新手扫盲还是很有帮助的,希望大家有所学习,日后有机会也会为大家带来更多关于二进制漏洞的讲解和利用方法。新手第一次写文,如若有误,欢迎大家的指正和教导,定虚心学习!不懂之处,也希望大胆询问交流,创造浓郁和谐的学习氛围,再见!