一、 实验目的
1.理解C语言程序的机器级表示。
2.初步掌握GDB调试器的用法。
3.阅读C编译器生成的x86-64机器代码,理解不同控制结构生成的基本指令模式,过程的实现。
二、实验工具
- SecureCRT
- Linux
- Objdump命令反汇编
- GDB调试工具
三、实验内容
登录bupt1服务器,在home目录下可以找到Evil博士专门为你量身定制的一个bomb,当运行时,它会要求你输入一个字符串,如果正确,则进入下一关,继续要求你输入下一个字符串;否则,炸弹就会爆炸,输出一行提示信息并向计分服务器提交扣分信息。因此,本实验要求你必须通过反汇编和逆向工程对bomb执行文件进行分析,找到正确的字符串来解除这个的炸弹。
本实验通过要求使用课程所学知识拆除一个“binary bombs”来增强对程序的机器级表示、汇编语言、调试器和逆向工程等方面原理与技能的掌握。 “binary bombs”是一个Linux可执行程序,包含了5个阶段(或关卡)。炸弹运行的每个阶段要求你输入一个特定字符串,你的输入符合程序预期的输入,该阶段的炸弹就被拆除引信;否则炸弹“爆炸”,打印输出 “BOOM!!!”。炸弹的每个阶段考察了机器级程序语言的一个不同方面,难度逐级递增。
为完成二进制炸弹拆除任务,需要使用gdb调试器和objdump来反汇编bomb文件,可以单步跟踪调试每一阶段的机器代码,也可以阅读反汇编代码,从中理解每一汇编语言代码的行为或作用,进而设法推断拆除炸弹所需的目标字符串。实验2的具体内容见实验2说明。
四、实验步骤及实验分析
1、反汇编并利用SSH Secure Shell Client工具下载反汇编代码
通过ls指令显示当前目录下的文件,找到压缩包bomb115.tar,即目标炸弹。通过tar xvf bomb115.tar解压此压缩包,然后再通过ls显示解压出的文件:bomb、bomb.c和README。
通过objdump –d bomb > bomb.txt将炸弹程序反汇编并重定向到bomb.txt,通过ls显示反汇编出的代码文件bomb.txt。
打开SSH Secure Shell Client工具,登录到远程主机,将远程主机上的文件下载到本机上,便于查看。
2、查看目标文件并做好调试准备
文件介绍:
bomb.txt:反汇编得到的代码文件,也是主要研究的目标文件。
bomb.c:主函数,通过调用每一关的函数实现,未显示每关的具体代码。
bomb:炸弹程序,当调试得出每一关的密码后打开程序运行来拆炸弹。
通过gdb bomb指令进入gdb调试环境。
大致浏览反汇编代码,可以观察到整个程序一共有六关,分别为phase_1到phase_6,并有一关隐藏关secret_phase,每次输入错误时会调用引爆函数explode_bomb,因此为避免调试时引爆炸弹,需要首先在引爆函数前设置断点,即b explode_bomb。
3、拆除炸弹
1、 第一个炸弹
程序流程:
- 取内存地址0x4024b0处的内容;
- 取用户输入的内容(即密码);
- 比较两者的值,相等则%eax置为0,进入下一关,不相等则调用引爆程序引爆炸弹。
破解思路:
通过x/s 0x4024b0指令取出该地址的字符串,得到:Only you can give me that feeling.
则密码为:Only you can give me that feeling.
通过 !
2、 第二个炸弹
程序流程:
- 读取用户输入内容(为6个数字);
- 判断输入的第一个值是否为1,不是则引爆炸弹;
- 做一个6次循环,判断后一个数是否等于前一个数加上之前循环变量,不是则引爆炸弹;
- 六个数字判断相等结束后,进入下一关
破解思路:
设输入内容为一个数组Key[6],则可知Key[0]=1,Key[i+1]=Key[i]+i。
因此第二关的密码是:1 2 6 24 120 720
3、 第三个炸弹
程序流程:
- 读取输入参数1和参数2,调用scanf函数传入两个参数;
- 比较参数1与7的大小,小于等于7继续,大于7引爆;
- 根据参数1的值来搜索跳转地址,计算得到最终的%eax;
- 比较参数1与5的大小,小于等于5继续,大于5引爆;
- 比较参数2与计算得到的%eax是否相等,相等则进入下一关,不相等则引爆。
重点在于参数1的选择决定了switch的跳转,该实验地址为(设参数1为x):
0x402510+x*8
其中存在一个Switch函数表,这个炸弹我选择参数1为2,则跳转地址为0x00400f33
Switch跳转到改地址开始计算eax%,最终结果为0x328-0xf7=0x231=561。
输入 2 561。
成功 !
4、 第四个炸弹
主程序流程:
- 读取2个参数,调用scanf函数传入参数;
- 比较输入参数与2的大小,小于则引爆;比较输入参数与4的大小,大于则引爆。
- 把输入参数传入函数func4,并调用函数func4;
- 若函数func4返回值等于%rsp+0x8,则返回,进入下一关,否则引爆炸弹。
func4函数流程:
1. 比较传入参数是否大于1,大于1则继续,小于1则返回0,等于1则返回%rax;
2. 循环%edi=%edi-1,并递归调用函数func4,直到参数小于等于1;
3. 循环变量%edi=edi-2,并传入%esp继续递归调用函数func4;
4. 函数返回的所得值加到%eax;
设b=%edi,a=%esi,则f(a,b)=f(a,b-1)+f(a,b-2)+a;
第二个参数小于1则返回0,等于1则返回%rax(即a)。
炸弹中默认b=8,我们输入a=2,经过上述式子计算得f(8)=561.
输入108 2 或者162 3。
成功 !
5、 第五个炸弹
程序流程:
- 输入字符串
- 调用string_length的字符串长度函数,测得的长度若不为6则引爆;
- 做一个6次的循环,循环变量%eax从1到6,;
- 我们要使得 string_not_equal返回值为0 ,也就是%ebp处的值和0x4024fe处的值相等,查看0x4024fe处的值,发现为bruins
- 循环赋giant了, 依次改变以%ebp为开始位置的char的数组的值 那么b,r,u,I,n,s就存在于该字符串,寻找改变字符串值的语句。
- 取得 (0x8[%ebp]+0xc(%ebp)) &0xf的值,作为下标取得0x402550中的值,查看 0x402550处的内存为 maduiersnfotvbylSo you think you can stop the bomb with ctrl-c, do you?
- bruins分别对应 13 6 3 4 8 7 所以要取得13 6 3 4 8 7
- 我们输入的内容写成 ASCII码应该是xd x6 x3 x4 x8 x7。x表示任取,随便取得 3d 36 33 34 38 37,对应ASCII码为=63487。输入
- 成功 !