CSAPP Lab2 实验记录 ---- Bomb Lab(Phase 1 - Phase 6详细解答 + Secret Phase彩蛋解析)_bomblab所有答案总结-程序员宅基地

技术标签: CSAPP  # CSAPP深入计算机系统  


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我可能会稍微没有那么仔细的分析了

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


实验需要指令及准备


我们首先把 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差不了多少
在这里插入图片描述

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qq_37500516/article/details/113789606

智能推荐

看懂这篇文章就够了!什么是Redis缓存雪崩、缓存穿透和缓存击穿?五分钟统统搞定-程序员宅基地

文章浏览阅读462次。前言今天的分享主要是讲下这个 redis,什么是缓存雪崩、穿透和击穿。这三个技术问题是我们平时开发工作中和面试过程中,必须要会的知识点,因为目前的互联网系统没有几个不需要用到缓存的,只要用到缓存的话,就需要掌握这三个技术问题。基本上无论哪个老哥去大厂面试,都会被问题这几个问题,所以作为一个互联网开发程序员来说,这个几个技术问题大家是需要搞懂的。而解决这几个问题的方案,通常有布隆过滤器,还有分布式锁。布隆过滤器是1970年的一项技术,距今也有50年了,之所以能够应用至今,说明这项技术还是挺优秀的,

做好的界面如何加上登录界面_网页中如何添加用户登录界面-程序员宅基地

文章浏览阅读1.1k次。1. 添加登录的界面类鼠标右键工程,点击添加新文件在弹出来的界面中选择Qt/Qt设计师界面类,点击choose在接下来的界面中选择界面模板为widget,点击下一步。输入界面类的类名Login,点击下一步点击完成。会发现工程里多了login.h、login.cpp、login.ui三个文件。2. 增加登录验证界面类在原有的main.cpp(软件都是先从这里启动的)里的main函数里会看到,程序启动干的第一件事是声明widget w;然后w.show();这样主界面类就出来了,现在_网页中如何添加用户登录界面

如何卸载modelsim_modelsim卸载-程序员宅基地

文章浏览阅读8.5k次,点赞10次,收藏10次。右击选择卸载在程序栏中选中mentor GraphicsProducts,右击卸载或更改点击全选,下一步,删除。_modelsim卸载

JavaWeb中使用JSON-程序员宅基地

文章浏览阅读309次。前言: 最近也是期末了,有好多好多文档和实验报告要交,所以都没啥时间写文,这段时间清闲了,来补一下之前学习时遗漏的一些知识树,话说就没人吐槽这个JSON图标好丑吗?什么是JSONJSON 指的是 JavaScript 对象表示法(JavaScript Object Notation)JSON 是轻量级的文本数据交换格式JSON 独立于语言 *JSON 具有自我描述性,更...

通过键盘码控制图像移动_c# 控制两张不同的图片移动-程序员宅基地

文章浏览阅读312次。通过键盘码控制图像移动这是代码运行后页面的效果图它们的效果是当你点击<键盘键时那张马里奥的图片将向左移动;点击<键时马里奥图片将向右移动;点击↑键时马里奥将向上移动;点击↓键时马里奥将向下移动;点击w键时羊驼图片将向上移动;点击s键时羊驼将向下移动;点击a键时羊驼将向左移动;点击d键时羊驼将向右移动;在这个页面上只布局了两张图片通过下面的代码可以实现图片的向左和向右移动;这是布局部分<body> <di..._c# 控制两张不同的图片移动

Android中使用gzip传递数据-程序员宅基地

文章浏览阅读381次。HTTP协议上的GZIP编码是一种用来改进WEB应用程序性能的技术。大流量的WEB站点常常使用GZIP压缩技术来减少文件大小,减少文件大小有两个明显的好处,一是可以减少存储空间,二是通过网络传输文件时,可以减少传输的时间。作者在写这篇博客时经过测试,4.4MB的文本数据经过Gzip传输到客户端之后变为392KB,压缩效率极高。一.服务端服务端有2种方式去压缩,一种可以自己压缩,但是更推

随便推点

Kryo序列化实现源码分析_python kryo 实现-程序员宅基地

文章浏览阅读1.1k次,点赞2次,收藏2次。在使用Kryo序列化之前需要将被序列化的类通过register()方法注册到其中去。在register的过程中,实则是要根据要序列化的类生成对应的Registration,Registration中记录了类的唯一id与对应的序列化类,在Kryo中,默认的序列化对象是FieldSerializer,没有特别指明的,都将以FieldSerializer来进行序列化。public Regist..._python kryo 实现

最全面的AndroidStudio配置指南总结-包括护眼模式-程序员宅基地

文章浏览阅读3.7k次。使用AndroidStudio开发APP已有半年多的时间了,从刚开始的不习惯到慢慢适应再到逐渐喜欢上AndroidStudio,中间的过程颇有一番曲折,现在把自己对AndroidStudio的配置心得总结下来,分享给大家,希望给后来人带来方便。强迫症童鞋的护眼模式设置方法传统模式的编辑域护眼模式的编辑域设置保护视力颜色 #C7EDCC(护眼绿)

【批处理DOS-CMD命令-汇总和小结】-跳转、循环、条件命令(goto、errorlevel、if、for[读取、切分、提取字符串]、)cmd命令错误汇总,cmd错误_cmd errorlevel-程序员宅基地

文章浏览阅读4k次,点赞5次,收藏28次。此文主要研究对代码分支化执行和重复利用的实现。分支化执行指根据中途的实际执行结果决定下一步执行的代码,跳转的代码行号;分支化执行大概分为跳转执行、条件判断执行;因此,分支化执行基本是只执行部分代码,部分代码不执行。代码重复利用的实现,一方面依赖程序调用(详见本人写的CMD命令实现程序调用一文),另一方面基于循环命令。打印goto命令的帮助信息。我们可以看到该命令的参数只有一个label。具体应用方法——在goto命令的下方放一行,开头是英文冒号后边紧跟“分支标识符”,然后再goto所在行后面加上“分支标识符_cmd errorlevel

Java面试宝典2013版-程序员宅基地

文章浏览阅读5.4k次。Java面试宝典2013版(超长版)一. Java基础部分......................................................................................................21、一个".java"源文件中是否可以包括多个类(不是内部类)?有什么限制?.....22、Java有没有goto?....

一对一直播软件源码开发,圆形纯数字按钮的实现_软件圆形数字-程序员宅基地

文章浏览阅读61次。在一对一直播软件源码开发过程中,会需要各种各样的按钮来进行界面的优化,其中圆形纯数字按钮是必不可少的,接下来就一起看看圆形纯数字按钮在一对一直播软件源码中时如何实现的吧。一、自定义按钮控件RelativeLayoutpublic class KeyboardView extends RelativeLayout { Context mContext; private GridView gridView; private List<Map<String, String&_软件圆形数字

JS数组字母排序(转载)_js数组按照字母排序的方法-程序员宅基地

文章浏览阅读1.6k次。//对数组中的多个对象对某一个字段按照字母先后顺序排序var array = [ {"id":"111","user":"D"}, {"id":"222","user":"B"}, {"id":"111","user":"A"}, {"id":"333","user":"C"}, {"id":"444","user":"F"}, {"id":"555","user":"E"} ];//对数组中的_js数组按照字母排序的方法