【CSAPP】探究BombLab奥秘:Secret_phase的解密与实战

举报
SarPro 发表于 2024/02/05 00:01:19 2024/02/05
【摘要】 这篇博文深入探讨了CSAPP(Computer Systems: A Programmer's Perspective)课程中的BombLab实验,聚焦于Secret_phase的解密与实战。作者通过对实验环境、逆向分析和程序攻击的详细讲解,揭示了解除炸弹背后的深奥机制。文章通过生动的案例和实战经验,引领读者深入理解计算机系统底层原理与程序设计之间的精妙关系。

1.gif

7dd2b7f171704327b7d8987c49da4628.gif

📋 前言

🌈个人主页:SarPro
🔥 系列专栏:《CSAPP | 奇遇记》
⏰诗赋清音:笔墨奔雷动,心随翠浪飞。山川蕴壮志澎湃,梦驭风云意悠远。

 🎉欢迎大家关注🔍点赞👍收藏⭐️留言📝
 🔔作者留言:

欢迎来到我的【CSAPP】炸弹实验室!这里是探索计算机系统世界的秘境,我的学习笔记博客为你打开CSAPP的炸弹之门。在这里,我不仅分享计算机系统的基础知识和高级技巧,还有着涉猎实用技术和项目经验的爆炸药水。无论你是初学者还是计算机大师,这个实验室会为你施展出神秘的学习魔法,帮助你在CSAPP的炸弹领域中踏上一场惊险之旅。准备好了吗?跟着我,让我们一起解除那些迷人的炸弹代码,揭示计算机系统的神奇面纱!



🌺1. CSAPP与Bomb简介

🍀1.1 CSAPP

《CSAPP》是指计算机系统基础课程的经典教材《Computer Systems: A Programmer's Perspective》,由Randal E. Bryant和David R. O'Hallaron编写。该书的主要目标是帮助深入理解计算机系统的工作原理,包括硬件和软件的相互关系,其涵盖了计算机体系结构、汇编语言、操作系统、计算机网络等主题,旨在培养学生系统级编程和分析的能力。


🍀1.2 Bomb

"Bomb实验" 是与CSAPP教材相关的一项编程实验。它是一种反汇编和逆向工程任务,旨在教授如何分析和解决复杂的程序问题。Bomb实验的目标是解开一系列的"炸弹",每个炸弹都有不同的解锁方法,需要分析程序的汇编代码,理解其工作原理,并找到正确的输入来解除炸弹。这个实验教授了计算机系统的底层知识,包括汇编语言和程序执行的原理。

资源获取:关注公众号 科创视野 回复  CSAPP Bomb实验


🌺2. bomb

🍀2.1 实验环境

  • VMware Workstation虚拟机环境下的Ubuntu 64位。

🍀2.2 实验过程

实验准备阶段:首先需要使用ubuntu联网环境跳转到链接下载实验所需的bomblab:Bomblab源文件

下载bomblab压缩包并输入

tar –xvf bomb.tar

进行解压缩,进入该目录所有文件如下所示:


在终端输入

sudo apt-get install gdb

安装调试器。基本用法参考下图:


实验过程阶段:

“Binary bombs”是一个可在Linux系统上运行的C程序,它由6个不同的阶段(phase1~phase6)组成。在每个阶段,程序会要求输入一个特定的字符串。如果输入的字符串符合程序的预期输入,那么这个阶段的炸弹就会被“解除”,否则炸弹就会“爆炸”,并输出“BOOM!!!”的提示信息。实验的目的是尽可能多地解除这些炸弹的阶段。

每个炸弹阶段考察了机器级语言程序的一个不同方面,难度逐级递增:

* 阶段1:字符串比较

* 阶段2:循环

* 阶段3:条件/分支

* 阶段4:递归调用和栈

* 阶段5:指针

* 阶段6:链表/指针/结构

在炸弹拆除任务中,还存在一个隐藏阶段。然而,只有在第四个阶段解决后添加特定的字符串后,该隐藏阶段才会出现。为了完成任务,需要使用gdb调试器和objdump反汇编炸弹的可执行文件,然后单步跟踪每个阶段的机器代码,理解每个汇编语言的行为或作用。这将帮助“推断”出拆除炸弹所需的目标字符串。为了调试,可以在每个阶段的开始代码前和引爆炸弹的函数前设置断点。

在终端输入

objdump -d bomb > bomb.asm

得到bomb的反汇编文件bomb.asm如下所示。



🍀2.3 Secret_phase

在bomb.c中存在这样一段话:“  

/* Wow, they got it!  But isn't something... missing?  Perhaps

 * something they overlooked?  Mua ha ha ha ha! */”

说明这个炸弹之中还有一个隐藏关卡,寻找进入secret_phase 的入口

进入bomb.asm中发现了如下汇编代码:


需要找到 secret_phase 函数的入口,也就是调用了 secret_phase 的函数。在 bomb.asm 文件中搜索,发现 phase_defused 函数调用了 secret_phase 函数。而在 bomb.c 文件中,每个 phase 后面都有一个 phase_defused 函数调用。因此可以通过分析 phase_defused 函数来找到调用 secret_phase 函数的位置。

对phase_defused的反汇编内容如图:

解释详细如下:

00000000004015c4 <phase_defused>:
  4015c4:	48 83 ec 78          	sub    $0x78,%rsp
  4015c8:	64 48 8b 04 25 28 00 	mov    %fs:0x28,%rax
  4015cf:	00 00 
  4015d1:	48 89 44 24 68       	mov    %rax,0x68(%rsp)
  4015d6:	31 c0                	xor    %eax,%eax
  4015d8:	83 3d 81 21 20 00 06 	cmpl   $0x6,0x202181(%rip)        # 603760 <num_input_strings>
                                                           //num_input_strings 表示我们已经输入了多少串字符串了,判断是否等于6,
                                                           //如果不等于6,直接跳转到最下方,则secret_phase无法进入
                                                           //所以进入secret_phase的则先决条件是:完成phase 1 - 6
  4015df:	75 5e                	jne    40163f <phase_defused+0x7b>
  4015e1:	4c 8d 44 24 10       	lea    0x10(%rsp),%r8
  4015e6:	48 8d 4c 24 0c       	lea    0xc(%rsp),%rcx
  4015eb:	48 8d 54 24 08       	lea    0x8(%rsp),%rdx
  4015f0:	be 19 26 40 00       	mov    $0x402619,%esi
  4015f5:	bf 70 38 60 00       	mov    $0x603870,%edi
  4015fa:	e8 f1 f5 ff ff       	callq  400bf0 <__isoc99_sscanf@plt>    //调用sscanf函数
  4015ff:	83 f8 03             	cmp    $0x3,%eax                       //判断返回值%eax是否等于3
  401602:	75 31                	jne    401635 <phase_defused+0x71>     //如果返回值%eax不等于3的话,则跳转到最下方,跳过了401630 callq  401242 <secret_phase>
                                                                       //即secret_phase无法进入,所以必须要让sscanf函数的返回值为3
401604:	be 22 26 40 00       	mov    $0x402622,%esi       //%esi=0x402622
  401609:	48 8d 7c 24 10       	lea    0x10(%rsp),%rdi
  40160e:	e8 25 fd ff ff       	callq  401338 <strings_not_equal>   //调用字符串比较函数,判断输入的字符串和%esi中存的字符串是否相等
  401613:	85 c0                	test   %eax,%eax
  401615:	75 1e                	jne    401635 <phase_defused+0x71>   //若相等,则跳转至401635
                                                                     //(gdb)  print (char*) 0x402622 得到字符串 DrEvil
                                                                     //以下的代码不影响解码,暂且不做分析
  401617:	bf f8 24 40 00       	mov    $0x4024f8,%edi
  40161c:	e8 ef f4 ff ff       	callq  400b10 <puts@plt>
  401621:	bf 20 25 40 00       	mov    $0x402520,%edi
  401626:	e8 e5 f4 ff ff       	callq  400b10 <puts@plt>
  40162b:	b8 00 00 00 00       	mov    $0x0,%eax
  401630:	e8 0d fc ff ff       	callq  401242 <secret_phase>
  401635:	bf 58 25 40 00       	mov    $0x402558,%edi
  40163a:	e8 d1 f4 ff ff       	callq  400b10 <puts@plt>
  40163f:	48 8b 44 24 68       	mov    0x68(%rsp),%rax
  401644:	64 48 33 04 25 28 00 	xor    %fs:0x28,%rax
  40164b:	00 00 
  40164d:	74 05                	je     401654 <phase_defused+0x90>
  40164f:	e8 dc f4 ff ff       	callq  400b30 <__stack_chk_fail@plt>
  401654:	48 83 c4 78          	add    $0x78,%rsp
  401658:	c3                   	retq   
  401659:	90                   	nop
  40165a:	90                   	nop
  40165b:	90                   	nop
  40165c:	90                   	nop
  40165d:	90                   	nop
  40165e:	90                   	nop
  40165f:	90                   	nop

在4015fa行的代码中,我们可以观察到调用了sscanf函数,它的作用是格式化读取指定的字符串。在调用sscanf函数之前,代码使用了两条mov语句,这两个参数分别是指定的字符串和格式化读取字符串。

根据代码可以猜测,我们需要输入两个数字。为了查看这几个参数对应的字符串,我们可以使用GDB调试器。我们可以先输入之前完成的字符串,并在0x4015fa处设置断点,最后查看断点处的参数。在gdb试探性输入print (char*)0x402619和print (char*)0x603870。

得到格式化字符串 %d %d %s ,而7 0就是phase 4的解码,联系sscanf函数的返回值%eax需要等于3,可以猜想需要在7 0 后面再输入一串字符串,即可进入隐藏关卡。

phase_defused进行分析发现,在401604行出现了一个奇怪的地址为0x402622,在gdb输入print (char*)0x402622进行解析


为了进入隐藏关卡,我们需要在第四关的解码7 0后面加上字符串"DrEvil"。每次输入密钥可能会很繁琐,因此可以通过创建名为"bomb_idea.txt"的文件来存储所有的拆弹密码如下


并使用命令

./bomb bomb_idea.txt

来运行可执行文件。如果每一关调试结束后,我们可以将新的拆弹密码写入".txt"文件,这样就可以通过验证是否爆炸来避免重复输入之前关卡的拆弹密码。

系统提示成功找到了secret phase!

开始分析secret_phase内容:


Secret_phase汇编代码的解释内容如下:

0000000000401242 <secret_phase>:
  401242:  53                       push   %rbx
  401243:  e8 56 02 00 00           callq  40149e <read_line>     //调用read_line函数,读取字符串
  401248:  ba 0a 00 00 00           mov    $0xa,%edx
  40124d:  be 00 00 00 00           mov    $0x0,%esi
  401252:  48 89 c7                 mov    %rax,%rdi
  401255:  e8 76 f9 ff ff           callq  400bd0 <strtol@plt>    //调用strtol函数,将字符串转换为整型数据num,存在%rax中
  40125a:  48 89 c3                 mov    %rax,%rbx        //%rbx=%rax=num
  40125d:  8d 40 ff                 lea    -0x1(%rax),%eax
  401260:  3d e8 03 00 00           cmp    $0x3e8,%eax
  401265:  76 05                    jbe    40126c <secret_phase+0x2a>  //num-1>1000(0x3e8),则会爆炸,所以输入的数字必须小于等于1001
  401267:  e8 ce 01 00 00           callq  40143a <explode_bomb>
  40126c:  89 de                    mov    %ebx,%esi       //%esi=%ebx=num  %esi存放输入的数据num,作为参数代入fun7
  40126e:  bf f0 30 60 00           mov    $0x6030f0,%edi  //%edi=6030f0 作为参数代入fun7
  401273:  e8 8c ff ff ff           callq  401204 <fun7>       //调用函数fun7
  401278:  83 f8 02                 cmp    $0x2,%eax     //将fun7的返回值%eax与2比较 
                                                     //因为fun7为调用phase_defusd之前最后调用的一个函数,所以如果%eax=2,则跳过炸弹,拆弹成功!
                                                     //所以需要对fun7进行分析
  40127b:  74 05                    je     401282 <secret_phase+0x40>
  40127d:  e8 b8 01 00 00           callq  40143a <explode_bomb>
  401282:  bf 38 24 40 00           mov    $0x402438,%edi
  401287:  e8 84 f8 ff ff           callq  400b10 <puts@plt>
  40128c:  e8 33 03 00 00           callq  4015c4 <phase_defused>
  401291:  5b                       pop    %rbx
  401292:  c3                       retq  
  401293:  90                       nop          //nop 方便指令读取,不影响分析
  401294:  90                       nop
  401295:  90                       nop
  401296:  90                       nop
  401297:  90                       nop
  401298:  90                       nop
  401299:  90                       nop
  40129a:  90                       nop
  40129b:  90                       nop
  40129c:  90                       nop
  40129d:  90                       nop
  40129e:  90                       nop
  40129f:  90                       nop

由于 fun7 函数是调用 phase_defused 函数之前的最后一个函数,因此如果 fun7 函数的返回值 %eax = 2,那么炸弹就会被跳过,拆弹成功。因此需要对 fun7 函数进行分析。首先阅读 fun7 函数的源代码。

在gdb输入下列指令进行解析

x/150 0x6030f0

首先,查看0x6030f0中存放的数据,发现它类似于phase 6中的结构体。在6304xxx地址处应该是一个指针。同时,我们意外地发现,phase 6的指针数组就在下方。这里实际上是一个带有两个指针的结构体。前面的7个结构体的两个指针都是有值的,它们指向其他的结构体。而最后8个结构体的指针是没有值的,只有头部数据。这些指针所指的数据结构是一个二叉树。


fun7函数的逻辑较为复杂,为了便于之后的分析,将其转换为C语言的形式展示如下所示。

int func7(Type *p, int input)
{
    if(p == NULL)
        return -1;
    if(&p <= input)
    {
        if(&p == input)
            return 0;
        else
        {
            p = p + 0x10;
            int n = func7(p, input);
            return 2 * n + 1;
        }
    }
    else
    {
        p = p + 0x8;
        int n = func7(p, input);
        return 2 * n;
    }
}

需要得到返回值 %eax=2,说明递归顺序为:

1.最底层得到0 return 0

2.向上经过一层 %eax = %eax*2 + 1 得到1 return 1

3.再向上经过一层% eax = %eax*2 得到2 return 2

p所指向的数据结构是二叉搜索树,该树的结构为p = p + 0x10是加载右结点,p = p + 0x8是加载左结点。返回路径如下:


分析可得顺推思路:

1.首先,我们来到二叉树的首地址0x6030f0,对应的数据为36。因为36需要大于x,才能使得%eax = %eax*2成立。因此,指针值应该是%rdi + 8,即加载左结点。指针值为6304016,查看得到值为8。

2.在前文提到的分析过程中,需要注意节点 8 对应的位置。根据题目要求,需要让 %eax 的值乘 2 后再加 1,因此 8 的值需要小于等于 x。根据代码逻辑,我们需要加载右子节点,因此指针值为 0x603110 + 16,即 6304080。通过查看该位置内存的值,我们可以得到节点 8 的值为 22。因此可以推断出,对于输入的 x 值,当 x 大于等于 11 时,答案为 x*2+1;当 x 小于 11 时,答案为 fun7(0x6030f0, x)。

3.最后我们得到了数据22,当我们输入22的时候,因为和指针所处位置对应头部数据的值相等,所以%eax = 0。

因此22为可行解,如下。


在查看22对应的位置时,我们发现该位置还有两个指针,并且不是空指针。我们猜想,如果22大于所需解码,返回值为%eax = %eax*2,同样符合要求。那么指针值应该为0x603150 + 8,即加载左结点。指针值为6304368,查看得到值为20。然而,该位置指针为空,不再继续指向下一结点。因此,20也是一个可行解。

终端验证:

在bomb_idea.txt文件末尾添加20 22如下:


在终端输入

./bomb bomb_idea.txt


系统显示全部关卡通关成功。


🍀2.4 实验结果

以上代码均存储在bomb_idea.txt文件中,每行代表对应的关卡,各阶段密钥如下所示:


在终端输入

./bomb result.txt

显示全部通关。


🍀2.5 实验体会

  1. 实验环境深刻: BombLab实验在CSAPP课程中为学习者提供了深入理解计算机系统的机会。通过搭建实验环境,深刻感受了底层系统编程的挑战与乐趣。

  2. 逆向分析揭秘奥秘: 解密Secret_phase成为实验的重点,透过逆向分析的手法,揭示了程序内部的隐藏逻辑。这一过程不仅考验了逻辑思维,也拓展了对程序运行机制的认识。

  3. 程序攻击实战体验: 通过实际的程序攻击,实战演练了对炸弹的拆解过程。这不仅对计算机系统安全性有了更深层次的认识,同时也提高了解决问题和调试技能。整个实验过程既充实又充满挑战,为深入学习计算机系统打下了坚实基础。


📝 总结 

计算机系统的世界,如同一座未被揭示奥秘的古老迷宫,引领你勇敢踏入计算机科学的神秘领域。CSAPP的Bomblab实验便是这场独特的学习冒险,从基本概念到底层实现,逐步揭示更深层次的计算机系统内核、汇编语言和数据结构的奥秘。

渴望挑战计算机系统中的安全学习路径和掌握底层系统编程的技术?不妨点击下方链接,一同探讨更多计算机科学的奇迹吧。我们推出引领趋势的💻 计算机科学专栏:《斯坦福大学之CSAPP》,旨在深度探索计算机系统中安全编程技术的实际应用和创新。🌐🔍


7dd2b7f171704327b7d8987c49da4628.gif

【版权声明】本文为华为云社区用户原创内容,未经允许不得转载,如需转载请自行联系原作者进行授权。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。