【CSAPP】Binarybomb 实验(phase_1-6+secret_phase)

2 篇文章 0 订阅
2 篇文章 0 订阅
本文详细介绍了如何通过使用gdb调试器和objdump来分析和解决Linux下的二进制炸弹程序,涉及字符串比较、for循环、switch分支、递归、数组和链表等多个阶段,每个阶段都通过调试和理解汇编代码找出解除炸弹的正确输入字符串。
摘要由CSDN通过智能技术生成

Binarybomb 实验(phase_1-6+secret_phase)

实验内容

一个“binary bombs”(二进制炸弹,下文将简称为炸弹)是一个Linux可执行C程序,包含了7个阶段(phase1~phase6和一个隐藏阶段)。炸弹运行的每个阶段要求学生输入一个特定的字符串,若的输入符合程序预期的输入,该阶段的炸弹就被“拆除”,否则炸弹“爆炸”并打印输出 "BOOM!!!"字样。实验的目标是拆除尽可能多的炸弹层次。
每个炸弹阶段考察了机器级语言程序的一个不同方面,难度逐级递增:

  • 阶段1:字符串比较
  • 阶段2:for循环
  • 阶段3:switch分支
  • 阶段4:递归函数
  • 阶段5:数组元素按序访问
  • 阶段6:链表
  • 隐藏阶段:只有在阶段4的拆解字符串后再附加一特定字符串后才会出现(作为最后一个阶段)

为了完成二进制炸弹拆除任务,需要使用gdb调试器和objdump来反汇编炸弹的可执行文件,并单步跟踪调试每一阶段的机器代码,从中理解每一汇编语言代码的行为或作用,进而设法“推断”出拆除炸弹所需的目标字符串。这可能需要在每一阶段的开始代码前和引爆炸弹的函数前设置断点,以便于调试。

实验材料:bomb程序与bomb.c文件。
请添加图片描述

实验目标

正常运行bomb程序,不执行程序内的explode_bomb函数。

实验过程

  1. 创建答案文本文件solution.txt,并随意填入7行字符串,对应phase_1-6 与 secret_phase 的破解字符串。
    在这里插入图片描述
  2. 使用gdb对bomb程序进行调试,并打开可视化界面。
    打开gdb
    在这里插入图片描述
    打开可视化
    在这里插入图片描述
  3. 整体界面
    在这里插入图片描述

phase_1

实验步骤
  1. 在gdb设置断点
    在这里插入图片描述

  2. 运行bomb程序,并定位到爆炸点
    运行
    在这里插入图片描述
    定位爆炸点
    在这里插入图片描述

  3. 分析爆炸点
    爆炸点跳转是通过判定strings_not_equal函数的返回值进行跳转。故我们查看参数%rsi中的值。
    在这里插入图片描述

  4. 修改solution.txt中,phase_1的字符串为Border relations with Canada have never been better.
    在这里插入图片描述

  5. 重新运行,过关
    在这里插入图片描述

phase_2

实验步骤
  1. 在gdb中设置断点
    在这里插入图片描述

  2. 运行bomb程序,并定位爆炸点。
    在这里插入图片描述

  3. 分析爆炸点
    通过函数名可知,phase_2需要我们输入6个数字。

  4. 修改solution.txt,phase_2的字符串随意输入6个数字。
    在这里插入图片描述

  5. 重新运行,并定位爆炸点。
    在这里插入图片描述

  6. 分析爆炸点
    炸弹爆炸直接原因是 %eax中的值 与 0x0(%rbp,%rbx,4) 的值不同,导致没有跳转,触发了下一条的explode_bomb
    根据前文mov %rsp,%rbp我们得出%rbp的值为%rsp的值。
    查看%rsp地址,发现%rsp为我们输入的6个数字,故%rbp为我们输入值的首地址。
    在这里插入图片描述
    再分析%rbx,很明显%rbx是1-5的一个遍历值,置于0x0(%rbp,%rbx,4)中,后者意义为遍历我们输入的第2-6个数字。
    在这里插入图片描述
    再来看最后一项%eax,先将%ebx设置为%ebx,再加上-0x4(%rbp,%rbx,4)的值,后者为我们遍历到的数字往前4个字节,即前一个数字。所以这里意思为,把我们输入数字按顺序0-5编号,当前数字必须等于当前编号+上一个数字。
    在这里插入图片描述

  7. 修改solution.txt,phase_2的字符串为0 1 3 6 10 15,即0,0+1,1+2,3+3,6+4,10+5。

  8. 重新运行,过关。
    在这里插入图片描述

phase_3

实验步骤
  1. 在gdb中设置断点
    在这里插入图片描述
  2. 运行程序,并定位到爆炸点。
    在这里插入图片描述
  3. 分析爆炸点
    爆炸原因为,__isoc99_sscanf 函数的返回值%eax小于等于1。我们查询百度得知 __isoc99_sscanf 函数的返回值为输入参数的数量。我们查看标注的地址0x5555554029cf,得知我们需要输入两个整数。
    在这里插入图片描述
  4. 修改solution.txt,phase_3的字符串随意输入两个整数。
    在这里插入图片描述
  5. 重新运行,并定位到爆炸点。
    在这里插入图片描述
  6. 分析爆炸点
    爆炸的直接原因为%rsp中的值大于7,分析%rsp,查看%rsp的值,发现%rsp为我们输入数字的首地址。所以我们输入的第一个数应该不大于7。
    在这里插入图片描述
  7. 修改solution.txt,phase_3第一个参数修改为小于等于7的任意值。
    在这里插入图片描述
  8. 重新运行,并定位到爆炸点。
    在这里插入图片描述
  9. 分析爆炸点
    爆炸直接原因为%eax 和 0x4(%rsp) 的值不相等。根据前文mov $0x1c1,%eax可知%eax的值为0x1c1。再分析%rsp,查看%rsp的值,发现%rsp为我们输入数字的首地址,而0x4(%rsp)为输入的第二个数。故把第二个数修改为449(0x1c1)。
    在这里插入图片描述
  10. 修改solution.txt,phase_3的字符串的第二个数为449。
    在这里插入图片描述
  11. 重新运行,过关。
    在这里插入图片描述

phase_4

实验步骤
  1. 在gdb设置断点
    在这里插入图片描述

  2. 运行程序,定位到爆炸点
    在这里插入图片描述

  3. 分析爆炸点
    同phase_3,需要输入两个整数。

  4. 修改solution.txt,phase_4的字符串为随意两个整数
    在这里插入图片描述

  5. 重新运行程序,定位到爆炸点
    在这里插入图片描述

  6. 分析爆炸点
    爆炸直接原因为%eax的值不等于0xa。而%eax为func4函数的返回值。故我们需要func4返回10,即0xa。

  7. 分析func4
    根据前文,func4有三个参数%edx,%esi,%edi。值分别为0xe,0x0,(%rsp)。
    在这里插入图片描述
    查看%rsp,发现%rsp为我们输入的两个整数的地址。
    进入func4函数
    在这里插入图片描述
    我们首先查看返回
    在这里插入图片描述
    从中我们了解递归的终止条件为%edi和%ebx相等,返回值为%ebx的值。
    我们查看有关%ebx的代码。
    在这里插入图片描述
    我们将代码分模块,分别为操作模块和跳转模块
    在这里插入图片描述
    操作模块1,分析此段代码执行的操作如下。
    在这里插入图片描述
    跳转模块1,当%ebx大于%edi时跳转。执行操作为将%rbx-1赋给%edx执行func4,将结果累加到%ebx中,并返回。
    在这里插入图片描述
    跳转模块2,当%ebx小于%edi时跳转。执行操作为将%rbx+1赋给%esi执行func4,将结果累加到%ebx中,并返回。
    在这里插入图片描述
    我们需要返回值累加为10,%edx初始为14即0xe,%esi初始为0,%edi为我们输入的参数。故我们执行两次跳转模块1即可得到返回值10,7+3 = 10。所以%rdi应该为3。

  8. 修改solution.txt,phase_4字符串的第一个参数应为3。
    在这里插入图片描述

  9. 重新运行程序,并定位爆炸点。
    在这里插入图片描述

  10. 分析爆炸点
    爆炸原因为0x4(%rsp)的值不等于0xa,而%rsp为我们输入的参数的首地址。而0x4(%rsp)为我们输入的第二个参数,故需修改第二个参数为10,即0xa。

  11. 修改solution.txt,phase_4的字符串第二个参数为10。
    在这里插入图片描述

  12. 重新运行程序,过关。
    在这里插入图片描述

phase_5

实验步骤
  1. 在gdb设置断点
    在这里插入图片描述

  2. 运行程序,并定位爆炸点。
    在这里插入图片描述

  3. 分析爆炸点
    同phase_4,需要输入两个整数。

  4. 修改solution.txt,phase_5的字符串为随意两个整数。
    在这里插入图片描述

  5. 重新运行程序,并定位爆炸点。
    在这里插入图片描述

  6. 分析爆炸点
    爆炸的直接原因是%edx不等于15,即0xf。我们查看有关%edx的代码。
    在这里插入图片描述
    从中可以看出%edx是一个计数器,我们需要执行15次add $0x1,%edx。我们查看可以跳转到目标的代码:
    在这里插入图片描述
    其中跳转条件为%eax不等于15,即0xf,所以我们需要%eax不等于15,15次。我们查看其中有关%eax的代码。
    在这里插入图片描述
    其中查看%rsp发现是我们输入的参数地址,所以上部分的操作为将我们输入的第一个参数赋给%eax,并取出低4位。且%eax的值不等于15,否则进入爆炸点<phase_5+57>。而下部分为取出(%rsi,%rax,4)中的值给%eax。我们查看%rsi中的值:
    在这里插入图片描述
    所以我们需要执行15次mov (%rsi,%rax,4),%eax,最后一次结果为15。我们从15反推,15->6(24/4)->14(56/4)->2(8/4)->1(4/4)->10(40/4)->0(0/4)->8(32/4)->4(16/4)->9(36/4)->13(52/4)->11(44/4)->7(28/4)->3(12/4)->12(48/4)->5(20/4)。所以%rax第一次应该为5。

  7. 修改solution.txt,phase_5的字符串第一个参数为5。
    在这里插入图片描述

  8. 重新运行,定位到爆炸点。
    在这里插入图片描述

  9. 分析爆炸点
    爆炸直接原因为%ecx和0x4(%rsp)的值不相等,没有跳转而触发下一条的炸弹。%rsp为我们输入参数的地址,所以0x4(%rsp)为我们输入的第二个参数。我们直接查看%ecx的值:
    在这里插入图片描述
    所以我们第二个参数应该为115。

  10. 修改solution.txt,phase_5的字符串第二个参数为115。
    在这里插入图片描述

  11. 重新运行程序,过关。
    在这里插入图片描述

phase_6

实验步骤
  1. 在gdb设置断点
    在这里插入图片描述

  2. 运行程序,定位到爆炸点。
    在这里插入图片描述

  3. 分析爆炸点
    同phase_2,我们需要输入6个数字。

  4. 修改solution.txt,phase_6的字符串为随意6个数字。
    在这里插入图片描述

  5. 重新运行程序,定位到爆炸点。
    在这里插入图片描述

  6. 分析爆炸点
    爆炸的直接原因是无符号%eax大于5,而%eax的值是%r12的值-1。我们查看%r12的值:
    在这里插入图片描述
    发现%r12是我们输入参数的首地址。add $0x4,%r12代表%r12往后移4字节,即我们输入的下一个数。我们查看有关的跳转代码:
    在这里插入图片描述
    此处发现是对%ebx进行计数,当%ebx超过5便走一次<phase_6+45>,我们再查看有关%ebx的代码:
    在这里插入图片描述
    从此处可以看出%ebx与%r13d有关,我们再查看有关%r13d的代码:
    在这里插入图片描述
    发现%r13d也是一个计数,跳出条件为%r13d的值等于6。在前文查找%r13d的初始值:
    在这里插入图片描述
    所以%r13为1->5的遍历,每次遍历都会传值给%ebx进行%ebx->5的遍历,所以会执行5次add $0x4,%r12,即比较我们输入每个数字-1的结果无符号的小于等于5,即我们输入的每个数字必须是1-6。

  7. 修改solution.txt,phase_6的字符串为6个1-6间的数字。
    在这里插入图片描述

  8. 重新运行,并定位到爆炸点。
    在这里插入图片描述

  9. 分析爆炸点
    爆炸的直接原因是%eax与0x0(%rbp)的值相等,没有跳转,所以触发了下一条的炸弹。其中根据前文%rbp与%r12的值相同,而%eax的值为(%rsp,%rax,4)。其中%rax和%ebx的值相同,我们查看%rsp的值:
    在这里插入图片描述
    发现%rsp为我们输入参数的地址。根据前文的分析,可知当%rbp指向我们输入的第一个参数时,%rax会遍历1-5,即第一个数与其后面的所有数进行对比,不能相同。当%rbp指向我们输入的第二个参数时,%rax会遍历2-5,即第二个数与其后面的所有数进行对比,不能相同。总结,此段代码限制输入不能有重复元素。故我们需要输入1-6,并且不重复。

  10. 修改solution.txt,phase_6的字符串为6个1-6间的数字,并且不重复。
    在这里插入图片描述

  11. 重新运行,并定位到爆炸点。
    在这里插入图片描述

  12. 分析爆炸点
    爆炸的直接原因是%rbx的值大于%eax的值没有触发跳转,而执行了下一句的炸弹。查看有关%rbx的代码:
    在这里插入图片描述
    从此看出%rbx与0x20(%rsp)有关,查看与后者有关的代码:
    在这里插入图片描述
    而0x20(%rsp)与%rdx有关,再次查看有关代码:
    在这里插入图片描述
    从这可以看出%rdx是<node1>经过操作得到,查看node1中的值:
    在这里插入图片描述
    从<node1+8>的值是0x555555604220即<node2>的地址,看出这里存储了链表的6个节点,节点内存储的是数据和节点的编号。初始链接顺序为:
    在这里插入图片描述
    我们把代码分模块:
    在这里插入图片描述
    模块4,将%esi设置为0,并执行模块3
    模块3,%rsp是我们输入参数的首地址,mov (%rsp,%rsi,4),%ecx为取第%rsi+1个参数放到%ecx中,并将%eax设为1,将%rdx设为链表节点1的地址,若%ecx大于1执行模块1,否则执行模块2。
    模块1,我们了解%rdx是链表的结点,所以0x8(%rdx)的值是链表下一节点的地址。%eax是计数,当%eax不等于%ecx就继续执行mov 0x8(%rdx),%rdx。即找到编号为%ecx的链表节点,然后执行模块2。
    模块2,将取出的节点地址放到0x20(%rsp,%rsi,8)的位置,然后%rsi计数+1,当%rsi等于6时,跳出模块,否则按顺序执行模块3。
    总结,此段代码执行的功能为,将6个链表的结点,按我们输入参数的编号存储到0x20(%rsp)的位置。验证:
    在这里插入图片描述
    继续查看有关0x20(%rsp)的代码:
    在这里插入图片描述
    发现此段代码是根据我们输入的节点顺序,重新排列链表。%rbx为重排后链表的头结点。重排后的链接顺序为:
    在这里插入图片描述
    而%eax为当前节点的下一个节点地址。我们需要的链表是节点值从小到大排序的链表。所以我们应该输入的6个参数为5,2,6,3,1,4。

  13. 修改solution.txt,phase_6的字符串为5 6 2 3 1 4。
    在这里插入图片描述

  14. 重新运行程序,过关。
    在这里插入图片描述

secret_phase

secret_phase是隐藏了入口的,所以我们需要查看入口所在的地址,再拆除炸弹。

实验步骤
  1. 查看bomb汇编代码,查找调用secret_phase函数的代码。
    执行objdump -d bomb > bomb.s再打开bomb.s文件,搜索secret_phase。
    在这里插入图片描述
    所以入口在phase_defused函数中,我们返回gdb,对phase_defused函数进行调试。

  2. 在gdb中设置断点
    在这里插入图片描述

  3. 运行程序,并定位到转折点。
    在这里插入图片描述

  4. 分析转折点
    当我们执行到第6次phase_defused函数,我们不会直接按顺序ret,而是会跳转<phase_defused+50>执行另一段代码。此处的转折点是%eax的值不等于3,我们没有跳转,而顺序执行下文的<phase_defused+101>跳转到<phase_defused+29>,而+29的位置顺序执行就为函数结束位置。所以我们需要%eax等于3,以便能抵达secret_phase的位置。
    我们查看%rsi与%rdi两个参数:
    在这里插入图片描述
    发现3 10是phase_4的破解字符串:
    在这里插入图片描述
    而%d %d %s说明需要输入两个整数一个字符串。所以我们需要在phase_4的答案后面加上一个字符串。

  5. 修改solution.txt,phase_4字符串后面添加随意字符串。
    在这里插入图片描述

  6. 重新运行程序,并定位转折点。
    在这里插入图片描述

  7. 分析转折点
    跳转的原因是strings_not_equal函数的返回值不是0,即参数%rdi与参数%rsi不相同。我们查看%rdi与%rsi的值:
    在这里插入图片描述
    发现,%rdi是我们添加在phase_4答案后的字符串,所以我们修改该字符串为DrEvil。

  8. 修改solution.txt,phase_4的第三个参数改为DrEvil。
    在这里插入图片描述

  9. 重新运行程序,成功进入secret_phase。
    在这里插入图片描述

  10. 在gdb设置断点,开始破解
    在这里插入图片描述

  11. 运行程序,并定位到爆炸点。
    在这里插入图片描述

  12. 分析爆炸点
    爆炸原因为%eax无符号值大于1000,即0x3e8。而%eax是%rax的值-1,我们查看+24行的%rax,发现%rax的值为我们的输入值。所以这里限制我们只能输入1-1000。

  13. 修改solution.txt,secret_phase的字符串为随意1-1000的值。
    在这里插入图片描述

  14. 重新运行程序,并定位到爆炸点。
    在这里插入图片描述

  15. 分析爆炸点。
    爆炸的直接原因是fun7函数的返回值%eax不等于2,没有跳转,而触发了下文的炸弹。我们查看fun7函数:
    在这里插入图片描述
    我们首先了解fun7的参数%esi和%rdi,查看%esi:
    在这里插入图片描述
    发现%esi是我们输入的数字。查看%rdi:
    在这里插入图片描述
    发现%rdi是一个结构,其中储存了一个数据,和两个地址,这是二叉树的结构。我们再来分析fun7函数的终止条件:
    在这里插入图片描述
    我们从中可以看出,函数的终止有两处。一是红色方框内容,判断%rdi节点是否为空,为空就将0xffffffff赋给%eax,然后结束函数。我们需要%eax的值为2,所以我们不能走红色的终止;二是蓝色方框内容,我们要避开两个跳转,一个为%edx大于%esi,一个为%edx不等于%esi。所以我们需要的终止条件为,%edx等于%esi,而%edx的值为%rdi节点存储的数据,所以我们输入的值%esi应该为二叉树某个节点的数据。
    我们将代码分块:
    在这里插入图片描述
    模块1,当%edx大于%esi,就执行mov 0x8(%rdi),%rdi,并执行fun7,最后将%eax * 2。我的理解为,若节点数据大于我们的输入值,则进入左子树,继续执行func7。
    模块2,首先将%eax置零,当%edx不等于%esi,联系上文即%edx小于%esi,就执行mov 0x10(%rdi),%rdi并执行fun7,最后将%eax * 2 +1。所以我们需要执行一次模块2,将%eax从0->1。再执行一次模块1,将%eax从1->2,然后结束函数即可得到返回值%eax为2。
    我们查询节点数值,因为函数递归调用,所以我们先执行模块1(左子树),再执行模块2(右子树)。
    在这里插入图片描述
    所以我们应该输入的值为22,即0x16。

  16. 修改solution.txt,修改secret_phase字符串为22。
    在这里插入图片描述

  17. 重新运行程序,过关。
    在这里插入图片描述

实验总结

过关答案截图:
在这里插入图片描述

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

霖行

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值