1.栈溢出的利用
1.进程使用的内存都可以按功能大致分为以下4个部分:
(1)代码区:这个区域存储着被装入执行的二进制机器代码,处理器会到这个区域取指并执行。
(1)代码区:这个区域存储着被装入执行的二进制机器代码,处理器会到这个区域取指并执行。
(2)数据区:用于存储全局变量等。
(3)堆区:进程可以在堆区动态地请求一定大小的内存,并在用完之后还给堆区。动态分配和回收是堆区的特点。
(4)栈区:用于动态地存储函数之间的调用关系,以保证被调用函数在返回时恢复到母函数中继续执行。
2.Win32系统提供两个特殊的寄存器用于标识位于栈系统顶端的栈帧。
(1)ESP:栈指针寄存器,其内存放着一个指针,改指针永远指向系统栈最上面的一个栈帧的栈顶。
(2)EBP:基址指针寄存器,其内存放着一个指针,改指针永远指向系统栈最上面一个栈帧的底部。
(3)EIP:指令寄存器,其内存放着一个指针,该指针永远指向下一条等待执行的指令地址。
一个栈溢出利用实验
今天看了一个关于溢出的小实验,挺好玩的,于是自己也想玩玩,首先看看这个实验的源码。
![](https://images0.cnblogs.com/blog2015/762667/201505/290026027827164.png)
我们准备在password.txt文件中植入二进制的机器码,在password.txt攻击成功时,密码验证程序应该执行植入代码,并在桌面上弹出一个消息框显示“failwest”字样.
首先我们要完成的几项工作:
(1)分析并调试漏洞程序,获得淹没返回地址的偏移。
(2)获得buffer的起始地址,并将其写入password.txt的相应偏移处,用来冲刷返回地址。
(3)向password.txt中写入可执行的机器代码,用来调用API弹出一个消息框。
如果在password.txt中写入恰好44个字符,那么第45个隐藏截断符NULL将冲掉authenticated,低字节中的1,从而突破密码证的限制。
![](https://images0.cnblogs.com/blog2015/762667/201505/290022004692171.png)
![](https://images0.cnblogs.com/blog2015/762667/201505/290022371261970.png)
正如我们所料,authenticated被冲刷后,程序直接进入验证通过的分支。
![](https://images0.cnblogs.com/blog2015/762667/201505/290023250323505.png)
(1)buffer数组的起始地址位0x0018FB44
(2)password.txt文件中第53~56个字符的ASCLL码将写入栈帧的返回地址,成为函数返回后执行的指令地址。
用汇编语言调用MessageboxA需要3个步骤:
(1)装载动态链接库user32.dll。MessageBoxA是动态链接库user32.dll的倒出函数。
(2)在汇编语言中调用这个函数需要获得这个函数的入口地址。
(3)在调用前需要向栈中按从右向左的顺序压入MessageBoxA。
为了让植入的机器代码更加简洁明了,我们在实验准备中构造漏洞程序的时候已经人工加载了user32.dll这个库,多以可以不用考虑第一步。
MessageBoxA的入口参数可以通过user32.dll在系统中加载的基址和MessageBoxA在库中的偏移相加得到。(具体可以使用vc自带工具“Dependency Walker“获得这些信息)
好吧 ,我的vc没有这个功能,只有在OD中去找了。
入口地址=7599FD1E
将以下汇编代码一十六进制形式抄入password.txt。
![](https://images0.cnblogs.com/blog2015/762667/201505/310038307984795.png)
第53~56字节为buffer的起始地址,最后保存,当再次打开程序的时候
果然和我们预想的一样,出现了对话框,点击确定后程序就会崩溃。
![](https://images0.cnblogs.com/blog2015/762667/201505/290024071106993.png)
到此就全部结束了,最重要的地方就是MessageBoxA的地址和buffer的起始地址,并且buffer的起始地址要恰好覆盖掉第53~56个字符栈帧的返回地址。