栈溢出原理
Last updated
Last updated
关于栈的介绍,可以阅读 中的介绍。
下面给出一个典型例子,在这个例子中由于变量声明的顺序和 buffer 声明的大小导致存在最后一字节的溢出。
这是一个简单的密码校验程序,会判断输入的字符串是否和666666相等。使用 vc6.0 来编译这个程序,成功后使用 winchecksec 查看所开的防护。可以看到 GS 是开启的,但这并不妨碍我们的溢出。
使用 OllyDbg 动态调试这个程序,输入 aaaaaa 看一下程序正常的执行流程。为了方便理解整个过程,在 strcmp 函数和 strcpy 执行完后下一个断点。
现在可以让程序运行,输入 aaaaaa 后程序会执行到我们下的第一个断点。进入 strcmp 这个函数,观察它的返回值。因为 a 的 ascii 码值大于 6 的 ascii 码值,不出意外函数会返回 1 ,x86 下返回值保存在 EAX 寄存器中,函数正常返回后,由于程序完成它的其余功能还会使用这些寄存器,所以这个返回值会保存在栈上,也就是 ss:[0012FEA0] 这个地方。
当执行到第二个断点时,看一下栈结构。其中 61 是我们输入 a 的 ascii 码形式,00 是字符串结束符。那么 buffer 的大小是 8 字节,如果我们输入 8 个 a 的话,最后的字符串结束符会溢出到 0012FEA0 这个位置把原来的值覆盖为 0,这样我们就可以改变程序的执行流程,输出 Congratulation! You have passed the verification!
好,我们先让程序正常运行下去。
这次我们输入 8 个 a 验证一下是否如我们想的一样:字符串的结束符会溢出到 strcmp 的返回值。可以看到 strcmp 的返回值还是 1。
继续运行到第二个断点处,查看一下当前栈的值。**strcmp的返回值已经成功由 1 溢出为 0 **。
这时候让程序继续运行,成功的输出了预想的字符串。