1. 做该实验,务必已经看完了深入理解计算机系统的第三章节。了解常见c语言结构对应的汇编代码的常见形式。
2. 同时,请务必去卡梅隆大学课程官网,查看说明文件。下载gdb,一般ubuntu自带了。然后,去网上搜索,常见的gdb调试命令。下面是我当时参考的。感谢他们:
https://blog.csdn.net/liigo/article/details/582231/
http://wdxtub.com/2016/04/16/thick-csapp-lab-2/
3. 下载到官方的文件后,tar -xvf解压,然后就可以看到一个可执行文件bomb
4. 弄完上述三个步骤后,直接gdb ./bomb命令打开gdb调试,并且载入文件。
5. 二话不说直接上来先不用管其他,我们先理清楚main函数的架构。看我们需要到哪里去获取密码。
使用b main设置断点。然后使用run命令运行程序。使用disas命令查看汇编att格式的代码。
其实我们查看下主函数的进程就会发现:
main下:依次是
fopen(库函数)
initialize_bomb
printf(库函数)
read_line
explode_bomb(这个就是引爆的函数,其实就是输入函数。)
跟着的就是phase_1-6六个炸弹了。
补充知识:
1. 在书上,我们学习了汇编代码执行时的栈,它生长方向是地址减少的方向。对于一个函数而言,就是返回地址,被保存的寄存器变量,该函数的局部变量,下一个函数的参数构造区,下一个函数的返回地址。这样一层层的向下嵌套。
2.在书上,我们学习的是,有时候时当参数比较少的时候,是寄存器直接传参,但是在该实验中,不知道是怎么回事(可能时便于我们看懂),参数都是通过栈传递的。所以,你可以经常看到,call之前,常常是一系列的push命令。
3.同时,我们需要多关注下%ebp寄存器,我们发现一个函数进去不远,就是一条mov %exp, %ebp,然后开始分配新的内存空间,然后通过mov 0x8(%ebp), %eax来把该函数的传入实参,从堆栈中取出,赋值给寄存器,这种模式,我们必须熟悉。相当于,ebp是是该函数在运行时栈中,该函数数据区域的开头部分,往前是该函数的传入参数,被保存的寄存器变量,下面新建立的局部变量等。
下面我们正式开始拆弹吧。
-----------------------------------------分割线-------------------------------------
1. 使用b phase_1命令,设置断电运行。直接看phase_1的汇编代码,就可以看到一个strings_equal这样的函数,我们使用gdb调试工具,直接查看该函数的两个输入参数即可,其中一种是我们的输入参数。
箭头上面两个push,就是strings_not_equal函数的两个传入实参,eax是我们自己键入的字符串,另外一个就是我们想要的密码,
答案为:Public speaking is very easy.(注意这里有个句号)
-----------------------------------------分割线-------------------------------------
2.查看phase_2的汇编源码,就可以看到一个read_six_num的函数,这相当于给了提示,说明读取的六个数字,然后我们就能看到一个典型的循环程序,一步步的阅读理解相关寄存器和条件判断语句,我们可以发现,这循环结构(+24到+68)对六个数字,执行a[i] == i * a[i – 1]这样的判断条件,任何一个出错就是爆炸,其中第一个参数一定为1;补充提示:(-18(%ebp) 就是第一个数字,然后把这个首地址给了%esi,然后执行上述判断,%ebx就是i)
因此答案为1 2 6 24 120 720
-----------------------------------------分割线-------------------------------------3.依然断电查看phase_3的汇编代码,我可以看到一大堆的爆照函数,吓人啊,不过不要慌张,我们先看看该函数前面一部分
我可以看到它调用库函数ss