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

举报
SarPro 发表于 2024/02/04 23:37:02 2024/02/04
【摘要】 在这篇博文中,作者深入解析了CSAPP(Computer Systems: A Programmer's Perspective)课程中的BombLab实验,聚焦于其中的第三阶段(Phase_3)。文章揭示了Phase_3的解密过程与实战策略,深入讲解了逆向工程和程序攻击的关键技术,为读者提供了深刻的计算机系统学习体验。

1.gif

2c3b549f930dc81c1bb64cca20bce92e.gif

7dd2b7f171704327b7d8987c49da4628.gif


📋 前言

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

cooll.gif

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

欢迎来到我的【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 phase_3

phase_3需要使用逆向工程技术找到正确的密码。

vim bomb.asm

使用vim指令输入进入反汇编文件bomb.asm,

/phase_3

在未插入处输入查找phase_3的位置。


在Phase_3函数中,程序会首先使用sscanf函数从用户输入的字符串中读取一个整数,并将其存储在%eax寄存器中。接着,程序会将%eax的值与1进行按位与运算,并将结果存储到%eax寄存器中。如果%eax的值为0,则表示输入的整数为偶数;否则,表示输入的整数为奇数。 接下来,程序会调用一个名为fun3的函数,并将输入的整数和一个立即数0x7作为参数传递给这个函数。fun3函数的具体实现可以在IDA中查看。在fun3函数中,程序会将输入的整数与0x7进行按位与运算,然后将结果与一个名为“global_value”的全局变量进行比较。如果相等,则返回0;否则,返回一个非0的值。 最后,Phase_3函数会检查fun3函数的返回值是否为0,如果是,则表示密码正确;否则,表示密码错误。 为了寻找正确的密码,需要找到“global_value”的值。可以使用gdb调试工具,在程序运行时获取“global_value”的值。首先,需要在gdb中运行程序,并在输入密码之前,在第一行代码处打一个断点。接着,输入一个偶数作为密码,然后运行到断点处。在这里,可以使用命令“x/gx 0x地址”来查看“global_value”的值。 得到“global_value”的值后,需要使用Python等脚本语言,在0到1000之间枚举所有满足条件的偶数,并将其作为密码输入到程序中,以验证是否正确。如果找到了正确的密码,程序会输出“Congratulations!”;否则,程序会输出“Explosion!”。 除了上述步骤,我们可以注意到Phase_3函数中的第四行代码,程序将0x4025cf赋值给了%esi寄存器。这是一个地址常量,由于它在sscanf函数的前面,可以推测0x4025cf可能是一个格式字符串。因此使用gdb工具中的x/s命令来查看该地址常量的内容,以进一步了解输入内容的格式。

其中,第7-10行代码是关键的判断条件。在这几行代码中,程序会将输入的整数与1进行按位与运算,并将结果存储到%eax寄存器中。随后,程序会将%eax的值与1进行比较,如果小于等于1,则会引爆炸弹。 %eax寄存器一般是存储函数的返回值,在Bomblab中,sscanf函数的返回值就是成功读取的元素个数。因此可以推断出,这里输入的元素个数必须大于1才能通过验证,否则会引爆炸弹。 为了找到正确的密码,需要输入两个整数,可以通过IDA等反汇编工具来了解程序的具体实现。

在终端查看跳转表中储存的地址。

x/8xg 0x402470

​​

仔细观察这些地址,可以发现都是函数phase_3范围内的地址。

当num1=0时,跳转到0x0000000000400f7c处执行。如果num2不等于0xcf,则触发炸弹。

当num1=1时,跳转到0x0000000000400fb9处执行。如果num2不等于0x137,则触发炸弹。

当num1=2时,跳转到0x0000000000400f83处执行。如果num2不等于0x2c3,则触发炸弹。

当num1=3时,跳转到0x0000000000400f8a处执行。如果num2不等于0x100,则触发炸弹。

当num1=4时,跳转到0x0000000000400f91处执行。如果num2不等于0x185,则触发炸弹。

当num1=5时,跳转到0x0000000000400f98处执行。如果num2不等于0xce,则触发炸弹。

当num1=6时,跳转到0x0000000000400f9f处执行。如果num2不等于0x2aa,则触发炸弹。

当num1=7时,跳转到0x0000000000400fa6处执行。如果num2不等于0x147,则触发炸弹。

所以拆弹密码有以下8种:

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

输入其中任意几种或者全部输均可。

在终端输入

./bomb

填入密钥0 207结果显示phase_3通关。

综上所述,解决Bomblab中的Phase_3题目需要一定的逆向工程技术和耐心,但通过对代码的分析和调试,我们可以找到正确的密码,进入下一个阶段。这是逆向工程学习中重要的一步,也可以帮助我们更深入地了解程序的运行机制。

对应C代码的实现为:

void phase_3(const char *input)
{
  //  0x8(%rsp)  0xc(%rsp)
  int num1, num2;
  //     %rdi     %rsi   %rdx   %rcx
  int result = sscnaf(input, "%d %d", &num1, &num2);
  if (result <= 1) {
    explode_bomb();
  }


  switch (num1) {
    case 0: // 0 207
      if (num2 != 0xcf) {
        explode_bomb();
      }
      break;

    case 1: // 1 311
      if (num2 != 0x137) {
        explode_bomb();
      }
      break;

    case 2: // 2 707
      if (num2 != 0x2c3) {
        explode_bomb();
      }
      break;

    case 3: // 3 256
      if (num2 != 0x100) {
        explode_bomb();
      }
      break;

    case 4: // 4 389
      if (num2 != 0x185) {
        explode_bomb();
      }
      break;

    case 5: // 5 206
      if (num2 != 0xce) {
        explode_bomb();
      }
      break;

    case 6: // 6 682
      if (num2 != 0x2aa) {
        explode_bomb();
      }
      break;

    case 7: // 7 327
      if (num2 != 0x147) {
        explode_bomb();
      }
      break;

    default:
      explode_bomb();
      break;
  }
}

Phase_3中每句代码的作用解释如下所示。

0000000000400f43 <phase_3>:
  400f43:  48 83 ec 18              sub    $0x18,%rsp     //给局部变量腾出空间
  400f47:  48 8d 4c 24 0c           lea    0xc(%rsp),%rcx  //加载地址,将0xc(%rsp)设为num2
  400f4c:  48 8d 54 24 08           lea    0x8(%rsp),%rdx  //加载地址,将0x8(%rsp)设为num1
  400f51:  be cf 25 40 00           mov    $0x4025cf,%esi  //因为后续调用了函数scanf,此处需对输入格式进行测试
                                                       //经测试,0x4025cf对应字符串"%d %d"
                                                       //因此可以猜测开头%rcx存放的为输入的第一个数据(设为num1)的地址,%rdx存放的为输入的第二个数据(设为num2)的地址
  400f56:  b8 00 00 00 00           mov    $0x0,%eax    //初始化%eax
  400f5b:  e8 90 fc ff ff           callq  400bf0 <__isoc99_sscanf@plt>  //调用scanf函数,此时%eax放scanf函数的返回值(输入数据的个数)
  400f60:  83 f8 01                 cmp    $0x1,%eax         
  400f63:  7f 05                    jg     400f6a <phase_3+0x27>  //jg:有符号大于则跳转,说明scanf输入数据的个数必须大于1
  400f65:  e8 d0 04 00 00           callq  40143a <explode_bomb>  //否则爆炸
  400f6a:  83 7c 24 08 07           cmpl   $0x7,0x8(%rsp)
  400f6f:  77 3c                    ja     400fad <phase_3+0x6a>  //ja:无符号大于则跳转,至爆炸,说明num1为无符号数,大于0且需要小于等于7,所以num1=[0,7]
  400f71:  8b 44 24 08              mov    0x8(%rsp),%eax           //将num1储存到%eax中
  400f75:  ff 24 c5 70 24 40 00     jmpq   *0x402470(,%rax,8)      //间接跳转,(此处%rax不完全等于%eax,由num1=1(%rax=1)时的跳转地址可推论)
                                                               //0x402470+%rax*8的计算结果作为地址,跳转到该地址继续执行
                                                               //根据该指令和后续的指令格式,很容易判断此处是switch语句的跳转表,跳转表的首地址为0x402470
                                                               //以 *0x402470 处的值为基地址,再加上8 * %rax 进行跳转,不同的 %rax 跳转到不同的位置。
  400f7c:  b8 cf 00 00 00           mov    $0xcf,%eax                 //case 0  %eax=0xcf=207
  400f81:  eb 3b                    jmp    400fbe <phase_3+0x7b>
  400f83:  b8 c3 02 00 00           mov    $0x2c3,%eax                //case 2  %eax=0x2c3=707
  400f88:  eb 34                    jmp    400fbe <phase_3+0x7b>
  400f8a:  b8 00 01 00 00           mov    $0x100,%eax                //case 3  %eax=0x100=256
  400f8f:  eb 2d                    jmp    400fbe <phase_3+0x7b>
  400f91:  b8 85 01 00 00           mov    $0x185,%eax                //case 4  %eax=0x185=389
  400f96:  eb 26                    jmp    400fbe <phase_3+0x7b>
  400f98:  b8 ce 00 00 00           mov    $0xce,%eax                 //case 5  %eax=0xce=206
  400f9d:  eb 1f                    jmp    400fbe <phase_3+0x7b>
  400f9f:  b8 aa 02 00 00           mov    $0x2aa,%eax                //case 6  %eax=0x2aa=682
  400fa4:  eb 18                    jmp    400fbe <phase_3+0x7b>
  400fa6:  b8 47 01 00 00           mov    $0x147,%eax                //case 7  %eax=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
  400fb7:  eb 05                    jmp    400fbe <phase_3+0x7b>
  400fb9:  b8 37 01 00 00           mov    $0x137,%eax                //case 1  %eax=0x137=311
  400fbe:  3b 44 24 0c              cmp    0xc(%rsp),%eax   //比较%eax的值和num2
  400fc2:  74 05                    je     400fc9 <phase_3+0x86>  //je:若相等则跳转至结束
  400fc4:  e8 71 04 00 00           callq  40143a <explode_bomb>  //否则爆炸
  400fc9:  48 83 c4 18              add    $0x18,%rsp       //释放空间
  400fcd:  c3                       retq  

🍀2.4 实验结果

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


在终端输入

./bomb result.txt

显示全部通关。


🍀2.5 实验体会

  1. 解密奥秘: 在CSAPP的BombLab实验中,深入研究了Phase_3,通过逆向分析揭示了其隐藏的机制。理解了程序背后的逻辑,成功解密了Phase_3,这一过程让我对计算机系统底层运行有了更深入的认识。

  2. 实战经验: 在攻克Phase_3的实战中,运用了各种适当的技术手段,包括逆向工程和程序调试等。通过实际动手的过程,加深了对计算机系统内部运作的理解,提升了解决实际问题的能力。

  3. 学术收获: 通过解密与实战,不仅提高了我的计算机系统安全意识,还培养了问题解决和分析的能力。CSAPP的BombLab实验为我打开了计算机科学领域的一扇大门,让我更加热衷于深入研究底层原理与系统编程。


📝 总结 

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

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

7dd2b7f171704327b7d8987c49da4628.gif

end.gif

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

评论(0

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

全部回复

上滑加载中

设置昵称

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

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

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