目录
写在前面:
上交的实验报告需要包含账户的姓名全拼以及学号,本报告的相应部分已经打码处理,请在自己的环境中完成实验!
一、 实验目的:
1. 理解程序(控制语句、函数、返回值、堆栈结构)是如何运行的
2. 掌握GDB调试工具和objdump反汇编工具
二、实验环境:
1. 计算机(Intel CPU)
2. Linux64位操作系统(Ubuntu 17)
3. GDB调试工具
4. objdump反汇编工具
三、实验方法与步骤:
本实验设计为一个黑客拆解二进制炸弹的游戏。我们仅给黑客(同学)提供一个二进制可执行文件bomb_64和主函数所在的源程序bomb_64.c,不提供每个关卡的源代码。程序运行中有6个关卡(6个phase),每个关卡需要用户输入正确的字符串或数字才能通关,否则会引爆炸弹(打印出一条错误信息,并导致评分下降)!
要求同学运用GDB调试工具和objdump反汇编工具,通过分析汇编代码,找到在每个phase程序段中,引导程序跳转到“explode_bomb”程序段的地方,并分析其成功跳转的条件,以此为突破口寻找应该在命令行输入何种字符串来通关。
本实验需解决Phase_1(15分)、Phase_2(15分)、Phase_3(15分)、Phase_4(15分)、Phase_5(15分)、Phase_6(10分)。通过截图+文字的形式把实验过程写在实验报告上,最后并撰写实验结论与心得(15分)。
四、实验过程及内容:
准备工作:
首先在desktop目录下新建一个文件夹experiment_3用于保存本实验的所有文件。从网站上下载实验所需文件,并将其存入此文件夹中。
接着输入命令:objdump -d bomb_64 > 1.txt,将bomb_64文件进行反汇编,并将结果存入1.txt文件。
接下来直接打开1.txt,找到phase_1函数位置,即可准备解答。
第一关:
对应汇编代码如图:
图:第一关汇编代码
接下来分析此段代码的作用:
首先将栈顶指针减小8,为函数分配空间;将立即数0x401af8存入寄存器esi中;调用strings_not_equal函数,如果返回值为0,就跳转到函数定义处+0x17的位置,也即正好跳过了炸弹爆炸函数。最后还原状态,返回。
由上,我们应当输入地址0x401af8中存储的字符串。而这个地址并不存在于1.txt文档中,因此我们需要使用指针访问此地址,并直接输出:
如上图,地址0x401af8中存储的字符串即为Science isn't about why, it's about why not?,将其输入即可通过第一关。
图:成功通过第一关
第二关:
对应汇编代码如图:
图:第二关汇编代码
代码在进行了一部分预处理后将%rsi寄存器设置为栈指针%rsp的值。接着调用了函数read_six_numbers,找到该函数的定义如下。
函数中调用了sscanf函数,将输入的字符串转化为六个数字,而如果没有六个数,直接使炸弹爆炸(%eax保存读取到的数字个数)。
回到第二关代码,可以看到其将栈指针%rsp的值和%rsp+12的值分别存入了%rbp和%r13。由于输入的是整数类型,%rsp和%rsp+12分别是是输入的第一个数的第四个数的地址。
接下来的部分是一个循环:程序将会判断输入的前三个数与后三个数是否对应相等,如果不对应相等就会引爆炸弹,且此处使用%r12d记录前三个数的和,如果三个数的和为0也会引爆炸弹。
因此可以输入:0 0 1 0 0 1作为答案。
图:读取六个数
图:输入不可全为0
图:通关
第三关:
对应汇编代码如图:
图:第三关汇编代码
首先程序将两个参数分别存入栈中,接着读取输入的数;如果输入的数小于两个,直接引爆炸弹,而如果大于等于两个,就继续判断。
此处由于栈是向下(小地址)增长的,地址小的数字是后输入的,地址大的数字是先输入的,所以%rsp+12地址中存的应当是第一个输入的数,判断这个数是否大于7,如果大于,直接引爆炸弹;如果小于,进行间接跳转:
图:间接跳转语句
根据间接跳转的定义,我们需要去查看地址0x401b60以及其后一段位置的值(由于第一个数字不可超过7,只需要看八个地址即可):
图:对应地址数据
可以发现,这些地址均是第三关的后续语句,这些语句在给%eax进行赋值之后都会跳转到同一个语句处:
其目的是比较%eax与第二个输入,如果不相等就会引爆炸弹。那么此时我们只需要使调转的地址中的赋值与第二个输入对应就可以过关。例如:第一个输入为0,跳转到0x400f32处,此处将会给%eax赋值0x217(十进制535),那么0 535就是一组可行的解了。
图:通过第三关
除此之外,本题存在多解,以下是本题所有可行解:
0 535;1 926;2 214;3 339;4 119;5 352;6 919;7 412。
第四关:
第四关及其调用的函数汇编代码如下图。
首先是本关的主函数phase_4:程序在接收输入后首先会检查输入的数字数量,如果输入的数字不是一个,直接将炸弹引爆。将输入的数字保存在(%rsp+12)中,接下来检查输入的数字是否小于零,如果小于,也直接引爆炸弹,反之则将输入数字存入%edi中,作为参数调用func4函数,调用函数后检查返回值%eax与0x37(十进制55)的关系,如果不相等,也引爆炸弹。那么本题的目的就是输入一个数,使得函数func4返回55。
接着分析被调用函数func4:此函数首先将返回值%eax置为1。接着判断参数%edi是否小于等于1,如果是,直接将%eax返回(此时为1),如果不是,分别将参数%edi设置为%edi-1和%edi-2再调用两次函数func4,并将返回值%eax设置为这两次调用函数的返回值之和。
图:第四关代码
经过如上分析,可以确定此函数就是斐波那契数列的函数,输入值参数n就是斐波那契数列的第n项,输入9即可通关。
图:第四关通过
第五关:
汇编代码如下图。
程序首先调用sscanf函数读取数据,如果输入的数字少于两个,直接引爆炸弹。接着将输入的第一个数的第四位保存,高位全部舍弃,存入%eax并回原处。判断此时的eax是否等于15,如果等于,引爆炸弹,说明输入的第一个数的十六进制的低四位不可全为1。
接着程序将%ecx和%edx置为0,进入循环。循环中执行如下语句:首先将%edx自增1,接着将%eax赋值为0x401ba0+%rax*4地址中的值,因此,我们需要查看对应地址的数据。而由于%eax与%rax在此处并无差异,可以理解为是在一个数组中进行跳转,因此需要查看一系列数据:
图:对应内存中的数据
可见有效数据共16个,且第一次读取的数字就是第一个输入的低四位对应位置的数据。读取完成后,将%ecx增加%eax的值,最后如果%eax==15,退出循环。
图:第五关汇编代码
最后程序将会判断:%edx是否等于12,不等就爆炸,说明循环中内容必须进行12次;%ecx是否等于第二个输入,如果不是也爆炸,则第二个输入需要是%ecx经过十二个数累加后的结果。
为了方便计算,将数组中的数据单独取出,如下图所示:
首先可知最后一次访问的数值是15,以此逆推可得到这12个数字逆序分别是:15,6,14,2,1,10,0,8,4,9,13,11。之和为93。
综上所述,输入的第一个数的低四位十进制表示应当为7,第二个数为93。
图:通过第五关
第六关:
汇编代码如下图。
图:第六关汇编代码
首先分析第六关函数phase_6本身:函数中首先将%edx置为10,%esi置为0。接着调用函数strtol,将字符串转化为long型。接着将上一步的返回值%eax存入node0。并将0x 602780作为参数,调用fun6函数。调用结束后,进行三遍:将%rax+8所表示地址的对应内容存入%rax中。最后比较%rax表示地址中的内容与node0中的内容,如果不相等就引爆炸弹。因此,我们的输入需要最终使得%rax表示地址中的内容与node0中的内容相等。
接着分析函数fun6:此函数进行了大量的跳转处理,极为难懂,但是观察其中内容可以知道这是一个将输入通过一段处理并得到输出的函数。那么可以通过gdb调试观察其对输入的改变来试图找到一个正确的解。
直接在最后的比较函数处设置断点:
图:设置断点
接着运行程序至断点处,首先尝试1作为第六关的输入:
图:运行结果
可以看到输入的1进入了%edx,经过一系列处理后的*$rax为600,那么接下来尝试600作为输入:可以看到直接通过了第六关!
图:全部通关
五、实验结果
本实验通过查看程序对应的汇编代码,理解各个函数的含义与作用,最终通过合理的输入通过了每一关。全部通关的结果如图:
图:实验完成
六、实验总结与体会
实验总结:
本实验中,我在经过了一定量汇编代码的阅读后,对程序运行的底层原理有了更深的理解,并逐渐熟悉汇编代码的逻辑与阅读方式。这将有助于我对程序的编写与优化。
实验体会:
本实验需要通过查看汇编代码来理解程序的目的,而汇编代码的阅读难度远超c语言,实验进行过程中遇到了很多的困难,以下是我总结的一些困难、解决方案与技巧。
寄存器的名字并不像c语言中的变量可以直接命名为具有意义的值,他们往往抽象难懂,且可能同时具有多个名字(仅仅是表示的数据大小不同)。因此,阅读过程中需要使用易懂的语言表示大部分语句的作用,例如各个函数开头具有的操作可以概括为:改变栈指针,为栈分配空间。除此之外,熟记不同寄存器的作用也是一个重要方法。
后几关的函数中往往存在各种跳转,每次看到跳转语句都去寻找对应的地址可能会非常费时,可以在跳转目的地址所在语句的最前端加上一些标记,例如LOOP,这样可以辅助判断循环的起点等重要位置。
尾注
本实验是本课程的第三次实验,难度不低,且涉及了比较陌生的查看特定地址的数据等操作,可能需要查阅资料才能完成。
如有疑问欢迎讨论,如有好的建议与意见欢迎提出,如有发现错误则恳请指正!
附:虚拟机常用指令+本实验全部答案
实验三:/*
进入实验三文件夹(需要先创建):cd ~/Desktop/experiment_3
输入反汇编指令查看汇编代码(只需生成一次):objdump -d bomb_64 > 1.txt
增加当前用户对bomb文件的执行权限:chmod +x bomb_64
进入gdb模式:gdb bomb_64
直接运行程序:./bomb_64
运行到关卡一输入处:r
第三关查看对应地址数据语句:print/x *(int*) (0x401b60+8*0)
第一关答案:Science isn't about why, it's about why not?
第二关答案:0 0 1 0 0 1
第三关答案(任选一组):0 535;1 926;2 214;3 339;4 119;5 352;6 919;7 412
第四关答案:9
第五关答案:7 93
第六关答案:600
*/