📋 前言
🌈个人主页:Sarapines Programmer
🔥 系列专栏:《斯坦福大学之CSAPP》
⏰诗赋清音:桃花灼灼春风暖,心随乐曲扬徐徐。 苦尽甘来梦未阑,岁月长河任舟游。
🎉欢迎大家关注🔍点赞👍收藏⭐️留言📝
🔔作者留言:欢迎来到我的【CSAPP】炸弹实验室!这里是探索计算机系统世界的秘境,我的学习笔记博客为你打开CSAPP的炸弹之门。在这里,我不仅分享计算机系统的基础知识和高级技巧,还有着涉猎实用技术和项目经验的爆炸药水。无论你是初学者还是计算机大师,这个实验室会为你施展出神秘的学习魔法,帮助你在CSAPP的炸弹领域中踏上一场惊险之旅。准备好了吗?跟着我,让我们一起解除那些迷人的炸弹代码,揭示计算机系统的神奇面纱!
目录
📋 前言
🌺1. CSAPP与Bomb简介
🍀1.1 CSAPP
🍀1.2 Bomb
🌺2. bomb
🍀2.1 实验环境
🍀2.2 实验过程
🍀2.3 phase_2
🍀2.4 实验结果
🍀2.5 实验体会
📝 总结
🌺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 BombLab实验解决源码(亲测有效!!!)
🌺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_2
phase_2是一个需要解密密码的关卡,需要输入一个字符串来解锁该关卡。如果输入的字符串符合要求,则可以成功通关,否则会引爆炸弹,导致失败。
进入反汇编文件bomb.asm
vim bomb.asm
在未插入处输入下列指令查找phase_2的位置。
/phase_2
分析反汇编代码的phase_2部分内容如下:
1.push %rbp: 将寄存器%rbp的值压入栈中。
2.push %rbx: 将寄存器%rbx的值压入栈中。
3.sub $0x28,%rsp:修改栈指针寄存器 %rsp 的值,以便在栈上分配一段新的空间。
3.callq 40145c <read_six_numbers>:调用一个名为"read_six_numbers"的函数。
5.je 400f30 <phase_2+0x34>:进行条件跳转。在该指令中,je 表示条件跳转指令,400f30 <phase_2+0x34> 是跳转目标地址,表示如果前面的条件成立,则会跳转到这个地址处执行后续的指令
……
可以发现phase_2函数有以下几个步骤:
- 将数据压入栈中;
- 减少栈指针40,为局部变量提供空间;
- 将栈指针存入%rsi寄存器中;
- 调用两个explode_bomb函数;
- 调用read_six_numbers函数读取6个数字。
尝试随意输入6个数字,如下:
为了解题,需要使%rsp的值为1,以便程序执行jmp指令跳过explode_bomb函数。jmp指令的目标地址是400f30,对应的指令为lea,用于加载有效地址。在调用read_six_numbers函数时,需要输入6个数字,该函数的地址为40145c,可以发现401480: mov $0x4025c3,%esi ,类似Phase 1向寄存器中转入数据(对应字符串),于是输入print (char*)0x4025c3进行测试,结果如下:
说明密钥需要6个整型数。回到phase_2反汇编进行分析,可以分析有一个循环,此时,结果上述循环,各寄存器对应的值如下:
%rbx | %rbp | %eax |
%rsp+4 | %rsp+24 | (%rsp)*2=2 |
%rsp+8 | (%rsp+4)*2=4 | |
%rsp+12 | (%rsp+8)*2=8 | |
%rsp+16 | (%rsp+12)*2=16 | |
%rsp+20 | (%rsp+16)*2=32 | |
%rsp+24 |
循环部分对应C代码
int i;
int a[6];
a[0] = 1;
for(i=1;i<6;i++)
{
a[i] = a[i-1]*2;
}
该代码段实现了对一组数的比较操作,并判断其中是否存在某个数是前一个数的2倍。这段代码是汇编语言的实现,对于不熟悉汇编语言的人来说,可能比较难懂。对这段代码进行详细的解析。
1.这段代码是一个循环操作,它对一组数进行比较,并且判断其中是否存在某个数是前一个数的2倍。这组数存储在栈中,栈顶元素即为第一个数。 在代码执行的开始,我们可以看到一条cmp指令,它将栈顶元素与立即数0x1进行比较。如果相等,说明第一个输入数为1,此时会跳转到地址400f30处;如果不相等,说明第一个输入数不是1,此时会跳转到地址400f17处。
2.在地址400f30处,我们可以看到两条lea指令,它们将%rsp+4和%rsp+24对应的地址分别存储到%rbx和%rbp寄存器中。%rbx寄存器存储的是第二个输入数的地址,%rbp寄存器存储的是第六个输入数后面的地址。
3.代码跳转到地址400f17处。可以看到sub指令,它将%rbx的值减去4,并将其对应的内存地址中的值(即前一个数)存储到%eax寄存器中。接着,将%eax的值乘以2,并将其与%rbx对应的内存地址中的值(即当前数)进行比较。如果相等,说明当前数是前一个数的2倍,此时会跳转到地址400f25处;如果不相等,说明当前数不是前一个数的2倍,此时会跳转到地址400f17处。
4.在地址400f25处,我们可以看到一条add指令,它将%rbx的值加上4。接着,代码会判断%rbx的值是否等于%rbp的值,如果不相等,则说明还没有处理完所有的数,此时会跳转到地址400f17处;如果相等,则说明已经处理完所有的数,此时会跳转到地址400f3c处,结束循环。 在循环中,代码会从栈中逐个取出这些数,并进行比较操作。如果存在某个数是前一个数的2倍,代码会跳转到地址400f25处,否则会跳转到地址400f17处。这个循环会一直执行,直到处理完所有的数,才会跳转到地址400f3c处,结束循环。
通过以上的分析,可以得到这组数的具体值。这组数分别为1,2,4,8,16,32。
在终端输入
./bomb
填入密钥
1 2 4 8 16 32
结果显示phase_2通关。
综上所述,解决phase_2的过程的难点是分析反汇编代码的循环部分,找到循环结束的位置,在循环中,代码会从栈中逐个取出这些数,并进行比较操作。如果存在某个数是前一个数的2倍,代码会跳转到地址400f25处,否则会跳转到地址400f17处。这个循环会一直执行,直到处理完所有的数,才会跳转到地址400f3c处,结束循环。
将Phase_2中每句代码的作用解释如下所示。
0000000000400efc <phase_2>:
400efc: 55 push %rbp //把数据压入栈
400efd: 53 push %rbx //把数据压入栈
400efe: 48 83 ec 28 sub $0x28,%rsp //把栈指针减少40,提供局部变量空间
//申请空间
400f02: 48 89 e6 mov %rsp,%rsi //把栈指针状态存入%rsi中
400f05: e8 52 05 00 00 callq 40145c <read_six_numbers> // 调用函数read_six_numbers,读取6个数字,此时(%rsp)已被赋值
400f0a: 83 3c 24 01 cmpl $0x1,(%rsp) //(%rsp)的值即输入的第一个参数的值,将(%rsp)的值与1比较
400f0e: 74 20 je 400f30 <phase_2+0x34> //若相等则跳转至400f30
400f10: e8 25 05 00 00 callq 40143a <explode_bomb> //否则爆炸
400f15: eb 19 jmp 400f30 <phase_2+0x34> //jmp指令无条件跳转,直接跳转至400f30
400f17: 8b 43 fc mov -0x4(%rbx),%eax
400f1a: 01 c0 add %eax,%eax //%eax的值*2
400f1c: 39 03 cmp %eax,(%rbx) //比较%eax的值和此时%rbx对应的内存的值
400f1e: 74 05 je 400f25 <phase_2+0x29> //若相等则跳转至400f25
400f20: e8 15 05 00 00 callq 40143a <explode_bomb> //否则爆炸
400f25: 48 83 c3 04 add $0x4,%rbx //%rbx的值(地址)加4
400f29: 48 39 eb cmp %rbp,%rbx //比较两个寄存器的值,判断是否比较完6个数
400f2c: 75 e9 jne 400f17 <phase_2+0x1b> //若不相等,则进行跳转至400f17,即循环没结束
400f2e: eb 0c jmp 400f3c <phase_2+0x40> //否则直接跳转至400f3c,循环结束标志
400f30: 48 8d 5c 24 04 lea 0x4(%rsp),%rbx //将%rsp+4代表的地址移入%rbx,即第2个输入数的地址
400f35: 48 8d 6c 24 18 lea 0x18(%rsp),%rbp //将%rsp+24代表的地址移入%rbp,即第6个输入数的后一块地址
400f3a: eb db jmp 400f17 <phase_2+0x1b> //直接跳转至400f17
//释放空间
400f3c: 48 83 c4 28 add $0x28,%rsp
400f40: 5b pop %rbx
400f41: 5d pop %rbp
400f42: c3 retq
🍀2.4 实验结果
以上代码均存储在bomb_idea.txt文件中,每行代表对应的关卡,各阶段密钥如下所示:
在终端输入
./bomb result.txt
显示全部通关。
🍀2.5 实验体会
-
解密挑战: 在CSAPP的BombLab实验中,Phase_2成为了一次解密的重大挑战。通过逆向工程和仔细分析程序逻辑,成功理解了Phase_2的设计思想,揭示了其中隐藏的奥秘。
-
实战经验: 实验过程中,通过灵活运用逆向技术和调试工具,顺利攻克了Phase_2的难题。实战经验让我更加熟悉了计算机系统底层的运行机制,为后续学习和实践奠定了坚实基础。
-
深刻领悟: 通过探究Phase_2,不仅在技术上有所提升,更对计算机系统的安全性和程序设计的复杂性有了更深刻的领悟。这次实验不仅仅是技术挑战,更是对计算机科学精髓的一次深刻探索。
📝 总结
计算机系统的世界,如同一座未被揭示奥秘的古老迷宫,引领你勇敢踏入计算机科学的神秘领域。CSAPP的Bomblab实验便是这场独特的学习冒险,从基本概念到底层实现,逐步揭示更深层次的计算机系统内核、汇编语言和数据结构的奥秘。
渴望挑战计算机系统中的安全学习路径和掌握底层系统编程的技术?不妨点击下方链接,一同探讨更多计算机科学的奇迹吧。我们推出引领趋势的💻 计算机科学专栏:《斯坦福大学之CSAPP》,旨在深度探索计算机系统中安全编程技术的实际应用和创新。🌐🔍