CSAPP Lab2 实验记录 —- Bomb Lab(Phase 1 – Phase 6详细解答 + Secret Phase彩蛋解析)

CSAPP Lab2 实验记录 —- Bomb Lab(Phase 1 – Phase 6详细解答 + Secret Phase彩蛋解析)前引今天是除夕然后平时摸着摸着鱼把CSAPP前三章看完了(浮点那里跳着看完的)因为学习第三章之前学过大部分王爽的汇编语言(就是因为要学CSAPP才学的汇编)然后看第三章相对第一遍初略看的时候简直不要太舒服就至少能看懂能做大部分CSAPP例题了刚开始没学汇编的时候里面是啥我都不知道也就导致我第一次看第三章的时候懵懵懂懂不知所以也就啥都没学进去~聊点其他的题外话吧反正寒假说学的有多认真倒也不一定感觉还是边耍边学的吧Leetcode今天也还没有刷题晚上也要玩游戏打ow


Lab 总结博客链接

CSAPP Lab入门系统安装摸索+Lab 博客链接


实验前提引子


这部分是我在大一寒假的时候写的 那个时候只写了Phase 1 - 5 没有做出来Phase 6 现在大二开学没几周 过来重新把Phase 6给完成了 算是弥补原来没有写出来的遗憾吧 那前面的Phase 1 - Phase 5的讲解 我就不再重新编辑了 那个时候感觉自己写的还是蛮好的 后面的Phase 6才是二次编辑讲解的 maybe原来有些地方的小理解有点问题 那就烦请Forgive Me一下了呜
Phase 6特此过来说明一下^^

各位继续往下看吧

这个引子是为了给一些这个实验还没有入门的hxd看的
因为这个实验直接拿给一个phase都还没过的人 干什么都是不知道的
这个实验入门还是挺简单的 所以大家可以对于前两个phase 可以看一下我是怎么解题的 大概流程或者操作熟悉一下
对于后面拆炸弹你可能就自己是懂得怎么解决了
过掉两个phase是不会影响这个Lab对你能力的提升的
所以对于前两个phase我会很详细的 把我怎么做的思路一步步都讲出来
对于后面3、4、5、6 四个phase我可能会稍微没有那么仔细的分析了

CSAPP Lab2 实验记录 ---- Bomb Lab(Phase 1 - Phase 6详细解答 + Secret Phase彩蛋解析)

需要什么指令 还有需要还有什么其他的 我都会在下面详细的给出来的


实验需要指令及准备


我们首先把 Bomb-Lab 给解压了
在这里插入图片描述


得到Bomb的文件夹 打开里面有三个文件 除了 bomb.asm反汇编文件
在这里插入图片描述

在这里插入图片描述

然后我们需要什么呢 首先要安装Gdb调试器 对于Ubuntu而言
打开终端 直接输入sudo apt-get install gdb 然后截图是下面的

在这里插入图片描述


然后就进入 bomb文件夹
我们可以先看看read文件 bomb.c文件可以不看 因为你看了也没有什么用qwq 看了你也不晓得在说什么(有彩蛋的)
到最后我们都是通过gdb调试器来运行bomb文件 来进行调试
下面先给出gdb调试器的一些指令 是我们后续需要用到的
这里先给出来 不需要全部记下来 后面我会用到的 再讲用法
这些指令我都是复制过来的
基本上都是要用到的

  r  运行程序

  b <*0x某某某>    在某个地址设置断点,具体哪里,可以看反汇编的代码,可以根据那个直接复制粘贴设断点的

  d 删除所有断点

  d <断点号>    删除指定断点

  info b    查看所有断点信息

  continue 从断点处继续执行

  display <$寄存器>    跟踪寄存器,碰到断点停下时会显示出所有跟踪的寄存器的当前值,非常好用的一个命令,注意的是gdb中表示寄存器的话前面用的不是百分符号%,而是美元符号$

  x/参数 <地址>    访问地址的内存,其实就是间接访问,也是很好用的指令,关于参数,s是输出为字符串,d为输出为十进制,x为输出为十六进制,b、w、l、q控制输出字节,默认是w,四字节,s字符串不受这个控制除外。

  info r    查看所有寄存器的值
  print (可加强制转换符号)<数字>	跟C语言的基本性质一样的,理解即可

然后我们提前生成Bomb.c的反汇编文件
为什么要生成 因为后面是需要用的 到后面需要怎么用的时候再讲
我们只需要生成一次 在终端输入objdump -d bomb > bomb.asm
就能看到 在bomb文件夹多出来了一个这样子的文件

在这里插入图片描述
ok 我们进入我们的紧张刺激的拆炸弹phase环节哈哈哈哈哈 (finally gogogo!)
在这里插入图片描述


Phase 1


我们先通过gdb 载入bomb文件 终端输入gdb bomb 然后就会出现这样子的状态
在这里插入图片描述


我们可以先运行一下这个bomb软件 直接输入r即可
然后就出现下面炸弹 have 6 phases with which to blow ourselves up

在这里插入图片描述


我们可以试一下 输入自己想输入的 让不让我们通过
比如 dontletmebomb

在这里插入图片描述
可是事不如我们所预期的 bomb了 那我们如何躲开炸弹爆炸通过呢
我们只能查看我们的反汇编语言来寻找蛛丝马迹了

这个时候反汇编我们之前生成的bomb.asm就有用武之处了
那我们打开bomb.asm
建议复制一份到windows 因为在ubuntu是只读的
然后不好打备注 打开之后我们先来到Phase_1段落处

在这里插入图片描述


我们这个时候来仔细分析分析
在这里插入图片描述

第一行代码 把栈指针减少了8 是为了给局部变量提供空间
与最后一行addq $0x8 相对应 函数都是会回收栈指针的
第二行代码向寄存器 esi给了0x402400的数据
第三行就是调用函数 strings_not_equal
看函数名字 我们应该能判断出来 这个函数是看我们输入的字符串和这个程序的其中的哪个字符串是否相同
然后我们再往后看看第四行代码 就是test eax寄存器是否有数
根据我们之前理解到的 rax寄存器一般里面存放的是函数的返回值
eax寄存器不过就是rax的低32位表示而已

哦? 这就有意思了 我们不难分析出 当rax寄存器当值等于0的时候
即可满足第五行代码的跳转指令
跳转指令跳转到400ef7处 然后是跳过了 400ef2处的指令

我们仔细看一下400ef2的指令 调用函数 explode_bomb
xdm 看函数名懂得都懂 爆炸指令 则我们可以得到下面的信息

如果当rax寄存器值不等于0的时候
我们不会跳转 就会来到400ef2处 就会调用爆炸函数 我们就会起飞

在这里插入图片描述

唯一的方法就是 我们输入的字符串和其中存储的一个字符串相等
相等的话 string_not_equal 返回值就会是0
不相等可能会返回1
(在c语言中 0有false的意思 1也有true的意思 即满足相等 函数返回false)


说了那么多 我们仔细看一下这两行代码
在这里插入图片描述
这里是为什么会向寄存器放入这个 0x402400呢
因为显然 程序是不肯定把提前准备好的字符串藏到其他很深的地方的
那不然我们怎么拆炸弹啊哈哈哈哈哈
我们就可以调查这个地方


有两个办法 因为是字符串
首先是 第一个是直接通过gdb调试看
print (char*)0x402400
我们一个一个试一下

在这里插入图片描述
哦哟 不错哦~ 出现了一串字符串~
这个可能是正确答案 我们先记下来
Border relations with Canada have never been better.
我先把下面一个方法介绍一下 再去核对一下这个答案是否是正确的

第二种是通过设置断点在349行代码处 此时已经经过了
mov 0x402400, $esi这行指令了

我们先输入b *0x400ee9 设置断点
然后我们先重新重新运行程序 输入r
然后随便输入一串字符串abcde
当程序运行到断点处自动停止 此时我们就可以看一下esi寄存器里面的数据了然后通过指令 x/s $esi 看寄存器中存放数据 这里的s就是字符串哈

在这里插入图片描述


两种办法介绍完了 我们现在就去重新运行验证一下 字符串正确与否
在这里插入图片描述
ok 终于拿下了~ 拿下(破音) 有了phase的经验
后面的拆炸弹相比也有一定经验了

如果觉得自己经过phase_1理解了拆弹流程了
真的想自己拆弹的话 建议phase_2就可以开始自己拆了 不用再跟着实验记录
如果觉得自己还没有拆弹的感觉 怕被炸飞的
可以继续跟着实验记录走一波
反正我是看完人家的phase_1之后的 phase_2就是全自己推了

ok 那我们来到phase_2继续当拆弹专家:)
在这里插入图片描述

拆弹密码1
Border relations with Canada have never been better.


Phase 2


在这里插入图片描述
老规矩 分析一下吧
357 358行 存放寄存器状态
359行提供局部变量空间
360行把我们的栈指针状态存入到rsi寄存器中

然后继续往下看到 callq read_six_numbers 看函数名字是读取六个数字 我们这边可以先试一下输入六个数字
在这里插入图片描述


不错的昂~ 炸弹成功炸掉 扣了HP-1 可惜我们的HP为99999999
而且还是god mode 说明这个phase不仅仅只是输入6个数字那么简单
要想仔细分析一下 我们就需要去函数 read_six_numbers代码区一探究竟
发现为40145c

有个快捷键 ctrl+f 我们可以搜索关于这个的文字
啪的一下很快嗷 我们就到了这个代码区

在这里插入图片描述


在这里插入图片描述

我们可以逐行的再来分析一下这个函数
首先栈指针减少24 从中我们可以不难得出 24刚好是6个int整形数字所需要的字节数
然后后面到814行之前应该是把6个整形数字的地址放到各个寄存器中


然后我们注意814行— 817行之间
首先816行有个调用函数 scanf 我们可以稍微去看一下这个函数

在这里插入图片描述
emmm 这个函数又跳转到其他位置
然后我之后再400bf0这里设置了一个断点
然后info r看了一下 寄存器rip 跳转地址看了记得是0x600000(可能有误)
但是反正也不需要去搞懂
这个应该就是跟c语言 scanf函数一样的


然后我们返回814行代码 有没有想到c语言我们调用scanf函数
我们需要首先给出 我们输入格式 比如%d %d %d %d
联系到第一题 我们可以调查一下 我们不难联想到 这个向esi转入的数字
可能就是 我们输入格式
说干就干
在终端输入
print (char*)0x4025c3

在这里插入图片描述


不错的昂 这里也分析出了确实是6个数字
这里还有个小细节也能分析出来至少是大于5个数字的
就是817行 rax装的是scanf函数的返回值
如果小于等于5 也会引发炸弹爆炸
对于输入数字的问题 我们就解决了


在这里插入图片描述
再返回phase_2
首先可以判断 当rsp间接引用的内存地址必须要等于1
通过我的两次尝试再加上一定的理性判断 可以判断出
(%rsp)装的肯定是我们输入6个数的第一个数
那么 0x4(%rsp)就是第二个数 0x8(%rsp)是第三个数

我们输入的数第一个就必须是1 跳转到400f30
接下来的分析我就快速分析一下了 rbx装2号数 rbp装6号数
跳转 400f17 下面就类似数学小学数学问题了
我用c语言来概括一下下面的代码在干什么

int i;
int a[6];
a[0] = 1;
for(i=1;i<6;i++)
{ 
   
	a[i] = a[i-1]*2;
}

还是不难分析的 最后就能成功得到6个数字为 1 2 4 8 16 32
我们重新开始实验 测试一下是不是这个数字
在这里插入图片描述

ok 拆弹专家level is becoming higher了嗷
我这边实际写博客的时间远比我解题的时间多qwq
但是接下来的四个phase 我不会再像这个样子 一点一点分析了
但是也会记录下来我的一些想法 关键步骤

在这里插入图片描述
拆弹密码2

1 2 4 8 16 32


Phase 3


0000000000400f43 <phase_3>:

//给局部变量腾出空间 把两个数据内存地址移向两个寄存器
  400f43:	48 83 ec 18          	sub    $0x18,%rsp
  400f47:	48 8d 4c 24 0c       	lea    0xc(%rsp),%rcx
  400f4c:	48 8d 54 24 08       	lea    0x8(%rsp),%rdx

//调查输入格式because 400f5b调用了scanf函数
//print (char*)0x4025cf
//得到%d %d 即为输入两个数
  400f51:	be cf 25 40 00       	mov    $0x4025cf,%esi    
  400f56:	b8 00 00 00 00       	mov    $0x0,%eax
  

//调用scanf函数
  400f5b:	e8 90 fc ff ff       	callq  400bf0 <__isoc99_sscanf@plt>

//也可从这里印证 返回值需要大于1
  400f60:	83 f8 01             	cmp    $0x1,%eax

//跳转400f6a
  400f63:	7f 05                	jg     400f6a <phase_3+0x27>
  400f65:	e8 d0 04 00 00       	callq  40143a <explode_bomb>

//因为只有两个数 我们从开头发现有个0x8(%rsp) 还有个0xc(%rsp)内存调用进入了寄存器
//所以我们不难推测出 这个0x8(%rsp)可能是第一个数
//通过两次断点尝试 我们肯定出这个是第一个数
//不碰炸弹条件需要小于等于7 
  400f6a:	83 7c 24 08 07       	cmpl   $0x7,0x8(%rsp)

//跳转400fad 如果大了即跳转 跳转地址为调用引爆炸弹指令
  400f6f:	77 3c                	ja     400fad <phase_3+0x6a>

//这里我还是花了点时间分析的
//下面很多重复的移动 
//这里不妨可以联系到类似跳转表
//因为我知道400f75也是跳转到一个地址 我计算出来在整个反汇编文件上限都没有
//那么我想到书里面有个跳转表 是通过自己减去一部分的地址 比如0~7的
//可能计算地址为100~107 通过减去100而到相对于的地方
//这里可以通过观察得到 刚好有7个跳转重复的 我们可得到应该第一个数范围应该是0~7 但最搞笑的是 应该是0~7 可是当我代入测试数据的时候
//不知道为什么 当第一个数为1的时候 是不存在的 我认为可能是设置数据没设计好的问题
//这里存在Bug
  400f71:	8b 44 24 08          	mov    0x8(%rsp),%eax//第一个数
  400f75:	ff 24 c5 70 24 40 00 	jmpq   *0x402470(,%rax,8)
  400f7c:	b8 cf 00 00 00       	mov    $0xcf,%eax//0 0xcf = 207
  400f81:	eb 3b                	jmp    400fbe <phase_3+0x7b>
  400f83:	b8 c3 02 00 00       	mov    $0x2c3,%eax//2 0x2c3 = 707 
  400f88:	eb 34                	jmp    400fbe <phase_3+0x7b>
  400f8a:	b8 00 01 00 00       	mov    $0x100,%eax//3 0x100 = 256
  400f8f:	eb 2d                	jmp    400fbe <phase_3+0x7b>
  400f91:	b8 85 01 00 00       	mov    $0x185,%eax//4 0x185 = 389
  400f96:	eb 26                	jmp    400fbe <phase_3+0x7b>
  400f98:	b8 ce 00 00 00       	mov    $0xce,%eax//5 0xce = 206
  400f9d:	eb 1f                	jmp    400fbe <phase_3+0x7b>
  400f9f:	b8 aa 02 00 00       	mov    $0x2aa,%eax//6 0x2aa = 682
  400fa4:	eb 18                	jmp    400fbe <phase_3+0x7b>
  400fa6:	b8 47 01 00 00       	mov    $0x147,%eax//7 0x147 = 327
  400fab:	eb 11                	jmp    400fbe <phase_3+0x7b>
  400fad:	e8 88 04 00 00       	callq  40143a <explode_bomb>
  400fb2:	b8 00 00 00 00       	mov    $0x0,%eax
  400	fb7:	eb 05                	jmp    400fbe <phase_3+0x7b>
  400fb9:	b8 37 01 00 00       	mov    $0x137,%eax

//跳转后要求 之前移入eax的数等于我们输入的第二个数
//上面已经把所有第一个数对应第二个数 标注了出来
//这道题的结果应该是有7种 有一种数据没设计进去 随意输入一种即可通过
  400fbe:	3b 44 24 0c          	cmp    0xc(%rsp),%eax
  400fc2:	74 05                	je     400fc9 <phase_3+0x86>
  400fc4:	e8 71 04 00 00       	callq  40143a <explode_bomb>
  400fc9:	48 83 c4 18          	add    $0x18,%rsp
  400fcd:	c3                   	retq   

拆弹密码3

0 207; 2 707; 3 256 ;4 389; 5 206; 6 682; 7 327


Phase 4


000000000040100c <phase_4>:
  40100c:	48 83 ec 18          	sub    $0x18,%rsp
  401010:	48 8d 4c 24 0c       	lea    0xc(%rsp),%rcx
  401015:	48 8d 54 24 08       	lea    0x8(%rsp),%rdx

// %d %d 输入格式
  40101a:	be cf 25 40 00       	mov    $0x4025cf,%esi 
  40101f:	b8 00 00 00 00       	mov    $0x0,%eax
  401024:	e8 c7 fb ff ff       	callq  400bf0 <__isoc99_sscanf@plt>
  401029:	83 f8 02             	cmp    $0x2,%eax
  40102c:	75 07                	jne    401035 <phase_4+0x29>

//第一个数小于等于14
  40102e:	83 7c 24 08 0e       	cmpl   $0xe,0x8(%rsp)
  401033:	76 05                	jbe    40103a <phase_4+0x2e>
  401035:	e8 00 04 00 00       	callq  40143a <explode_bomb>

//edx 14
  40103a:	ba 0e 00 00 00       	mov    $0xe,%edx

//esi 0
  40103f:	be 00 00 00 00       	mov    $0x0,%esi

//edi 第一个数 esi 0 edx 14 

  401044:	8b 7c 24 08          	mov    0x8(%rsp),%edi
  401048:	e8 81 ff ff ff       	callq  400fce <func4>
  40104d:	85 c0                	test   %eax,%eax

//edi 7 esi 0 edx 14 eax 0 ecx 7
  40104f:	75 07                	jne    401058 <phase_4+0x4c>

//第二个数为0
  401051:	83 7c 24 0c 00       	cmpl   $0x0,0xc(%rsp)
  401056:	74 05                	je     40105d <phase_4+0x51>
  401058:	e8 dd 03 00 00       	callq  40143a <explode_bomb>
  40105d:	48 83 c4 18          	add    $0x18,%rsp
  401061:	c3                   	retq   


0000000000400fce <func4>:

//edi 第一个数 esi 0 edx 14 eax 14 ecx 14
//edi 第一个数 esi 0 edx 14 eax 7 ecx 0
//edi 第一个数 esi 0 edx 14 eax 7 ecx 7
//edi 0~7 esi 0 edx 14 eax 7 ecx 7

  400fce:	48 83 ec 08          	sub    $0x8,%rsp
  400fd2:	89 d0                	mov    %edx,%eax
  400fd4:	29 f0                	sub    %esi,%eax
  400fd6:	89 c1                	mov    %eax,%ecx
  400fd8:	c1 e9 1f             	shr    $0x1f,%ecx
  400fdb:	01 c8                	add    %ecx,%eax
  400fdd:	d1 f8                	sar    %eax
  400fdf:	8d 0c 30             	lea    (%rax,%rsi,1),%ecx

//这里限制了edi 小于等于rcx
  400fe2:	39 f9                	cmp    %edi,%ecx
  400fe4:	7e 0c                	jle    400ff2 <func4+0x24>
  400fe6:	8d 51 ff             	lea    -0x1(%rcx),%edx
  400fe9:	e8 e0 ff ff ff       	callq  400fce <func4>
  400fee:	01 c0                	add    %eax,%eax
  400ff0:	eb 15                	jmp    401007 <func4+0x39>

//edi 0~7 esi 0 edx 14 eax 0 ecx 7

  400ff2:	b8 00 00 00 00       	mov    $0x0,%eax

//这里限制了edi 大于等于rcx
//得到即edi只能等于rcx 7
//edi为第一个数 即第一个数为7
  400ff7:	39 f9                	cmp    %edi,%ecx
  400ff9:	7d 0c                	jge    401007 <func4+0x39>
  400ffb:	8d 71 01             	lea    0x1(%rcx),%esi
  400ffe:	e8 cb ff ff ff       	callq  400fce <func4>
  401003:	8d 44 00 01          	lea    0x1(%rax,%rax,1),%eax
  401007:	48 83 c4 08          	add    $0x8,%rsp
  40100b:	c3                   	retq

拆弹密码4

7 0


Phase 5


我的Phase4 和我的Phase5都是
刚解出来 我就跑过来写解答了
相对于Phase4 我认为Phase5的难度是上升了一个台阶
因为我分析起来 Phase4可能就花了不到20分钟
我自认为还是没有什么难度的
而Phase5相比来说 我花了更多时间去看
相关寄存器的数据和其他的东西 去尽量搞懂每行代码在干什么
正好趁我手感火热 赶快就把博客写了

这部分我就不能仅仅把那个备注给写了 还是觉得有必要写的详细一点
一步步来吧

在这里插入图片描述


0000000000401062 <phase_5>:

  //储存rbx寄存器状态 减少栈指针为局部变量提供空间
  401062:	53                   	push   %rbx
  401063:	48 83 ec 20          	sub    $0x20,%rsp

  //没有搞懂fs:0x28是啥 但反正设置断点得到fs:0x28为0
  401067:	48 89 fb             	mov    %rdi,%rbx
  40106a:	64 48 8b 04 25 28 00 	mov    %fs:0x28,%rax
  401071:	00 00 
  401073:	48 89 44 24 18       	mov    %rax,0x18(%rsp)

  //异或设置rax为0
  401078:	31 c0                	xor    %eax,%eax

  //调用函数 检测字符串长度 与下面一条指令 则说明字符串需要长度为6
  40107a:	e8 9c 02 00 00       	callq  40131b <string_length>
  40107f:	83 f8 06             	cmp    $0x6,%eax
  401082:	74 4e                	je     4010d2 <phase_5+0x70>
  401084:	e8 b1 03 00 00       	callq  40143a <explode_bomb>
  401089:	eb 47                	jmp    4010d2 <phase_5+0x70>

  //rbx位置存放着第一个数字位置
  //下面四条指令的作用就是 rdx取的是字符的低四位
  40108b:	0f b6 0c 03          	movzbl (%rbx,%rax,1),%ecx
  40108f:	88 0c 24             	mov    %cl,(%rsp)
  401092:	48 8b 14 24          	mov    (%rsp),%rdx
  401096:	83 e2 0f             	and    $0xf,%edx
  
  //这个时候我不知道这条指令是干嘛的
  //直接调用指令 x/s 0x4024b0 出现一串字符串
  //maduiersnfotvbylSo you think you can stop the bomb with ctrl-c, do you
  //这个指令是干什么呢 也就是把这个语句中的一个字符 转移到rdx中
  //字符定位就在地址 0x4024b0再加上我们之前输入的某个字符的低四位
    401099:	0f b6 92 b0 24 40 00 	movzbl 0x4024b0(%rdx),%edx
  
  //这个语句又是把maduiersnfotvbylSo其中一个字符转移到 一个地址
  4010a0:	88 54 04 10          	mov    %dl,0x10(%rsp,%rax,1)
  
  //最刚开始rax一直为0 现在加+1
  4010a4:	48 83 c0 01          	add    $0x1,%rax
  
 
  //与6相比较 如果不等于6的话 循坏又到0x40108b位置处
  //这里的意思就像c语言中 for(i=0;i<6;i++) 
  //我们先看看如果rax为6之后又是怎么样了
  4010a8:	48 83 f8 06          	cmp    $0x6,%rax
  4010ac:	75 dd                	jne    40108b <phase_5+0x29>

  //我一看到这里 我们把这四条指令一起看
  //第四条指令调用 判断字符串是否相等 而第二条又是向寄存器存放了一个不晓得什么的东西
  //这个时候我大胆估计 这个esi装的就是我们需要匹配的字符串
  //print (char*)0x40245e 得到字符串为flyers
  //诶这里的 我们需要匹配的flyers字符串也刚好是6个字符
  //那和我们输入的6个字符又有什么联系呢
  4010ae:	c6 44 24 16 00       	movb   $0x0,0x16(%rsp)
  4010b3:	be 5e 24 40 00       	mov    $0x40245e,%esi
  4010b8:	48 8d 7c 24 10       	lea    0x10(%rsp),%rdi
  4010bd:	e8 76 02 00 00       	callq  401338 <strings_not_equal>

  //当字符串相等后 返回值为0 跳转到4010d9
  4010c2:	85 c0                	test   %eax,%eax
  4010c4:	74 13                	je     4010d9 <phase_5+0x77>
  4010c6:	e8 6f 03 00 00       	callq  40143a <explode_bomb>
  4010cb:	0f 1f 44 00 00       	nopl   0x0(%rax,%rax,1)
  4010d0:	eb 07                	jmp    4010d9 <phase_5+0x77>

  //eax置0
  4010d2:	b8 00 00 00 00       	mov    $0x0,%eax
  4010d7:	eb b2                	jmp    40108b <phase_5+0x29>

  //这里不知道在干什么 但我们看到4010e9位置调用 stack_chk_fail函数
  //这里应该是检查堆栈是否溢出或者是也有什么地方不相同
  //反正重心应该也不会在这里
  4010d9:	48 8b 44 24 18       	mov    0x18(%rsp),%rax
  4010de:	64 48 33 04 25 28 00 	xor    %fs:0x28,%rax
  4010e5:	00 00 
  4010e7:	74 05                	je     4010ee <phase_5+0x8c>
  4010e9:	e8 42 fa ff ff       	callq  400b30 <__stack_chk_fail@plt>

 //这里调用函数结束 炸弹也就成功拆除了
  4010ee:	48 83 c4 20          	add    $0x20,%rsp
  4010f2:	5b                   	pop    %rbx
  4010f3:	c3                   	retq   

ok 这里就是连接着上面代码段 已经分析出了
maduiersnfotvbylSo you think you can stop the bomb with ctrl-c, do you
这个代码了
然后我们来仔细分析一下
那个时候我是这样揣测的
因为要循坏六次 然后六次都把这个字符串的一个字符送到一个地址
后面还要进行匹配 那么 我们送到那个地址的字母
按照顺序 就应该是
f l y e r s

但是哪个字符送出去 决定权在于我们六个输入的字符的后四位

ok 我们把大概思路理清了 我们就在字符串定位即可
第一个字符 f位置在字符串地址开始 9号位 即确定后四位为9

我们的一个ASCII的字符是有一个字节长 也就是8位
后四位确定了 但是前四位没有确定 最开始的位置是符号位0
那么有三个位置不确定的 ASCII字符大小最小是32 32为空格

按照这种逻辑 我们可以列出来多个组合方式
就拿第一个举例子
32+16+9 = 57 ; 64+32+16+9 = 121 ; 32+9 = 41; 64+32+9 = 105;
64+9 = 73等等等等… 然后我们在ASCII表上找到对应的符号即可…

我这里就贴一个我满足条件的一个字符串
9?>567

最终拆弹密码可能有上百种组合
我这列出来我的一种

9?>567

去尝试一下呢 OK 拿下~
在这里插入图片描述


Phase 6


我大概是在6点钟左右开始动工 在晚上8点20左右就最终完成了Phase 6
现在我的感受只有两个 第一个是确确实实 大一一年的磨练与学习 能力真的提高了不知道多少 真真实实感受到了自己的进步与蜕变 第二个是 老美真的是不得不佩服 人家老师的题目的构思 以及实验设计的精巧

这个实验确实比较的困难 做出来可能真的首先需要耐心 第二个就是对于汇编语言真的掌握的比较熟练 还有就是对于GDB调试比较熟练 做这个Phase会用到GDB调试 好了 废话不多说了 今天本来打算晚上看虚拟内存的 然后完成Malloc Lab 但是过来做Phase 6了 吃了饭回来就没时间了 那只能明天来弄咯


Phase 6的话 细节很多 我们一部分一部分来剖析吧 比较是二次编辑 还是想写好一点 那下面走起了


第一部分主要是来判断是否为6个数字 如果小于6个数字 Bome 大于6个数字也 Bome 必须是刚好6个 比较容易看出来 就不介绍了

00000000004010f4 <phase_6>:
  4010f4:	41 56                	push   %r14
  4010f6:	41 55                	push   %r13
  4010f8:	41 54                	push   %r12
  4010fa:	55                   	push   %rbp
  4010fb:	53                   	push   %rbx
  4010fc:	48 83 ec 50          	sub    $0x50,%rsp            // rsp 开了 80字节的栈
  401100:	49 89 e5             	mov    %rsp,%r13            
  401103:	48 89 e6             	mov    %rsp,%rsi
  401106:	e8 51 03 00 00       	callq  40145c <read_six_numbers>
  40110b:	49 89 e6             	mov    %rsp,%r14             // r14 = rsp
  40110e:	41 bc 00 00 00 00    	mov    $0x0,%r12d
  401114:	4c 89 ed             	mov    %r13,%rbp
  401117:	41 8b 45 00          	mov    0x0(%r13),%eax
  40111b:	83 e8 01             	sub    $0x1,%eax
  40111e:	83 f8 05             	cmp    $0x5,%eax
  401121:	76 05                	jbe    401128 <phase_6+0x34> 
                                    // eax -= 1; eax >= 5跳转 
  								    // 则这里是判定是否大于等于6 小于6 bomb
  401123:	e8 12 03 00 00       	callq  40143a <explode_bomb>
  401128:	41 83 c4 01          	add    $0x1,%r12d
  40112c:	41 83 fc 06          	cmp    $0x6,%r12d
    401130:	74 21                	je     401153 <phase_6+0x5f> // eax += 1; eax == 6跳转 跳转至 401153
  401132:	44 89 e3             	mov    %r12d,%ebx
  401135:	48 63 c3             	movslq %ebx,%rax
  401138:	8b 04 84             	mov    (%rsp,%rax,4),%eax
  40113b:	39 45 00             	cmp    %eax,0x0(%rbp)
  40113e:	75 05                	jne    401145 <phase_6+0x51>
  401140:	e8 f5 02 00 00       	callq  40143a <explode_bomb>
  401145:	83 c3 01             	add    $0x1,%ebx
  401148:	83 fb 05             	cmp    $0x5,%ebx
  40114b:	7e e8                	jle    401135 <phase_6+0x41>
  40114d:	49 83 c5 04          	add    $0x4,%r13
  401151:	eb c1                	jmp    401114 <phase_6+0x20>

第二部分开始进入正题了 这里我要做一下解说了
首先就是 刚开始的循环目的 就是把 6个数字 假如为num1、num2、num3、num4、num5、num6 不特定指的话 就用numx来做 6个输入进来的数字 numx = 0x7 - numx 我们把部分切的细一点

  401153:	48 8d 74 24 18       	lea    0x18(%rsp),%rsi	     // rsi = rsp + 24 
  401158:	4c 89 f0             	mov    %r14,%rax            // r14 = rsp rax = r14 = rsp
  40115b:	b9 07 00 00 00       	mov    $0x7,%ecx            // ecx = 0x7
  401160:	89 ca                	mov    %ecx,%edx	       // edx = ecx = 0x7
  401162:	2b 10                	sub    (%rax),%edx          // edx = 0x7 - numx
  401164:	89 10                	mov    %edx,(%rax)          // numx = 0x7 - numx
  401166:	48 83 c0 04          	add    $0x4,%rax            // rsp + 4 ++num;
  40116a:	48 39 f0             	cmp    %rsi,%rax	       // rsi = rsp + 24 循环6次 numx = 0x7 - numx
  40116d:	75 f1                	jne    401160 <phase_6+0x6c>
  40116f:	be 00 00 00 00       	mov    $0x0,%esi 	     // esi = 0 ecx = 0x7
  401174:	eb 21                	jmp    401197 <phase_6+0xa3> // jmp 401197

第三部分的话 就有点难了 因为这部分需要先理解 4011ab到最后在干什么了 看解析之前 建议认认真真的仔细分析完401176-4011a9在干什么内容再看 如果没理解的话 我们就暂且认为是在把某个结构体的地址放到rsp + 32 - rsp + 72 每个地址8字节 刚好6个的位置 所以我们先看看第四部分的代码 第三部分的话 后面会给的


在看下面的代码之前 可能大家已经注意到了一个神秘数字 0x6032d0 我先说一下我怎么注意到的 因为我是逐行逐行分析的 先分析完第三部分 分析的模模糊糊后 就看最后一部分 就发现我们的数据访问了这个地址 则我们先gdb调试看一下
在这里插入图片描述


此时xdm 有没有什么感觉了 如果此时你已经感觉呼之欲出了 就不用再往下看了 赶快去继续完成你的phase 如果还是模模糊糊的 那我下面就要介绍一下了 我看到这里的时候 就发现后面的数字 就是最后8字节数字每次都加了16字节 有点像指针数组 指针数组是通过前面的node1、2、3...看出来 访问的是一个结构体
此时不妨打破沙锅问到底 我们再访问6304480看看 即node1的指针 看看能不能有数据

在这里插入图片描述


此时结果已经很明显了 这个指针指向的是下一个节点 node2 我们如果访问6304496 得到的会是node3先出现 则我们可以推测出 前面的 332、168、924是节点数据 1 2 3是节点编号 最后8字节是next指针


在完成上面的推测后 我们再来看看第四部分的代码 注释很详细的写出了 链表修改的全过程 这部分的工作就是根据我们第三部分的向栈中放结构体地址的顺序 而修改链表的顺序 仔细看看注释 最后再给出第三部分

  4011ab:	48 8b 5c 24 20       	mov    0x20(%rsp),%rbx       // rbx = 第一个我们认为的node地址 
  4011b0:	48 8d 44 24 28       	lea    0x28(%rsp),%rax       // rax = rsp + 40 指向第二个node的地址
  4011b5:	48 8d 74 24 50       	lea    0x50(%rsp),%rsi       // rsi = 指向结束位置 rsp + 80堆栈
  4011ba:	48 89 d9             	mov    %rbx,%rcx             // rcx = 第一个node地址
  4011bd:	48 8b 10             	mov    (%rax),%rdx           // rdx = 第n(2,3,4,5,6)个node地址(会循环5次)
  4011c0:	48 89 51 08          	mov    %rdx,0x8(%rcx)        // 指针指向第n(2,3,4,5,6)node 则该链表的next地址修改
  4011c4:	48 83 c0 08          	add    $0x8,%rax             // rax += 8 则rax移向第n+1(
  4011c8:	48 39 f0             	cmp    %rsi,%rax             // 当rsi = rsp + 80(当已经遍历完了2,3,4,5,6)node 后 即停止循环 进入验收
                                                                 // 结束则意味着链表已经按照我们输入的方式已经排序好了 没有遍历完
  4011cb:	74 05                	je     4011d2 <phase_6+0xde> // rax = rsp + 0x50 = rsi
  4011cd:	48 89 d1             	mov    %rdx,%rcx             // 移动向第n个节点(2,3,4,5) 
  4011d0:	eb eb                	jmp    4011bd <phase_6+0xc9> // 循环
  4011d2:	48 c7 42 08 00 00 00 	movq   $0x0,0x8(%rdx)        // 末尾链表next 为 NULL 则设置为0x0
  4011d9:	00 
  4011da:	bd 05 00 00 00       	mov    $0x5,%ebp            
  4011df:	48 8b 43 08          	mov    0x8(%rbx),%rax       // 0x8(%rbx) 为链表第二项的地址
  4011e3:	8b 00                	mov    (%rax),%eax          //链表第二项头部数据
  4011e5:	39 03                	cmp    %eax,(%rbx) //链表第一项与第二项的数据比较
  4011e7:	7d 05                	jge    4011ee <phase_6+0xfa> //第一项数据大于或等于第二项则成功!
  4011e9:	e8 4c 02 00 00       	callq  40143a <explode_bomb>
  4011ee:	48 8b 5b 08          	mov    0x8(%rbx),%rbx
  4011f2:	83 ed 01             	sub    $0x1,%ebp
  4011f5:	75 e8                	jne    4011df <phase_6+0xeb>
  4011f7:	48 83 c4 50          	add    $0x50,%rsp
  4011fb:	5b                   	pop    %rbx
  4011fc:	5d                   	pop    %rbp
  4011fd:	41 5c                	pop    %r12
  4011ff:	41 5d                	pop    %r13
  401201:	41 5e                	pop    %r14

第四部分已经介绍完了 第三部分相对来说 就没有那么难了 因为最后这部分的链表修改 就根据这部分的代码来修改
下面的注释写的很清楚了 大家看注释应该就能看懂了

  401176:	48 8b 52 08          	mov    0x8(%rdx),%rdx
  40117a:	83 c0 01             	add    $0x1,%eax //如果为3 则会循环到node1->node2->node3 最后rdx会为node3结构体的地址
  40117d:	39 c8                	cmp    %ecx,%eax
  40117f:	75 f5                	jne    401176 <phase_6+0x82>
  401181:	eb 05                	jmp    401188 <phase_6+0x94>
  401183:	ba d0 32 60 00       	mov    $0x6032d0,%edx          // edx = 0x006032d0 当ecx = 1时才会来到这里
  401188:	48 89 54 74 20       	mov    %rdx,0x20(%rsp,%rsi,2)  // edx = rsp + 2*rsi + 32 核心代码****** 写链表地址顺序的
  40118d:	48 83 c6 04          	add    $0x4,%rsi               // rsi += 4
  401191:	48 83 fe 18          	cmp    $0x18,%rsi              // 循环6次
  401195:	74 14                	je     4011ab <phase_6+0xb7>
  401197:	8b 0c 34             	mov    (%rsp,%rsi,1),%ecx    // ecx = rsp + rsi 则为遍历1 2 3 4 5 6号输入数字
  40119a:	83 f9 01             	cmp    $0x1,%ecx             // origin: ecx = numx = (0x7 - (origin)numx)
  40119d:	7e e4                	jle    401183 <phase_6+0x8f> 
          // 如果numx <= 1的话 就跳转 jle 
  		 // 透露一点的话 就是你认为链表位置排名第五的话 你输入2 得到 ecx = 5 最后放入栈的则是node5的地址
  40119f:	b8 01 00 00 00       	mov    $0x1,%eax //eax 后面做循环
  4011a4:	ba d0 32 60 00       	mov    $0x6032d0,%edx
  4011a9:	eb cb                	jmp    401176 <phase_6+0x82> //跳入第四部分做最后的处理

最后我们再来总结一下干了什么 最后再来得到我们的答案
1、numx = 0x7 – numx
2、我们需要链表逆序(因为第四部分要求 链表第一项数据 > 第二项数据)
3、我们根据gdb调试 看地址0x6032d0得逆序顺序应该是3 4 5 6 1 2 又因为这个顺序 是经过了numx = 0x7 - numx 则原输入数据应该是4 3 2 1 6 5
在这里插入图片描述


好了 到了验收时间 经过上面的分析 得出来了结果4 3 2 1 6 5 看一下对不对
yeah! we finally make it! 我们还可以gdb看看链表中的指针

在这里插入图片描述


这个是在jge 0x4011e7处断的点 我们可以看出来是这样得
在这里插入图片描述


Phase Secret(彩蛋Phase)


其实如果仔细点 细心点的hxd就可以发现 这个Lab是有很多细节的 比如你在输入的时候 点了ctrl+c的时候 会出现下面的输出
当时不小心点到了 就发现这个 真的很有趣 尽管很多地方我都夸赞了老美老师做这些Lab的用心与沉浸 确确实实也带给我们很多很愉快的过程 这些Lab解决的过程 可能在之后很多年回想起来 还是会觉得特别有趣 ^^

在这里插入图片描述


这里先加一点预告吧 因为这篇博客篇幅太长了 所以我把Secret Phase单独作为一篇博客来写吧 因为在我把大一没有完成的Phase 6完成的时候 长吐了一口气 认为已经完成Lab的时候 忽然想看一下Bomb.c里面是怎么样的时候 我忽然看到了一段注释 那个时候 我就知道 Bomb Lab的历程还有最后一段路没有走 解决Secret Phase的博客链接我会在下面放着 对这个隐藏彩蛋Phase感兴趣的hxd就可以来看看 那各位下篇博客再见啦!

CSAPP Lab2实验记录 —- Bomb Lab(Secret Phase彩蛋解析)

前提预警 彩蛋Phase难度跟Phase 6差不了多少
在这里插入图片描述

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/38295.html

(0)
编程小号编程小号

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注