zucc--二进制炸弹第1,2,3,4,5,6,secret_phase关卡(binarybomb)-

版权声明://若需转载,请各位大虾注明出处,小生在此有礼. https://blog.csdn.net/sos768/article/details/84893207
  • zucc第一届作为计原实验大作业写下来纪念一下
  • (32位地狱(最高难度)完全版
  • 本次大作业花费了博主2天的时间,心累啊
  • 废话不多说,进入整体分析
  • 有兴趣的同学可以通过下载以下源代码跟随这作者的操作来进行操作一次
  • https://download.csdn.net/download/sos768/10921537
    ===================================================================
  • disas phrase_x (观看重定位被整理之后的汇编代码)
  • info r (查看此时各个寄存器的值)

phase_1:

  • 因为是调试完以后才开始写报告,所以截图也在自身调试记录里面进行截取

  • 首先gdb bomb进入调试模式

  • 然后disas phase_1找出关卡1所在的汇编代码

  • 在调用phase_1之前设置断点
    在这里插入图片描述

  • gdb下输入 r 执行程序

在这里插入图片描述

  • abcdef 进行测试,然后找到后进行对比= =这些都是虚的
  • 直接进行phase_1炸弹代码分析
  • 可以看到代码里面调用了string_not_equal方法
  • 相等就跳转,不想等就爆炸,
  • 所以直接p查看一下此时的栈帧

在这里插入图片描述

  • 在这里我是直接按照老师的方法查看栈帧的,
    推荐可以这样写(x /s 0x0804a004),效果和上图是一样的,到这边第一关就成功了

Phase_2:

  • 和第一关一样,先gdb bomb,然后disas phase_2,查看第二关的代码
  • 在这里为了方便截图,就只截取了一部分
    在这里插入图片描述
  • 我们可以发现 调用了read_six_numbers 函数,发现读入的是6个整数数字,如果不符合就跳转爆炸
    -可以发现第二个数字要求为1
    在这里插入图片描述

  • 并且不停的循环将ebx-8 和 ebx-4的数字相加与ebx进行比较,如果不相同就爆炸,然后将ebx加4并进行比较是否已经到达了最后一个数字
    在这里插入图片描述

  • 可以发现,第三个数字必须为1,2两个数字的和,且第四个数字必须为2,3数字的和,所以可以得知整体数字为:
    0 1 1 2 3 5

到这里phase_2也已经完成了

Phase_3:

  • 第三关测试直接放在了bomb.txt上面

  • 为了截图方便,截图将直接进行在bomb.txt文本中

  • 进入正题

  • 首先照旧
    在这里插入图片描述

  • 开辟空间,建立栈帧

  • 可以发现这里有一个sscanf 函数,自然可以推出,在其上方应该有参数传入过程,所以推测后查看其传入参数的类型:

在这里插入图片描述

  • 可以发现参数类型如我在文档里面注释的这样是两个整数

  • 继续往下看,发现这一句代码

在这里插入图片描述

  • 可以推断eax参数 与1比较,若小于等于1,则跳转爆炸,若大于则跳转(eax>1)

  • 还有下面类似的一个语句:
    在这里插入图片描述

  • 意思是一致的:ebp-4的值和7进行比较,若大于7则爆炸(phase_3+0xa2),小于等于7的话,把ebp-4的值放到eax上去

-跳转之后可以发现是一个很熟悉的声明:
在这里插入图片描述

  • ps:我们可以发现在jmp *0x804a03c(,%eax,4) 这边声明之后的语句,不断的在执行移动,跳转,判断的指令,并且地址跳动幅度不大,所以判定为一个switch语句,然后马不停蹄的去看了老师的提示:
    结果符合自己的推断,继续
    在这里插入图片描述

  • 得知是一个switch语句后,所以选取了起始位置进行测试,这里我选取了0,即跳转到8048e59 所在行

  • 发现代码进行了如下操作:
    在这里插入图片描述

在这里插入图片描述

  • 即上方传入的立即数0x289进行了下面的操作:
  • 0x289 + 0x33b -0x3e7+0x3e7-0x3e7+0x3e7-0x3e7
  • 通过计算得知结过为0x11,即十进制的17
  • 进行测试 0 17
    成功
  • 到这里,关卡3就通过了

Phase_4

  • 照旧先看代码

  • 可以发现关卡4和关卡3有很多共同之处,所以就先进行查看了sscanf其输入的类型
    在这里插入图片描述

  • 发现 需要的是两个整数
    在这里插入图片描述

  • 继续往下看:

  • 这里也进一步验证了参数数字为2

  • 并且通过与运算,如果为负数就跳转爆炸,可以得知eax(这里的eax已经被ebp-4覆盖了)应该是个正数,即其中一个参数应该是个正数
    在这里插入图片描述

  • 继续往下看:

  • 将eax这个参数和14进行了比较,如果小于等于14不爆炸,所以这个参数的范围为(0,14]
    在这里插入图片描述

  • 进入func4函数
    在这里插入图片描述

  • 传参数和保护现场部分:

在这里插入图片描述

  • 进行运算模块:

  • 先把传入的eax 14/2的31次,所以eax=0

  • 然后赋值运算

  • 在图里面我写出了所有寄存器在当时运算结束后的值
    在这里插入图片描述

  • 从这里进入n>=7时候的模块 \7-n<=0? ->64(n>=7)
    在这里插入图片描述

  • 跳转后进行下图所示的运算:
    在这里插入图片描述

  • 如果没有跳转,则执行下方运算,可以看到又调用了本身func4,所以这是一个递归运算
    在这里插入图片描述

  • 可以得知这个递归在不断的往中间靠拢,所以在(0,14]范围内选取中间往外的值
    7

  • 跳出func4后继续往下看:

  • 发现汇编里面将返回值和0进行了比较,如果为0就不爆炸退出,所以可知第二个数字为0

  • (其实在这边有一个很简单的方法,因为前面已经知道了范围在0-14之间,写一个脚本在这一步不断run脚本暴力解决就可以了)
    在这里插入图片描述

  • 进行测试 7 0:

  • 惊喜的发现通过了!
    在这里插入图片描述

  • 到这里,关卡4已经结束了

Phase_5

  • 照旧查看代码,并且发现操作一致:
    建立栈帧,然后开辟空间
    在这里插入图片描述

  • 不同的是这里运行了string_length 函数,并且发现call完这个函数后,代码将eax进行了比较,所以这个应该就是此函数的返回值,从这里可以得知,输入的应该是6个字符

-这边进一步证明了上面的结论:
在这里插入图片描述

  • 发现这里开始进行循环
    在这里插入图片描述
    操作从 eax=edx+ebx-1这边就可以看出来,明显是在取出第一个字符(此时edx=1,且ebx(ebp+8)为起始地址),不断的进行与运算后,与从地址(0x804a05c+与运算完的结果)的地址里面取出字符

  • 这个时候我们先x / s 看一下 0x804a05c 里面存放的字符

    在这里插入图片描述

  • 然后继续往下看发现,我们运算完的地址还要和0x80484d0进行比较,所以查看一下存放了什么字符
    在这里插入图片描述

  • 查看:esp-4的值:发现为oilers,所以必须与这个一致,同时,也从上面那个地址存放的字符里面确定,o,i,l,e,r,s所存在的位置,分别为:10,4,15,5,6,7,转换为16进制:a 4 f 5 6 7,因为是与0xf做与运算,所以只需要lsm一致,所以前一位任取.
    这里我选择了:3a 34 3f 35 36 37
    查询ascii表对应为:4?567
    在这里插入图片描述

  • 进行测试
    在这里插入图片描述成功

  • 到这里,phase_5就结束了

Phase_6

  • 首先照旧获取代码

  • 可以看出代码很长,所以分块进行分析

  • 首先还是一样的读取了参数

  • 并且可以从中可以看出调用了方法读取6个数字
    在这里插入图片描述

  • 继续往下看:发现进行了跳转,不断的有代码段从下面循环到上方,且eax-1-5<=0,否则会爆炸,且可以分析出是6个不同的整数,所以基本可以确定为(1-6数字)
    在这里插入图片描述

  • 继续往下看,发现一个小循环,esi+4-5<=0就向上跳转,发现%eax变为edx+edi4-4
    Edx+4
    (edi-1),看到这边是不是觉得很熟悉,结合之上的分析,得出代码里面是一个6个节点构成的链表,但还是不知道关系,暂定为data[6]
    在这里插入图片描述
    在这里插入图片描述

  • 接着往下看发现,lea -0x24(%ebp),%edx,推测为当前数据地址赋值为edx ,即为%edx=&data[i],并且ebx+1,并且 %eax的值减去%edx+4%ecx*4-4的赋值给了%eax,这里还看不出具体的关系,只能明确两个值不能相等,否则跳转到105重新开始
    在这里插入图片描述

  • 接着往下看,索引转换,进行小循环
    在这里插入图片描述

  • 从这里可以发现,会将当前节点和下一个节点进行比较,而且必须当前节点的值必须大于下一个节点才符合,否则爆炸,并且使得大的数成为当前的节点,也就是说,这边必须按照一定的顺序,也就是降序排列,并且把所得的值存入了节点空间,可以发现0x08048ca0段进行了跳转105,所以这时候可以回到,上方的105段。
    在这里插入图片描述

  • 可以看出节点输入开始后,减法,加法操作之后,便会和7进行比较,不等于重新跳回105
    在这里插入图片描述

  • 并且从这里可以发现节点是以8个步长进行储存的
    在这里插入图片描述

  • 分析得到第一个节点的位置,分别查看得知节点地址此时存储的值
    在这里插入图片描述

  • 即 Node1—0x1fd 转化为10进制分别为:509
    Node2—0x111 273
    Node3—0x223 547
    Node4—0x1ef 495
    Node5—0x0d7 215
    Node6–0x263 611
    进行降序排列为:6 3 1 4 2 5
    因为还和7进行了比较,所以最终结果应为7-n:1 4 6 3 5 2
    在这里插入图片描述

  • 进行测试:
    在这里插入图片描述成功

  • 到这里,phase_6关卡就结束了

Secret_phase

  • 首先找寻代码段,发现只有在<phase_defuse>函数中可以进入秘密关卡,所以首先我们从这里入手,寻找进入秘密关卡的条件,

  • 仔细观看代码,可以在这里发现,在这里有一个地址里面的值和6进行比较,所以就进行了调试,在每个关卡设置断点发现,每次通过一个关卡,这个值就会加1
    在这里插入图片描述

  • 结合这一部分可以得知秘密关卡只有在第6关通过之后,才可以进入,否则不等于6的话会跳过秘密关卡
    在这里插入图片描述

  • 继续看下去发现这里eax和3进行了比较,(所以需要在第四关插入所需要的参数才会进入隐藏关卡,否则不会等于3)而eax 是sscanf函数读取参数的个数
    在这里插入图片描述

  • 而sscanf函数读取的类型储存在0x804a06c里面,所以查看了一下类型:
    在这里插入图片描述

  • 结果发现需要我们去输入一个字符串,从后面的函数 string_not_equal中发现,读入的字符串保存在0x804a075中,查看后发现字符串为”DrEvil”
    在这里插入图片描述

  • 之后在phase_4原先的答案后面加上了进入了隐藏关卡所需要的字符串后成功进入隐藏关卡,
    在这里插入图片描述
    =====================================================================================

  • 进入隐藏关卡其实还有一种很耍赖的方法,就是在gdb调试的时候,在上方cmp $0x3,%eax前面设置断点,然后在这个时候什么都不用管,直接改变eax的值为3,然后run®,在下一步eax=0前面也设置断点,同然直接改变eax的值为0,接着再run,就直接进入隐藏关卡了

  • 改变方法就是 set %eax=3

  • (偷偷钙素你们,这个方法可以度过所有的关卡-- 》 --)
    ======================================================================================

  • 知道了怎么进入隐藏关后,开始着手破解隐藏关卡:

  • 分析秘密关卡的汇编代码:

  • 从这一行分析出,调用了strtol_internal 函数,加上上方传入的参数
    分析得出原型----->strtol(%eax,NULL,10),得知输入的是一个10进制数字
    在这里插入图片描述
    在这里插入图片描述

  • 可以发现输入的10进制数字要<=1001
    —>%eax-1-0x3e8<=0->%eax<=0x3e9(1001)
    在这里插入图片描述

  • 并且其调用了fun7函数,根据代码,其返回值必须为2才不会爆炸
    在这里插入图片描述

  • 进入fun7分析一下

  • 照旧输入参数,分别设定为第一个参数a和第二个参数b
    在这里插入图片描述

  • 从图中标注的代码行这里知道,如果传入的参数*a>b,将(esp+4)传入参数也就是(a+4),进行递归,并且递归返回值加倍
    在这里插入图片描述

  • 分析下一段代码发现也有相对应的一段,如果*a<b,就把(a+8)传入作为参数,
    并且递归返回值加倍后加1
    在这里插入图片描述

  • 分析完fun7 后,回转主程序段,现在已经知道了返回值必须为2
    所以进行反递归计算如图,
    在这里插入图片描述

  • 也就是说这二次递归中,两种情况分别进行了一次,按照顺序为,先(若a>b,则传入a+4),然后为(若a<b,则传入a+8)

  • 使用gdb查看了一下储存值发现了我们所需要的值(0x804b5f8为最开始传入的参数0x24)
    在这里插入图片描述

  • 0x16 ,转换为10进制为6+16=22,进行测试;

在这里插入图片描述成功

  • 到这里,所有关卡都已经通过了
  • 本次大作业报告在这里也已经圆满结束了

参考链接:

猜你喜欢

转载自blog.csdn.net/sos768/article/details/84893207