栈溢出笔记1.2 覆盖EIP

来源:互联网 发布:js中的大于等于 编辑:程序博客网 时间:2024/06/10 18:26

1.1节中我们说到可以利用栈溢出来破坏栈中原有的内容,这一节中,我们就来看看如何争夺到返回地址(EIP),使得我们可以随意控制它的值,这样我们就可以控制程序。来看一个经典的程序:

这里写图片描述

这个程序的get_print函数中定义了一个大小为11个字节的数组,正常情况下我们的输入应该最多为10个字符(还有一个\0结束符),而gets函数没有明确定义输入的大小,因此,我们可以输入超过10个字符,从而造成栈溢出。如下,输入10个‘A’,一切正常:
这里写图片描述
图8
当我输入11个‘A’时,虽然顺利打印出来11个‘A’,但是VS2008报了如下错:
这里写图片描述
图9

运行时错误检查检测到栈崩溃,这是Windows为抵抗栈溢出漏洞利用采用的措施。目前我们还不知道如何绕过,先去掉它,在工程属性中,“C/C++”——“代码生成”的“基本运行时检查”选择为默认值,然后重新编译。
这里写图片描述
图10

修改后,输入11个‘A’貌似是没什么问题了,但是输入12个‘A’的时候,又出来一个这样的对话框:
这里写图片描述
图11

缓冲区溢出被检查到了,这当然不是一个好消息。作为经典的漏洞,Windows自然有多种对付招式,这又是一种叫做栈Cookie的保护方式,可以检查到栈溢出。同样,先去掉它,在工程属性中,“C/C++”——“代码生成”的“缓冲区安全检查”选择为否(GS-, 见图10),然后重新编译。这一次,我们输入一大串‘A’:

这里写图片描述
图12

什么?VS2008又出现了弹窗?别紧张,这次是好消息。
这里写图片描述
图13

看到熟悉的0xC0000005,表明是访问了不该访问的地址。同时,0x41414141不就是“AAAA”吗?这说明我们输入的“AAAA”已经以某种方式被程序使用了,这果断是好消息。

下面,用Immunity Debugger来看看究竟发生了什么。先找到函数get_print()的代码,在 MOV EBP, ESP语句上下断点:

这里写图片描述
图14

然后运行到这里,查看栈内容:
这里写图片描述
图15

回想1.1中的内容,get_print没有参数,因此0012FF14(当前ESP)处为保存的EBP,0012FF18(EBP+4)为返回地址(重要)。

下面两句分配栈帧的代码对栈的影响较大:

/*********************************************************/MOV EBP, ESPSUB ESP, 4C/*********************************************************/

分配了4C(76字节)大小的空间,因此,下面这段栈空间(get_print)是我们关注的内容:
这里写图片描述
图16

现在,定位到gets函数,我们关注的不是它的调用过程,而是参数,它位于栈上EBP-C的位置,因此,它紧邻保存的EBP。也就是说,这个缓冲区下面是保存的EBP,再下面是保存的返回地址。这很重要,它决定我们需要输入多少内容才能准确地改写保存的返回地址(EIP)。

我们在gets函数之后设断点,并输入以下内容(16个A和4个B):

这里写图片描述
图17

此时,查看栈内容:
这里写图片描述
图18

看到了吗?保存的EBP被‘AAAA’覆盖,保存的返回地址(EBP+4)被BBBB覆盖。因为,我们知道局部变量的准确位置,因此,可以准确的知道需要多少字节来覆盖返回地址的内容。
这样,我们就从程序手中争夺了EIP,get_print()返回时,它将跳转到0x42424242处执行,由于该地址不可访问,因此会出现0xC0000005错误。后面,我们将给EIP写入有意义的地址,从而执行我们自己的内容。

0 0
原创粉丝点击