
信息 = 位 + 上下文
CSAPP的开篇就明确地强调了这一点,而这次的缓冲区溢出的实验将这句话发挥到了极致。(实验文件见这里)
举个例子:菜刀可以用来切菜,也可以用来砍人。对于厨师菜刀就是切菜工具,对于罪犯就是杀人工具。这里的菜刀就是位,菜刀还是那把菜刀,但上下文(厨师、罪犯)不同了,那么信息(切菜、砍人)也就不同了。断章取义的理解一样事物必然不能看到全貌。
那么放在计算机里的解释就是:一坨01的数据,你可以把它解释成整型、浮点、字符、指令、寄存器。数据还是那些数据,就看你的上下文(解释器、解释方法、组织方法)了,不同的解释结果是南辕北辙的。
===============level 0=============
知识点:rtn addr

要想理解栈的机制,这张图是关键。可以看到Frame Pointer(%ebp)中存的是上层函数的%ebp,而其上方就是return address,即当前函数返回到上层函数的地址。这个也就解这题的关键了,也是缓冲区溢出攻击的基石。return address就像是盗梦空间的n层和n+1层的入口,万一没改好就迷失在意识边缘了。
题目简要描述如下:
首先主程序会调用test函数
另外有一个smoke函数
此函数一般情况是不会调用的,但如何去让test调用它就是要解决的问题。有了rtn addr在栈中的组织方式就能很容易的想到把smoke的地址放到getbuf的返回地址中就能调用smoke了。
通过反汇编,然后查看getbuf的代码,注意到这段:
可以看到lea把buf的指针地址(-0x18(%ebp))传给了Gets(),也就是buf距离rtn addr有0x18 + 4(%ebp的字节数)=0x1c(28)个字节的距离,于是只要在buf开始处随便填入28字节,并在rtn addr中填入smoke的地址就行了。
代码如下(相邻两个空格隔开一个字节,括号中为注释,为方便便阅读进行了换行):
最后可以画出这样一个栈图:

从图中可以看到buf溢出到了rtn addr保存的地址,并改写为smoke()的地址。于是乎,getbuf()返回时就运行到了smoke()处。

===============level 1=============
知识点:函数的参数
Level1在level0的基础上需要给一个fizz的函数传参数,以此能让其运行if (val == cookie)分支。
这里先把cookie变量中的值给找出来,这个用gdb就行了,问题在于val的值怎么给它传进去。其实,仔细想想也不难,根据函数在栈中的调用方式,第一个参数不就在0x8(%ebp)嘛,那0x8(%ebp)在哪呢?查看fizz的反汇编可以看到函数一般在最开始这样做:
也就是说,%ebp是什么不重要,重要的是%esp是什么。回想一下getbuf()返回时做了什么很有好处。它把rtn addr弹出来了,那么最后%esp就成了rtn addr所在内存的上一个地址。而当push %ebp时,%esp又压入一个,于是它又变成了rtn addr所在的地址。那么0x8(%ebp)就是rtn addr所在内存的上两个地址。得到如下的stack图:
代码应该很容易写出了。
===============level 2=============
计算机是什么?计算机就是一坨线。
Level2要求test运行后能调用bang函数,并在bang中运行if(global_value ==cookie)分支。
bang函数:
这里的关键是要把global_value设置成cookie才行。可问题是单凭一个缓冲区怎么来设置一个全局变量。这就是信息=位+上下文的本质了,命令可以是数据,数据也可以是命令,一切就看你如何去解释了。栈里存的不一定是数据,也可以是命令。那么rtn addr返回的地址就是你输入到栈里的命令开始处,于是你看到了另一个世界,原来程序还可以这样运行。
本文来自电脑杂谈,转载请注明本文网址:
http://www.pc-fly.com/a/jisuanjixue/article-30833-1.html
自已弄点水果榨汁加点酒精加点水加点糖就好了