CSAPP Bomb Lab 实验记录 [yy-b]

前言

写这个的目的就是想记录一下自己做过的东西,内容可能比较简单,不喜请略过.
写的比较详细,按步骤大概率可重复进行实验.
本次的内容是CSAPP上的实验Bomb Lab.
部分参考了****上的其他一些文章,感谢大佬们

实验环境

  1. MobaXterm
  2. Linux系统
  3. Objdump命令反汇编
  4. GDB调试工具

实验内容

准备阶段

(实验所需材料略)

  1. 登录服务器,解压炸弹压缩包
  2. 进入bomb22目录,反汇编bomb程序,储存为bomb.s
  3. 使用vi查看bomb.s
  4. 再开一个终端,使用gdb调试bomb程序
  5. Ctrl+c暂停调试
    (此处图片[数据删除])

phase_1

  1. vi中使用/main找到主函数
    CSAPP Bomb Lab 实验记录 [yy-b]
    观察到各步骤函数为phase_1,phase_2等等,找到phase_1
    CSAPP Bomb Lab 实验记录 [yy-b]
  2. 逐行翻译phase_1,先开辟栈帧,然后保存了一个地址调用了一个函数(从名字可以猜出是比对字符串的函数),之后返回值不相等就调用另一个函数(从名字可以猜出是爆炸的函数),然后还原栈帧结束,因此先在爆炸函数处设断点防止爆炸:
    CSAPP Bomb Lab 实验记录 [yy-b]
  3. 再找到strings_not_equal函数:
    CSAPP Bomb Lab 实验记录 [yy-b]
    简单看一下就是逐个比字符,猜测phase_1中保存的地址就是要比较的字符串(根据网上查到的攻略的指示,eax返回的是输入的,直接入栈的是比对的,这样推理也可以)
    则用r运行程序,查看此地址,输出为字符串格式:
    CSAPP Bomb Lab 实验记录 [yy-b]
  4. 尝试将此字符串输入,通过了第一关
    CSAPP Bomb Lab 实验记录 [yy-b]

phase_2

  1. vi 中 /phase_2 定位到phase_2
    CSAPP Bomb Lab 实验记录 [yy-b]
    头开始看,压入两个值(?)后开辟栈帧(这块不是太清楚,不过关系不大),然后调用了read_six_numbers函数,从名字猜出是要读六个数字(注意有四个寄存器是默认作为函数的参数的,这里用到了%rsi)
  2. 先来看这个函数:定位到read_six_numbers函数
    CSAPP Bomb Lab 实验记录 [yy-b]
    开辟栈帧后的操作简单来说就是调用者保存寄存器和参数传递,可以不看(对解题意义不大)
    不过要注意一点(根据网上攻略的提醒),在后面调用了一个[email protected]的东西,这个经过观察是来比对读入串的个数的,查看上两行的地址发现:
    CSAPP Bomb Lab 实验记录 [yy-b]
    果然是代表输入六个数字,后面比对个数小于等于5就爆炸
  3. 回到phase_2函数,第345行比对了压入栈的第一个数,其不等于1就爆炸,可知第一个数为1;之后进入循环,循环中每次将后一个数与前一个数比较,如果不是前一个数的两倍则引爆炸弹(这块我只是大概比对了一下),那么这是一个等比数列,尝试输入,通过
    CSAPP Bomb Lab 实验记录 [yy-b]

phase_3

  1. 先定位到此函数
    CSAPP Bomb Lab 实验记录 [yy-b]
    有了上一阶段的经验,我们先来查看第370行给出的地址,即可看到本阶段的输入模式串
    CSAPP Bomb Lab 实验记录 [yy-b]
    可以看出本阶段要输入两个数字,368、369行即输入的两个数字所储存的位置
  2. 第376行向后可以看到,如果输入的第一个数大于7就爆炸,则第一个数小于等于7
  3. 然后第379行根据第一个输入的数字进行寻址,注意是先计算出0x402500 + %rax + 8,再通过*取出地址中的内容,将这个内容作为地址,那么我们查看下这块的地址:
    CSAPP Bomb Lab 实验记录 [yy-b]
    观察发现这是一个跳转表,总的来说就是根据输入的第一个值可以跳到380、382、384……等行,即阶 段3相当于一个switch语句;跳转后紧接着一行改变eax值,再调到398行做判断,如果与第二个输 入的值相等则通过,那么这里应该有7个答案,我们随便取一组,比如第一组0,0x116,也就是输入0 278, 通过
    CSAPP Bomb Lab 实验记录 [yy-b]

phase_4

  1. 定位到phase_4:
    CSAPP Bomb Lab 实验记录 [yy-b]
    还是一样,先查看输入模式串:
    CSAPP Bomb Lab 实验记录 [yy-b]
    要输入两个数字(注意435行,别的函数都是判断>1个数就可以,这里要判断=2个数才行secret_phase处有用)
  2. 首先437行第一个数大于14就爆炸;然后%edx和%esi赋值为14和0,%edi赋值为第一个输入的 数(再次注意这三个寄存器是默认给函数当参数的),这是再下行调用func4函数时传入的第3,第2, 第1个参数
  3. 查看func4函数:
    CSAPP Bomb Lab 实验记录 [yy-b]
    注意到其中多次调用了自己,这应该是个递归函数
    接下来就一步一步翻译就行了,可以还原出其c代码:(其中引入了一个tmp临时变量,是第406行到第412行做的事)
    CSAPP Bomb Lab 实验记录 [yy-b]
  4. 再回到phase_4,调用完func4后返回值要=37(444行),同时第二个输入的数也要是37才能通过,那么我们可以写个c程序枚举一下看第一个数是哪个值:
    CSAPP Bomb Lab 实验记录 [yy-b]
    答案是10,则phase_4的答案是10 37:
    CSAPP Bomb Lab 实验记录 [yy-b]

phase_5

  1. 代码如下:
    CSAPP Bomb Lab 实验记录 [yy-b]
    还是先查看下输入格式串,要输入两个数字
    CSAPP Bomb Lab 实验记录 [yy-b]
  2. 首先是第462行,第一个输入的数与15做按位与,相当于保留输入值的后4位,结合第466行判 定,及第一个数模15不能为0;再之后ecx,edx置零,edx+=1
  3. 注意第471行,是一个寻址,即以第一个数后四位为根据向0x402540后寻址,将此处值存到eax中 (注意eax中能存32位二进制,即8个16进制数;而且是小端存储,即对应下表,当rax=0时eax 存的是0x0000000a),又知最大向后跳转15*4个地址,那么向后取60+4(一个地址中是2个16进 制数)个地址输出成16进制数:
    CSAPP Bomb Lab 实验记录 [yy-b]
    回到原函数,第472行将eax加到ecx上,再拿eax与15比,不等就回到第469行再执行,则edx相 当于一个计数器,ecx是所有eax的和;等于15的话再将15与edx相比,不等就爆炸,也就是说要让 eax在edx=15时等于15;最后将第二个输入的数与ecx相比,相等即通过
  4. 那么通过以上的分析,从第15次eax=15向前倒就可得出第一次的值了,第15次eax=15,那么上 一次eax的值就是6,即0x0f对应的偏移值,依次类推再向前是14,2,1,10,0,8,4,9,13,11,7,3,12,5,则第一 个数是5,再把前面这些都加起来,得115,那么最后的答案是5 115:
    CSAPP Bomb Lab 实验记录 [yy-b]

phase_6

  1. phase_6的代码(好长)
    这段代码不只长,而且相比于前面几段可谓是一顿乱跳,跳转非常多,所以阅读的重点是从头开始先把整段的逻辑结构理清楚
    CSAPP Bomb Lab 实验记录 [yy-b]
    CSAPP Bomb Lab 实验记录 [yy-b]
  2. 首先就来看第489行(前面的都可以不管),开辟栈帧,之后把一个地址传给了read_six_numbers函数,通过第二阶段的经验我们得知这个函数是用来读取6个数字的,那么本阶段的答案应该是6个数字,存在0x30(%rsp)后面的位置,我们用gdb调出来看看:
    CSAPP Bomb Lab 实验记录 [yy-b]
    CSAPP Bomb Lab 实验记录 [yy-b]
    可以看到就是我们输入的六个数字
  3. 492向后的结构我们手画一下(图炸了,见谅):
    CSAPP Bomb Lab 实验记录 [yy-b]
    从中可以看到核心是最后一段(主要是要看出来这是个链表),那么521行给的应该是链表的表头地 址0x6033f0,调用内存查看(同时查看其指向的地址,从而遍历链表):
    CSAPP Bomb Lab 实验记录 [yy-b]
    然后只要将值从小到大排列,再把顺序打一遍即可,程序的作用可以概括为把原链表重新排一遍,值递增则通过
    最后答案为2 6 5 3 1 4
    CSAPP Bomb Lab 实验记录 [yy-b]

secret_phase

  1. 通过攻略我们大概了解到有一个secret_phase,其入口不得而知,通过提示我们知道大概和 phase_defused(每个阶段结束后会进入这个函数)有关,调出其代码:
    CSAPP Bomb Lab 实验记录 [yy-b]
    通过资料和分析得知,中间有一段不寻常,读取了一个字符串,有了经验我们先来看942行地址的东西,这里应该是一个模式串:
    CSAPP Bomb Lab 实验记录 [yy-b]
    这可能就是入口,应该是在两个数字后面输一个字符串来进入,再来看后面这两个地址中的东西:
    CSAPP Bomb Lab 实验记录 [yy-b]
    10 37 是第四题的答案,那么看来就是在这之后输入下面那个字符串就可以了:
    CSAPP Bomb Lab 实验记录 [yy-b]
    成功进入
  2. 先来看secret_phase
    CSAPP Bomb Lab 实验记录 [yy-b]
    开头部分可以看到有两次调用函数,第一次是read_line(),从而可以推断出此关卡应该是一个字符串作为参数(查看函数发现确实如此,不放图了)。随便输入一个测试用gdb单步调试观察第二个调用函数的参数,发现确实是我们输入的字符串:
    CSAPP Bomb Lab 实验记录 [yy-b]
    第二个函数从名字就可以猜出来是把字符串变长整型,验证一下:
    CSAPP Bomb Lab 实验记录 [yy-b]
    那么我们输入的应该还是一个数字
    之后592行调内存看看(直接看没看明白):
    CSAPP Bomb Lab 实验记录 [yy-b]
    再结合593行,得知我们输入的数字要小于1001,不然就爆炸了
    再之后595开始,可以看到往fun7中传递了我们输入的数字和一个地址,fun7返回值为3就成功了
  3. 那么我们来看看fun7:
    CSAPP Bomb Lab 实验记录 [yy-b]
    通过分析后我们手画一下结构:
    (先注意下,568行和575行表明值域后面连续两段都是地址,猜测又是一个链表,其节点长这个样子:
    CSAPP Bomb Lab 实验记录 [yy-b]
    其实这里就可以猜出是个二叉链表了,我们后面验证一下)
    CSAPP Bomb Lab 实验记录 [yy-b]
    从这里我们可以看到,第一次调用fun7 %eax值为0,之后递归调用,共三个出口:一个返回%eax自己 (当esi传入值,也就是我们输入的值与节点的值相同时);第1个地址对应(上图画反了):返回自 己2;第2个地址对应(上图画反了):返回自己2+1。那么这个结构就很明显是一个二叉树了,我 们先来查看二叉 链表的值(根地址就是rdi传进去的那个):
    CSAPP Bomb Lab 实验记录 [yy-b]
    果然是,那么根的值 是0x24,向左为2+1,向右为2(又画反了……):
    CSAPP Bomb Lab 实验记录 [yy-b]
    一直向左或向右查询的话我们很快就可以知道这棵树 有4层(不过我们并不需要知道);为了让最终返回值是3,我们需要(0*2+1)*2+1=3,即向右两次,则查找此节点值就行了:
    CSAPP Bomb Lab 实验记录 [yy-b]
    则答案是0x6b,也就是输入107:
    CSAPP Bomb Lab 实验记录 [yy-b]
    (终于拆完啦!!!)

END

祝您心明眼亮