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

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



🌺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实验便是这场独特的学习冒险,从基本概念到底层实现,逐步揭示更深层次的计算机系统内核、汇编语言和数据结构的奥秘。


相关实践学习
阿里云图数据库GDB入门与应用
图数据库(Graph Database,简称GDB)是一种支持Property Graph图模型、用于处理高度连接数据查询与存储的实时、可靠的在线数据库服务。它支持Apache TinkerPop Gremlin查询语言,可以帮您快速构建基于高度连接的数据集的应用程序。GDB非常适合社交网络、欺诈检测、推荐引擎、实时图谱、网络/IT运营这类高度互连数据集的场景。 GDB由阿里云自主研发,具备如下优势: 标准图查询语言:支持属性图,高度兼容Gremlin图查询语言。 高度优化的自研引擎:高度优化的自研图计算层和存储层,云盘多副本保障数据超高可靠,支持ACID事务。 服务高可用:支持高可用实例,节点故障迅速转移,保障业务连续性。 易运维:提供备份恢复、自动升级、监控告警、故障切换等丰富的运维功能,大幅降低运维成本。 产品主页:https://www.aliyun.com/product/gdb
目录
相关文章
|
4月前
|
数据采集 机器学习/深度学习 算法
|
7月前
|
存储 安全 Ubuntu
【CSAPP】探秘AttackLab奥秘:level 3的解密与实战
【CSAPP】探秘AttackLab奥秘:level 3的解密与实战
76 0
|
7月前
|
存储 前端开发 rax
【CSAPP】探秘AttackLab奥秘:level 5的解密与实战
【CSAPP】探秘AttackLab奥秘:level 5的解密与实战
114 0
|
7月前
|
存储 安全 Ubuntu
【CSAPP】探秘AttackLab奥秘:level 1的解密与实战
【CSAPP】探秘AttackLab奥秘:level 1的解密与实战
76 0
|
7月前
|
存储 安全 Ubuntu
【CSAPP】探秘AttackLab奥秘:level 2的解密与实战
【CSAPP】探秘AttackLab奥秘:level 2的解密与实战
105 0
|
2月前
|
前端开发 NoSQL Java
Sa-Token学习圣经:从入门到精通Sa-Token,成为 史上最全的权限设计专家
尼恩团队推出了一系列技术学习资料,帮助开发者提升技能,应对面试挑战。最近,有读者在面试一线互联网企业如得物、阿里、滴滴等时遇到了与SpringCloud工业级底座相关的面试题,特别是用户权限认证和单点登录的设计问题。为此,尼恩团队整理了《Sa-Token学习圣经》,从入门到精通,帮助大家系统化地掌握Sa-Token框架。
|
2月前
|
存储 Kubernetes 数据安全/隐私保护
k8s学习--Secret详细解释与应用
Secret 支持四种类型: - **Opaque Secrets**:存储任意类型机密数据,需自行加密。 - **Service Account Token Secrets**:自动管理 API 访问令牌。 - **Docker Registry Secrets**:存储 Docker 私有仓库认证信息。 - **TLS Secrets**:存储 TLS 证书和私钥,用于加密通信。
229 0
|
7月前
|
存储 NoSQL Ubuntu
【CSAPP】探究BombLab奥秘:Phase_3的解密与实战
【CSAPP】探究BombLab奥秘:Phase_3的解密与实战
68 0
【CSAPP】探究BombLab奥秘:Phase_3的解密与实战
|
7月前
|
存储 NoSQL Ubuntu
【CSAPP】探究BombLab奥秘:Phase_1的解密与实战
【CSAPP】探究BombLab奥秘:Phase_1的解密与实战
67 0
|
7月前
|
存储 NoSQL Ubuntu
【CSAPP】探究BombLab奥秘:Phase_2的解密与实战
【CSAPP】探究BombLab奥秘:Phase_2的解密与实战
72 0