BUPT CSAPP lab2二进制炸弹

一、实验目的
1.理解C语言程序的机器级表示。
2.初步掌握GDB调试器的用法。
3.阅读C编译器生成的x86-64机器代码,理解不同控制结构生成的基本指令模式,过程的实现。
二、实验环境
1.SecureCRT(10.120.11.12)
2.Linux
3.Objdump命令反汇编
4.GDB调试工具
5.Xshell 软件
三、实验内容
登录bupt1服务器,在home目录下可以找到Evil博士专门为你量身定制的一个bomb,当运行时,它会要求你输入一个字符串,如果正确,则进入下一关,继续要求你输入下一个字符串;否则,炸弹就会爆炸,输出一行提示信息并向计分服务器提交扣分信息。因此,本实验要求你必须通过反汇编和逆向工程对bomb执行文件进行分析,找到正确的字符串来解除这个的炸弹。
本实验通过要求使用课程所学知识拆除一个“binary bombs”来增强对程序的机器级表示、汇编语言、调试器和逆向工程等方面原理与技能的掌握。 “binary bombs”是一个Linux可执行程序,包含了5个阶段(或关卡)。炸弹运行的每个阶段要求你输入一个特定字符串,你的输入符合程序预期的输入,该阶段的炸弹就被拆除引信;否则炸弹“爆炸”,打印输出 “BOOM!!!”。炸弹的每个阶段考察了机器级程序语言的一个不同方面,难度逐级递增。
为完成二进制炸弹拆除任务,需要使用gdb调试器和objdump来反汇编bomb文件,可以单步跟踪调试每一阶段的机器代码,也可以阅读反汇编代码,从中理解每一汇编语言代码的行为或作用,进而设法推断拆除炸弹所需的目标字符串。实验2的具体内容见实验2说明。
四、实验步骤及实验分析
准备工作:
登录bupt1服务器,使用ls命令,发现炸弹文件压缩包bomb334.tar。使用tar -xvf bomb334.tar解压文件压缩包,得到一个目录bomb334。使用cd bomb334命令进入目录,使用ls命令,可看到三个文件bomb,bomb.c,README 。
在这里插入图片描述

输入cat README命令,阅读README文件内容,确认炸弹bomb334属于学生2020211472。

在这里插入图片描述

 用vi编辑器,输入命令vi answer ,创建一个文件answer,用于存储答案。

在这里插入图片描述

阶段一:总览
查看bomb.c文件内的代码,发现实验分为六步,六步拆掉实验应分别位于phase_1,phase_2,phase_3,phase_4,phase_5,phase_6六个函数中。
在这里插入图片描述在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

观察bomb.c文件最后的文字提示,推测还存在第七个隐藏关卡
在这里插入图片描述

使用objdump工具查看bomb文件的代码,在phase_defused函数的代码中,我们可以发现隐藏的炸弹关卡secret_phase
在这里插入图片描述

输入gdb bomb,进入gdb调试器,键入disas phase_defused,获得phase_defused函数的汇编代码
观察汇编代码,进入隐藏关卡secret_phase的条件包括通过前六个关卡(即输入d字符串数达到6),和两个整形参数,一个字符串参数。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

总览分析到此告一段落,接下来进入正式拆解炸弹环节。

阶段二:phase_1拆解 注:此关卡设计字符串比较
键入b phase_1在phase_1函数处设置断点。
在这里插入图片描述

键入命令disas phase_1,观察phase_1的代码,根据<phase_1+9>处的代码,发现该关卡应输入一字符串,并与对应的字符串相互比较,二者一致则拆除炸弹通过关。

同时观察代码,根据<phasse_1+4>处的代码,可发现从键盘输入的字符串应与存储在0x402670处的字符串相互比较。故键入x /s 0x402670,以字符串形式显示该地址处的数据。得到一串字符串Many students of BUPT want to be a code farmer after graduation.
在这里插入图片描述

此即为第一关卡答案。
键入命令r运行程序,输入字符串Many students of BUPT want to be a code farmer after graduation.
在这里插入图片描述

随后重复利用ni命令单步执行,同时观察指令跳转,程序未触发炸弹<explode_bomb>,第一关顺利通过。
在这里插入图片描述
在这里插入图片描述

随后使用crtl+C命令和kill命令安全退出调试程序。
在这里插入图片描述

打开answer文件,存入第一关答案Many students of BUPT want to be a code farmer after graduation.保存并退出。键入cat answer,检查字符串是否已存入文件answer。
在这里插入图片描述
重新进入gdb调试工具,键入r answer ,关卡一通过,说明正确答案已正确存入文件answer。
在这里插入图片描述
至此,关卡一已通过。

阶段三:phase_2拆解 注:此关卡涉及数据加减比较
键入b phase_2在phase_2函数处设置断点。
在这里插入图片描述
键入命令disas phase_2,观察phase_2的代码,根据<phase_2+25>处的代码,可知我们应输入六个数字。
在这里插入图片描述
此处应使用disas指令反汇编read_six_numbers函数,观察其汇编代码可证实该函数的功能确实是输入六个数字,若未输入六个数字则在函数中触发炸弹。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

继续观察phase_2函数,发现在输入六个数字后需要连续进行两个判断,对栈顶的前两个元素的值进行判断,不满足第一个值为0,第二个值为1则触发炸弹。故,可知输入的前两个数字应为0,1。
在这里插入图片描述

继续观察后续代码,可发现代码中存在一个循环,循环的结束条件是%rbp=%rbx
起初%rbp=(%rsp+10),%rbx=%rsp,每执行一次循环,%rbx+=0x4,故需要执行四次循环。
在这里插入图片描述

又因在每次循环执行中,需满足条件(%rbx)+(%rbx+0x4)=(%rbx+0x8)
即前两个数之和等于第三个数,所以我们输入的数字是一个斐波那契数列
在这里插入图片描述

因为前两个数字是0,1 故六个数字为0,1,1,2,3,5,此即为第二关卡答案。
键入命令r answer运行程序,输入0 1 1 2 3 5。
在这里插入图片描述

随后重复利用ni命令单步执行,同时观察指令跳转,程序未触发炸弹<explode_bomb>,第二关顺利通过。
随后使用crtl+C命令和kill命令安全退出调试程序。
打开answer文件,存入第二关答案0 1 1 2 3 5.保存并退出。键入cat answer,检查字符串是否已存入文件answer。
重新进入gdb调试工具,键入r answer ,关卡通过,说明正确答案已正确存入文件answer。
至此,关卡二已通过。
阶段四:phase_3拆解 注:此关卡涉及switch语句
键入b phase_3在phase_3函数处设置断点。
在这里插入图片描述
键入命令disas phase_3,观察phase_3的代码,发现,输入函数的参数与0x4029ad有关,
使用x /s 0x4029ad函数进行观察,发现本次需要输入两个整数。
在这里插入图片描述在这里插入图片描述
继续向后观察,发现对第一个输入数字的判断,第一个数字以无符号比较不可大于7
在这里插入图片描述
继续向后观察,发现后续代码中存在一个switch语句,跳转位置取决于输入的第一个数字。
在这里插入图片描述
查看switch各分支的位置在这里插入图片描述

故,以第一个输入数字为2为例:
其将执行运算
eax=0
eax+=0x349;
eax-=0x14d;
eax+=0x14d;
eax-=0x14d;
eax+=0x14d;
eax-=0x14d;
eax=508
执行后,出现补充条件,第一个数字有符号比较时不可大于5
在这里插入图片描述
eax后与第二个输入数字比较,相等则拆除炸弹
在这里插入图片描述
故,当第一个输入数字为2,第二个数字为508
其他情况同上述推理方法
键入命令r answer运行程序,输入2 508。
在这里插入图片描述
随后重复利用ni命令单步执行,同时观察指令跳转,程序未触发炸弹<explode_bomb>,第三关顺利通过。
随后使用crtl+C命令和kill命令安全退出调试程序。
打开answer文件,存入第三关答案2 508保存并退出。键入cat answer,检查字符串是否已存入文件answer。
重新进入gdb调试工具,键入r answer ,关卡通过,说明正确答案已正确存入文件answer。
至此,关卡三已通过。

阶段五:phase_4拆解 注:此关卡涉及递归操作
键入b phase_4在phase_4函数处设置断点。
键入命令disas phase_4,观察phase_4的代码,
同关卡三,我们可发现本题也是输入两个整数
在这里插入图片描述在这里插入图片描述在这里插入图片描述

阅读代码,我们可发现,对第一个输入数字,出现比较,要求第一个输入数字不得超过0xe,即14。
在这里插入图片描述

继续观察后续代码,发现代码中出现函数func4调用,
使用disas func4,查看fun4函数汇编代码
在func4函数内部出现了调用fun4函数,可推测出此题采用了递归的思想。
在这里插入图片描述

返回phase_4函数,继续观察,发现要拆解炸弹,func4的返回值应为3,第二输入数据应为3。
接下来分析func4函数,等价func函数的c语言为:
int fun(int edi, int esi, int edx)
{
int eax = edx;
eax -= esi;
int ecx = eax;
ecx = 0;
eax += ecx;
eax /= 2;
ecx = eax + esi;
if (ecx > edi)
{
eax = fun(edi, esi, ecx - 1);
eax = 2;
}
else
{
eax = 0;
}
if (ecx < edi)
{
eax = fun(edi, ecx + 1, edx);
eax = eax * 2 + 1;
}
return eax;
}
对该函数进行分析,要让最后eax=3
则3=1
1+1
1=0*0+1
所以需先进入第二个if模块两次,经过测试,当edi=12是满足条件,
故答案为12 3
将答案输入程序进行测试,成功拆弹,后将答案存入answer文件

阶段六:phase_5拆解 注:此关卡涉及循环和数据转换(根据按位与)
键入b phase_5在phase_5函数处设置断点。
键入命令disas phase_5,观察phase_5的代码,
在这里插入图片描述

观察代码,发现本次需要输入一个长度为6的字符串
在这里插入图片描述

继续向下观察,可以发现后续存在一个循环,循环次数为六,
在这里插入图片描述
在这里插入图片描述

每次循环都会对每个字符与0xf进行按位与操作,在这里插入图片描述

后根据按位与的结果作为偏置值,前往以地址0x402720起始处寻值,将相应值累加存入寄存器%ecx中在这里插入图片描述

最后累加值需要和0x40相等,方可不触发炸弹在这里插入图片描述

现在查看以地址0x402720起始的内存存储的数据
在这里插入图片描述

前16个整数数据如上,所以得到一个符合条件的情况为:104+122=64。
此时查看ASCII表,发现a的对应值为97,d的对应值为100,a&0xf=1,d&0xf=4,所以其中一个密码为四个a与两个d组合
取密码aaaadd,将其输入程序进行测试,测试通过,炸弹拆解。将答案存入answer文件。

至此关卡5通过。

第6,7关卡是选做部分,我就不上图了

阶段七:phase_6拆解 注:此关卡涉及多重循环和根据地址寻值
键入b phase_6在phase_6函数处设置断点。

键入命令disas phase_6,观察phase_6的代码,

观察代码可知,此时需要输入六个整数

继续向下观察,发现将进入一个循环,循环会进行六次

在循环过程中,六个整数会被逐一取出进行-1操作,后与0x5进行无符号比较,小于等于0x5才不会触发炸弹,且六个数需要互不相同。

由此可知,我们需要输入按某种顺序输入1-6六个整数。设六个数为a1-a6。
继续向下观察,进入新的循环,该循环中,每个输入的数将转换为7-该数

继续向下观察,程序将进入一个新的循环,循环存在嵌套,大循环进行六次,(0x18=6*0x4)小循环进行次数为ai的值。

该循环中,针对从栈指针对应地址+20起,每八个字节为一个单位的数据进行操作,存入0x6042f0+8ai,ai为输入的数据转变后的值

离开上个循环后,检查栈内数据,查看上个循环新产生的数据
由下图可发现,以地址0x7fffffffea00开始,八个字节一个单位,原本由键盘输入的数据在前24字节,新产生的数据存储在地址0x7fffffffea20开始,占48个字节。

继续向后查看代码,后方代码涉及对以0x6042f0起始地址的检索,

故查看地址0x6042f0起始的地址内的数据

再观察后续代码,发现调用地址获取的数据应从大到小排列,
所以数据先后顺序应为:0x3df, 0x307, 0x25f, 0x232, 0x16c, 0x0c2
所以地址顺序应为:0x6043f0,0x604330,0x604300,0x604320,0x604340,0x604310,
所以数字顺序为 1 5 2 4 6 3
故原数字输入顺序为6 2 5 3 1 4,此即为本题答案
将6 2 5 3 1 4输入程序测试,成功通过。将答案存入文件answer。

阶段八:secret_phase拆解 注:此关卡涉及递归和二叉树的存储结构
键入b secret_phase在secret_phase函数处设置断点。
键入命令disas secret_phase,观察secret_phase的代码,

跟据阶段一获得的信息,可知隐藏关卡入口位于函数phase_defused中,进入隐藏关卡secret_phase的条件包括通过前六个关卡(即输入d字符串数达到6),和两个整形参数,一个字符串参数。
利用disas phase_defused获取phase_defused函数的汇编代码,发现字符串变量需要与地址0x402a00处的数据进行比较

利用x /s命令获得0x402a00处的数据,为DrEvil,此为进入隐藏关卡的字符串指令

又发现输入的数据存储在0x6048b0中,此处为第四题的输入存储区,故可知,要进入隐藏关卡,需在第四题的答案后加一个字符串 DrEvil,所以在answer文件内第四题答案后添加DrEvil,r answer运行程序,进入隐藏关卡

此时0x6048b0内的数据为:

接下来分析secret_phase代码,发旋本题要求输入一行数据,后数据要同0x3e8进行比较,要小于0x3e8,推测次数数据为整数

发现其中调用了fun7函数,进入反汇编fun7函数,返现fun7发生了自身调用,故此为递归。

先继续分析secret_phase函数u,返现其破解条件为fun7返回值为6。

有发现fun7函数有两个参数,一个为输入值,另一个为0x604110,此应为地址,故使用x指令查看内部数据

观察数据可知,此为二叉树的存储结构
对fun函数进行分析
当fun7函数检索左子树时,条件为输入值小于当前结点数据,此时返回值2
当fun7函数检索右子树时,条件为输入值大于当前结点数据,此时返回值
2+1
下图为二叉树存储结构

当fun7返回值为6
6=32
3=1
1+1
1=0*0+1
所以二叉树搜索顺序为先搜左子树,再搜右子树,再搜右子树
所以对应值应为35,此即为本关卡答案
向程序输入35,成功通过。

至此本次二进制炸弹实验全部通过

  • 14
    点赞
  • 76
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值