【CMU CS15213】Bomb Lab CSAPP 实验报告

文章详细介绍了如何通过阅读和理解x86-64汇编代码来完成CMUCS15-213课程的拆弹实验,涉及字符串比较、循环、数组处理、函数调用等多个技术点。每个阶段的炸弹都对应一个特定的解密逻辑,读者需要理解并利用这些逻辑来找出正确答案。实验中还涉及到了GDB的使用,以及对《计算机系统概论》(CSAPP)中知识的实际应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言

这学期做完了计组实验后,我终于有时间挑战一下一直心心念念的CMU CS15-213的拆炸弹实验了。
看了几眼题目,发现需要读懂汇编代码,于是又屁颠屁颠跑回去学CSAPP第三章……

学完之后,我大致描述一下这个Lab:这个Lab重点考察x86-64汇编代码阅读能力,但考察的难度不深,主要是读懂条件分支、循环和数组链表等代码的实现。
而入门x86-64汇编代码的最好教程就是CSAPP第三章!
而入门x86-64汇编代码的最好教程就是CSAPP第三章!
而入门x86-64汇编代码的最好教程就是CSAPP第三章!
(此发言综合了找资源等时间精力上的消耗的考量,含有较强的个人主观成分;当然若您有更好的资料,您对,您也可分享)

在学CSAPP第三章的时候,首先要简单掌握各个指令分别是什么意思,而重点在于后面的“控制”“过程”两节,讲解了分支、循环、函数调用过程中的返回值被调用者保存局部变量参数等概念的汇编实现,学会了对看懂汇编程序大有帮助!

Bomb Lab 提供两个文件,可执行文件bomb和程序主函数bomb.c,我们目前只有程序的主函数,需要使用objdump反编译bomb得到炸弹程序完整的汇编代码,再用所学知识反编译为C代码。

因此实际上呀,是有6个阶段,要拆6个炸弹!

但是这个Lab并没有想象中的难,最好是尽量自己做,不会再查相关资料,而不是直接看别人的总结。

准备工作

  1. 在VM安装Ubuntu(bomb程序在Linux下才能运行)
  2. 下载lab文件夹CASPP实验官网官方学生资源界面
  3. 使用objdump反汇译得到汇编代码程序(objdump安装方式上网搜索即可,windows也可以反汇编)
  4. 学习使用GDB调试bomb程序,用Linux的gdb才能运行bomb(GDB指令手册
  5. 学习CSAPP第三章

正式开始吧

  1. 下载并解压程序文件,得到bomb可执行文件与bomb.c
  2. 在该文件夹下终端输入指令objdump -S -d main > main.txt,从bomb中反汇编出汇编文件bomb.txt
  3. 再用指令gbd bomb进入到gdb功能

那现在,我们就有汇编代码与gdb啦
在这里插入图片描述

main函数

(main的源码我就不贴了)
我们从bomb.c文件中得知,我们的目标就是解决6个phase函数,每次一个输入,当6次输入都不会引爆各自phase函数中的<explode_bomb> 时,就能够正常通过phase函数啦!

phase_1

那就开始看<phase_1>函数吧!

0000000000400ee0 <phase_1>:
phase_1():
  400ee0:	48 83 ec 08          	sub    $0x8,%rsp  			# 开8字节的栈
  400ee4:	be 00 24 40 00       	mov    $0x402400,%esi   	# 第二个参数(第一个是你刚输进入的数)
  400ee9:	e8 4a 04 00 00       	call   401338 <strings_not_equal> #查一下
  400eee:	85 c0                	test   %eax,%eax
  400ef0:	74 05                	je     400ef7 <phase_1+0x17> # BOMB if %eax == 0
  400ef2:	e8 43 05 00 00       	call   40143a <explode_bomb>
  400ef7:	48 83 c4 08          	add    $0x8,%rsp # 关栈
  400efb:	c3                   	ret

(p.s. 里面的两个函数<strings_not_equal><explode_bomb>,先姑且按字面意思理解,一个是比较两字符串是否相等并返回布尔值,另一个是炸弹爆炸。lab做完后再去看源码相信对你来说已是小菜一碟)

书上说,x86-64给函数传参使用的寄存器是(依次列出):%rdi %rsi %dx rcx r8 r9。因此我们在调用函数<strings_not_equal>前设置的%rsi就是它的第二个参数,那我们的第一个参数则是我们的%rdi。为了验证想法,我们可以用GDB查看在0x400ee9位置时这两个参数的值(此时0x400ee9位置的指令尚未执行):
在这里插入图片描述
忽略中间执行信息,我们直接看头尾,我先是在0x400ee9设置了一个断点,然后输入r执行调试,输入hhhhhhhWhat?。随后达到断点,查看两寄存器指向位置的字符串,证实了我们的想法。

继续看<phase_1>的代码:

400ee9:	e8 4a 04 00 00       	call   401338 <strings_not_equal> #查一下
400eee:	85 c0                	test   %eax,%eax
400ef0:	74 05                	je     400ef7 <phase_1+0x17> # BOMB if %eax == 0
400ef2:	e8 43 05 00 00       	call   40143a <explode_bomb>

这一段是非常经典的分支代码了,我们知道调用函数<strings_not_equal>会返回一个布尔值,而这个返回值是放在%rax中传出的。test %eax,%eax使%eax = %eax & %eax,与je指令一起使用则是比较%rax == 0,满足则跳转,不满足则不跳转然后炸弹爆炸。

那就简单了嘛,只要我的输入和%rsi指向的字符串相同,那我就成了嘻嘻~

成功通过<phase_1>
在这里插入图片描述

phase_2

这是<phase_2>开头部分,信息量比较小:

0000000000400efc <phase_2>:
  400efc:	55                   	push   %rbp
  400efd:	53                   	push   %rbx 		# 保存被调用者保存寄存器,可以不理会
  400efe:	48 83 ec 28          	sub    $0x28,%rsp   # 开栈(开栈的用途有多种,看后面才能知道这里的目的)
  400f02:	48 89 e6             	mov    %rsp,%rsi	# 把栈交给%rsi

这时候也还看不出%rsi的作用:
在这里插入图片描述
接下来是一个函数调用与一个分支判断,“read_six_numbers”是吧,那我就随便输入个1 1 1 1 1 1吧。暂时不管函数<read_six_numbers>内部进行了什么工作,直接看调用后的结果。

400f05:	e8 52 05 00 00       	call   40145c <read_six_numbers> # 获取6个int数
400f0a:	83 3c 24 01          	cmpl   $0x1,(%rsp)
400f0e:	74 20                	je     400f30 <phase_2+0x34> # 若nums[0]==1
400f10:	e8 25 05 00 00       	call   40143a <explode_bomb>

在这里插入图片描述
这不就来了嘛,看来这个栈,相当于一个int数组呀!(姑且命名为nums数组)
然后的分支判断比较1 == (%rsp)相当于1 == nums[0],不满足就爆炸,还好我满足了哇。

下面又直接跳到了位置0x400f30,不好,书上说,这是循环的征兆!

  							# 跳到循环初始化
400f15:	eb 19                	jmp    400f30 <phase_2+0x34>
  # 循环体begin
400f17:	8b 43 fc             	mov    -0x4(%rbx),%eax  # %eax = nums[i-1]
400f1a:	01 c0                	add    %eax,%eax
							# if(2*nums[i-1] != nums[i]) BOMB();
400f1c:	39 03                	cmp    %eax,(%rbx)  	# if(2*nums[i-1] != nums[i]) BOMB()
400f1e:	74 05                	je     400f25 <phase_2+0x29>
400f20:	e8 15 05 00 00       	call   40143a <explode_bomb>
  							# 即总要有nums[i] == 2 * nums[i-1]!!
400f25:	48 83 c3 04          	add    $0x4,%rbx 		# i++
  							# 循环终止判断
400f29:	48 39 eb             	cmp    %rbp,%rbx
400f2c:	75 e9                	jne    400f17 <phase_2+0x1b>
400f2e:	eb 0c                	jmp    400f3c <phase_2+0x40>
							# 循环初始化
400f30:	48 8d 5c 24 04       	lea    0x4(%rsp),%rbx 	# %rbx加4,rbx即for循环中的i 
400f35:	48 8d 6c 24 18       	lea    0x18(%rsp),%rbp	# 终止条件
400f3a:	eb db                	jmp    400f17 <phase_2+0x1b> 
  # 循环体end

循环的流程已经给出来了,直接看注释。目前得到的最重要的信息有:

### 计算机系统中的Bomb实验原理详解 #### Bomb Lab概述 计算机系统的学习过程中,CSAPPBomb Lab是一个重要的实践环节。这个实验室设计旨在帮助学生深入了解底层编程、汇编语言以及二进制文件的工作机制[^1]。 #### 实验目标 通过解决一系列由程序炸弹设置的问题来掌握逆向工程技巧。每个阶段都涉及分析给定的目标代码并找出触发条件以安全解除爆炸装置模拟器。这不仅考验了参与者对于C语言和x86汇编的理解程度,还锻炼了解决实际问题的能力。 #### 工作流程解析 - **准备环境**:确保安装有必要的工具链如GCC编译器、GDB调试器等。 - **获取源码与资源**:下载官方提供的`bomb.c`以及其他辅助材料比如`tshref.out`,后者包含了所有测试案例的标准输出供参考[^2]。 ```bash wget http://csapp.cs.cmu.edu/3e/bomb.tar tar xf bomb.tar cd cs-apps/lab-bomb/ make ``` - **启动炸弹仿真器**:运行生成好的可执行文件开始挑战之旅。 ```bash ./bomb ``` - **逐级破解谜题** - 使用反汇编工具查看内部逻辑; - 应用静态分析方法推测可能输入; - 利用动态跟踪技术验证假设直至成功通关; #### 关键知识点回顾 在整个解密过程中会涉及到多个核心概念的应用: - **函数调用约定**:熟悉参数传递方式及栈帧布局有助于快速定位关键位置。 - **字符串处理指令**:熟练运用诸如`movsb`,`stosb`之类的操作可以简化某些类型的难题求解过程。 - **控制流转移机制**:理解跳转表、异常处理器等工作模式能够有效应对复杂分支情况下的推理需求。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值