计算机系统实验二——bomblab(炸弹实验)

本文详细解析了BOM实验的第六关,通过分析汇编代码,揭示了输入数字的限制、链表结构以及递归函数的使用。通过对输入数字的限制条件进行逆向推理,找出输入数字的规律,成功解除了炸弹。同时,介绍了隐藏关卡的解谜过程,展示了如何从汇编代码中找出关键信息,最终解密隐藏关卡。
摘要由CSDN通过智能技术生成

实验题目

bomblab

实验目的

  1. 使用gdb工具反汇编出汇编代码,结合c语言文件找到每个关卡的入口函数。然后分析汇编代码,分析得到每一关的通关密码。
  2. 进一步加深对linux指令的理解,对gdb调试的一些基本操作以及高级操作有所了解。
  3. 熟悉汇编程序,懂得如何利用汇编程序写出C语言程序伪代码,熟悉并掌握函数调用过程中的栈帧结构的变化,熟悉汇编程序及其调试方法。

实验环境

个人PC、Linux 32位操作系统、Ubuntu16.04

实验内容

准备阶段

  • 将实验压缩包解压并找到本人所用到的实验文件夹bomb7,复制到linux系统中,打开文件夹得到bombbomb.cREADME文件;
  • 阅读README等实验相关材料,通过各种方式了解实验的相关内容和过程;
  • 检查bomb实验中的两个文件,发现bomb.c文件残缺,无法运行;而bomb文件可以正常运行,实验主要部分与bomb.c文件关系不大;
  • 了解实验的要求,该实验共有7个关卡,包括6个普通关卡和1个隐藏关卡
  • 将bomb文件反汇编并生成 .txt 文件(objdump bomb -d > my_bomb.txt),这样可以在my_bomb.txt中分析汇编代码,而bomb文件则可结合gdb进行调试分析;

分析阶段

<phase_1>
  • 反汇编代码
08048b90 <phase_1>:
 8048b90:	83 ec 1c             	sub    $0x1c,%esp //esp-28 -> esp,申请栈空间
 8048b93:	c7 44 24 04 44 a1 04 	movl   $0x804a144,0x4(%esp) //0x0804a144 -> M(esp+4),将内存空间放入esp寄存器
 8048b9a:	08 
 8048b9b:	8b 44 24 20          	mov    0x20(%esp),%eax //M(esp+32) -> eax
 8048b9f:	89 04 24             	mov    %eax,(%esp) //eax -> M(esp)
 8048ba2:	e8 63 04 00 00       	call   804900a <strings_not_equal> //调用函数判断string是否相等
 8048ba7:	85 c0                	test   %eax,%eax //test if eax is empty,if empty,ZF = 1.
 8048ba9:	74 05                	je     8048bb0 <phase_1+0x20> //jump if ZF = 1
 8048bab:	e8 65 05 00 00       	call   8049115 <explode_bomb> //call <explode_bomb>
 8048bb0:	83 c4 1c             	add    $0x1c,%esp //esp+12 -> esp
 8048bb3:	c3                   	ret    //return
  • 解题思路
  1. 先把重要的反汇编代码意义标注出来(注释如上)
  2. 采用逆向思维法,先找出炸弹什么时候会爆炸。
8048bab:	e8 65 05 00 00       	call   8049115 <explode_bomb> //call <explode_bomb>

执行这一步就会爆炸。

  1. 找到跳过爆炸这一步的条件。
 8048ba7:	85 c0                	test   %eax,%eax //test if eax is empty,if empty,ZF = 1.
 8048ba9:	74 05                	je     8048bb0 <phase_1+0x20> //jump if ZF = 1

只要eax为0,则执行je指令,跳过爆炸。

  1. 顺藤摸瓜,找出eax为0的条件。
 8048b9b:	8b 44 24 20          	mov    0x20(%esp),%eax //M(esp+32) -> eax
 8048b9f:	89 04 24             	mov    %eax,(%esp) //eax -> M(esp)
 8048ba2:	e8 63 04 00 00       	call   804900a <strings_not_equal> //调用函数判断string是否相等

追溯到 mov 0x20(%esp),%eax指令,把我们输入的参数放进%eax中,然后放进(%esp) ,再调用函数<strings_not_equal>,如果输入的内容与传入的字符串相等,则返回0,这个就是eax为0的条件。

  1. 找出传入<strings_not_equal>的参数。
 8048b93:	c7 44 24 04 44 a1 04 	movl   $0x804a144,0x4(%esp) //0x0804a144 -> M(esp+4),将内存空间放入esp寄存器

所求的字符串即是0x804a144里面的值。

  1. 进入gdb调试模式,找到0x804a144地址格子里面的东西
gates@ubuntu:~/bomb7$ gdb -q bomb
Reading symbols from bomb...
(gdb) x/s 0x804a144
0x804a144:	"Brownie, you are doing a heck of a job."
  1. 输入找出来的字符串,验证答案。
gates@ubuntu:~/bomb7$ ./bomb
Welcome to my fiendish little bomb. You have 6 phases with
which to blow yourself up. Have a nice day!
Brownie, you are doing a heck of a job.
Phase 1 defused. How about the next one?
  1. 炸弹一拆除!
<phase_2>
  • 反汇编代码
08048bb4 <phase_2>:
 8048bb4:	53                   	push   %ebx //save old edx
 8048bb5:	83 ec 38             	sub    $0x38,%esp //open new stack
 8048bb8:	8d 44 24 18          	lea    0x18(%esp),%eax //esp+24->eax
 8048bbc:	89 44 24 04          	mov    %eax,0x4(%esp) //eax -> M(esp+4)
 8048bc0:	8b 44 24 40          	mov    0x40(%esp),%eax //M(esp+64) -> eax
 8048bc4:	89 04 24             	mov    %eax,(%esp) //eax -> M(esp)
 8048bc7:	e8 70 05 00 00       	call   804913c <read_six_numbers>
 8048bcc:	83 7c 24 18 00       	cmpl   $0x0,0x18(%esp) //cmp
 8048bd1:	79 22                	jns    8048bf5 <phase_2+0x41> //M(esp+24-0)>=0
 8048bd3:	e8 3d 05 00 00       	call   8049115 <explode_bomb> //Bomb!
 8048bd8:	eb 1b                	jmp    8048bf5 <phase_2+0x41> //
 8048bda:	89 d8                	mov    %ebx,%eax //ebx -> eax
 8048bdc:	03 44 9c 14          	add    0x14(%esp,%ebx,4),%eax //eax+M(20+esp+4*ebx) -> eax
 8048be0:	39 44 9c 18          	cmp    %eax,0x18(%esp,%ebx,4) //cmp
 8048be4:	74 05                	je     8048beb <phase_2+0x37> //jump if eax==M(24+esp+4*ebx)
 8048be6:	e8 2a 05 00 00       	call   8049115 <explode_bomb> //Bomb!
 8048beb:	83 c3 01             	add    $0x1,%ebx //ebx+1 -> ebx
 8048bee:	83 fb 06             	cmp    $0x6,%ebx //cmp
 8048bf1:	75 e7                	jne    8048bda <phase_2+0x26> //jump if ebx!=6
 8048bf3:	eb 07                	jmp    8048bfc <phase_2+0x48> //jump
 8048bf5:	bb 01 00 00 00       	mov    $0x1,%ebx //1 -> ebx
 8048bfa:	eb de                	jmp    8048bda <phase_2+0x26> //jump
 8048bfc:	83 c4 38             	add    $0x38,%esp //esp+56 -> esp
 8048bff:	5b                   	pop    %ebx //pop
 8048c00:	c3                   	ret      
  • 解题思路
  1. 先把重要的反汇编代码意义标注出来(注释如上)
  2. 找到炸弹爆炸的汇编代码。
 8048bd3:	e8 3d 05 00 00       	call   8049115 <explode_bomb> //Bomb!
 8048be6:	e8 2a 05 00 00       	call   8049115 <explode_bomb> //Bomb!
  1. 找到跳过第一个炸弹的方法。
 804913c <read_six_numbers>
 8048bcc:	83 7c 24 18 00       	cmpl   $0x0,0x18(%esp) //cmp
 8048bd1:	79 22                	jns    8048bf5 <phase_2+0x41> //M(esp+24-0)>=0

<read_six_numbers>是读取输入的六个数字,cmpl、jns语句结合,判断M(esp+24)与0x0的大小,满足M(esp+24)>=0x0则可跳过第一个炸弹,由此可知,输入的第一个数应该要大于等于0。

  1. 顺着跳转指令寻找重要寄存器的值。
 8048bf5:	bb 01 00 00 00       	mov    $0x1,%ebx //1 -> ebx
 8048bfa:	eb de                	jmp    8048bda <phase_2+0x26> //jump
 8048bda:	89 d8                	mov    %ebx,%eax //ebx -> eax

ebx=1,eax=ebx=1。

  1. 找到跳过第二个炸弹的方法。
 8048bdc:	03 44 9c 14          	add    0x14(%esp,%ebx,4),%eax //eax+M(20+esp+4*ebx) -> eax
 8048be0:	39 44 9c 18          	cmp    %eax,0x18(%esp,%ebx,4) //cmp
 8048be4:	74 05                	je     8048beb <phase_2+0x37> //jump if eax==M(24+esp+4*ebx)

分析这一段代码可以知道,这是把第一个数与eax(此处是1)相加,得到的结果与第二个数相比较,如果等于第二个数方可跳过炸弹。所以第二个数就是第一个数加1。

  1. 顺藤摸瓜,找到跳出循环的条件。
 8048beb:	83 c3 01             	add    $0x1,%ebx //ebx+1 -> ebx
 8048bee:	83 fb 06             	cmp    $0x6,%ebx //cmp
 8048bf1:	75 e7                	jne    8048bda <phase_2+0x26> //jump if ebx!=6
 8048bf3:	eb 07                	jmp    8048bfc <phase_2+0x48> //jump

由此段代码可以知道,ebx每次加1,然后跳到上面的一步,直到等于6跳出循环。

  1. 总体描述输入内容。

输入第一个数只要满足大于等于0即可,第二个数等于第一个数加1,第三个数等于第二个数加2,第四个数等于第三个数加3……,依此类推,最后输进去6个数即可。

  1. 输进去满足上述关系的6个数,发现答案确实如此。
Phase 1 defused. How about the next one?
1 2 4 7 11 16
That's number 2.  Keep going!
  1. 炸弹二拆除!
<phase_3>
  • 反汇编代码
08048c01 <phase_3>:
 8048c01:	83 ec 2c             	sub    $0x2c,%esp //
 8048c04:	8d 44 24 1c          	lea    0x1c(%esp),%eax //
 8048c08:	89 44 24 0c          	mov    %eax,0xc(%esp) //为输入内容做准备 
 8048c0c:	8d 44 24 18          	lea    0x18(%esp),%eax //
 8048c10:	89 44 24 08          	mov    %eax,0x8(%esp) //为输入内容做准备 
 8048c14:	c7 44 24 04 0f a3 04 	movl   $0x804a30f,0x4(%esp) //%d%d 
 8048c1b:	08 
 8048c1c:	8b 44 24 30          	mov    0x30(%esp),%eax //
 8048c20:	89 04 24             	mov    %eax,(%esp) //传递参数 
 
 8048c23:	e8 38 fc ff ff       	call   8048860 <__isoc99_sscanf@plt> //
 8048c28:	83 f8 01             	cmp    $0x1,%eax //eax与1比较 
 8048c2b:	7f 05                	jg     8048c32 <phase_3+0x31> //eax>1则跳过爆炸 
 8048c2d:	e8 e3 04 00 00       	call   8049115 <explode_bomb> //Bomb!
 
 8048c32:	83 7c 24 18 07       	cmpl   $0x7,0x18(%esp) //
 8048c37:	77 66                	ja     8048c9f <phase_3+0x9e> //M(0x18+exp)>0x7则跳转爆炸 
 8048c39:	8b 44 24 18          	mov    0x18(%esp),%eax //M(esp+0x18) -> eax 
 8048c3d:	ff 24 85 a0 a1 04 08 	jmp    *0x804a1a0(,%eax,4) //jump to *(0x804a1a0+4*eax)
 8048c44:	b8 00 00 00 00       	mov    $0x0,%eax //0 -> eax
 8048c49:	eb 05                	jmp    8048c50 <phase_3+0x4f> //jump
 8048c4b:	b8 4c 02 00 00       	mov    $0x24c,%eax //0x24c -> eax 
 8048c50:	2d 31 03 00 00       	sub    $0x331,%eax //eax-0x331 -> eax
 8048c55:	eb 05                	jmp    8048c5c <phase_3+0x5b> //jump
 8048c57:	b8 00 00 00 00       	mov    $0x0,%eax //0x0 -> eax
 8048c5c:	05 05 03 00 00       	add    $0x305,%eax //eax+0x305 -> eax
 8048c61:	eb 05                	jmp    8048c68 <phase_3+0x67> //jump
 8048c63:	b8 00 00 00 00       	mov    $0x0,%eax //0x0 -> eax
 8048c68:	2d 9e 00 00 00       	sub    $0x9e,%eax //eax-0x9e -> eax
 8048c6d:	eb 05                	jmp    8048c74 <phase_3+0x73> //jump
 8048c6f:	b8 00 00 00 00       	mov    $0x0,%eax //0x0 -> eax
 8048c74:	05 9e 00 00 00       	add    $0x9e,%eax //eax+0x9e -> eax
 8048c79:	eb 05                	jmp    8048c80 <phase_3+0x7f> //jump
 8048c7b:	b8 00 00 00 00       	mov    $0x0,%eax //0x0 -> eax
 8048c80:	2d 9e 00 00 00       	sub    $0x9e,%eax //eax-0x9e -> eax
 8048c85:	eb 05                	jmp    8048c8c <phase_3+0x8b> //jump
 8048c87:	b8 00 00 00 00       	mov    $0x0,%eax //0x0 --> eax
 8048c8c:	05 9e 00 00 00       	add    $0x9e,%eax //eax+0x9e -> eax
 8048c91:	eb 05                	jmp    8048c98 <phase_3+0x97> //jump
 8048c93:	b8 00 00 00 00       	mov    $0x0,%eax //0x0 -> eax
 8048c98:	2d 9e 00 00 00       	sub    $0x9e,%eax //eax-0x9e -> eax
 8048c9d:	eb 0a                	jmp    8048ca9 <phase_3+0xa8> //jump
 8048c9f:	e8 71 04 00 00       	call   8049115 <explode_bomb> //Bomb!
 
 8048ca4:	b8 00 00 00 00       	mov    $0x0,%eax //0x0 -> eax
 8048ca9:	83 7c 24 18 05       	cmpl   $0x5,0x18(%esp) //cmp 0x5,M(0x18+esp)
 8048cae:	7f 06                	jg     8048cb6 <phase_3+0xb5> //if greater, jump to Bomb
 8048cb0:	3b 44 24 1c          	cmp    0x1c(%esp),%eax //cmp eax,M(0x1c+esp)
  • 34
    点赞
  • 229
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值