csapp bomb lab

本文详细介绍了csapp bomblab的六个关卡及secret_phase的破解过程,包括每个阶段的汇编代码分析、输入验证和解谜思路。从phase_1到phase_6,逐步揭示了如何根据汇编代码推断输入字符串和数字的规律,最终成功解锁所有关卡。

真相只有一个!从扑朔迷离的线索里推理出真相总是那么刺激。我们将在bomblab体会如何根据星星点点的线索,胡乱假设合理推断,大胆验证,从而揭开真相神秘的面纱。bomblab的场景为拆炸弹,任何一个输入不正确均会引发炸弹爆炸。根据二进制文件反汇编形成的汇编代码来推断应该输入的字符串,解锁6个关卡和待解锁的神秘关卡。

bomblab链接地址:bomblab
gdb指南:gdbnotes

首先反汇编得到bomb二进制文件对应的汇编代码
objdump -d bomb > bomb.txt
将反汇编得到的汇编代码重定向到bomb.txt

phase_1

phase_1对应的汇编代码如下

0000000000400ee0 <phase_1>:
  400ee0:	48 83 ec 08          	sub    $0x8,%rsp
  400ee4:	be 00 24 40 00       	mov    $0x402400,%esi
  400ee9:	e8 4a 04 00 00       	callq  401338 <strings_not_equal>
  400eee:	85 c0                	test   %eax,%eax
  400ef0:	74 05                	je     400ef7 <phase_1+0x17>
  400ef2:	e8 43 05 00 00       	callq  40143a <explode_bomb>
  400ef7:	48 83 c4 08          	add    $0x8,%rsp
  400efb:	c3                   	retq   

在地址0x400ee9处调用了string_not_equal函数,在调用之前将立即数0x402400存入了%esi中,%rsi为第二个参数所用寄存器,我们推测%rdi存储我们输入的字符串。
使用gdb bomb开始调试程序,在phase_1函数处设置断点验证。
观察到%rdi为地址的字符串正是我们输入的字符串。由函数名称strings_not_equal 推测该函数用于判断输入的字符串是否和0x402400处的字符串相等,使用x/s 0x402400显示0x402400处对应的字符串内容
“Border relations with Canada have never been better.”

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//保存栈顶指针
  400f05:	e8 52 05 00 00       	callq  40145c <read_six_numbers>   

查看phase_2的汇编代码,第6行调用了read_six_numbers 来读入输入数据,根据函数名可知该函数应该是用于读入六个数字,接下来转到read_six_numbers 的汇编代码部分,推断读入的六个数存储在rsp开始的24个字节中。

000000000040145c <read_six_numbers>:
  40145c:	48 83 ec 18          	sub    $0x18,%rsp//分配栈空间
  401460:	48 89 f2             	mov    %rsi,%rdx
  401463:	48 8d 4e 04          	lea    0x4(%rsi),%rcx
  401467:	48 8d 46 14          	lea    0x14(%rsi),%rax
  40146b:	48 89 44 24 08       	mov    %rax,0x8(%rsp)
  401470:	48 8d 46 10          	lea    0x10(%rsi),%rax
  401474:	48 89 04 24          	mov    %rax,(%rsp)
  401478:	4c 8d 4e 0c          	lea    0xc(%rsi),%r9
  40147c:	4c 8d 46 08          	lea    0x8(%rsi),%r8
  401480:	be c3 25 40 00       	mov    $0x4025c3,%esi
  401485:	b8 00 00 00 00       	mov    $0x0,%eax
  40148a:	e8 61 f7 ff ff       	callq  400bf0 <__isoc99_sscanf@plt>
  40148f:	83 f8 05             	cmp    $0x5,%eax
  401492:	7f 05                	jg     401499 <read_six_numbers+0x3d>
  401494:	e8 a1 ff ff ff       	callq  40143a <explode_bomb>
  401499:	48 83 c4 18          	add    $0x18,%rsp
  40149d:	c3                   	retq 

read_six_numbers返回后设置断点break *0x400f0a,输入1 2 3 4 5 6,执行后x /32xb $rsp查看rsp后32个字节的内容,如下所示,int大小为4个字节,以小端法存储

0x7fffffffe3c0: 0x01    0x00    0x00    0x00    0x02    0x00    0x00    0x00
0x7fffffffe3c8: 0x03    0x00    0x00    0x00    0x04    0x00    0x00    0x00
0x7fffffffe3d0: 0x05    0x00    0x00    0x00    0x06    0x00    0x00    0x00
0x7fffffffe3d8: 0x31    0x14    0x40    0x00    0x00    0x00    0x00    0x00

接下来查看调用输入结束后的汇编代码

  400f0a:	83 3c 24 01          	cmpl   $0x1,(%rsp)//将栈顶元素与1比较
  400f0e:	74 20                	je     400f30 <phase_2+0x34>
  400f10:	e8 25 05 00 00       	callq  40143a <explode_bomb>
  400f15:	eb 19                	jmp    400f30 <phase_2+0x34>//在explode_bomb调用返回后才会执行
  400f17:	8b 43 fc             	mov    -0x4(%rbx),%eax
  400f1a:	01 c0                	add    %eax,%eax
  400f1c:	39 03                	cmp    %eax,(%rbx)
  400f1e:	74 05                	je     400f25 <phase_2+0x29>
  400f20:	e8 15 05 00 00       	callq  40143a <explode_bomb>
  400f25:	48 83 c3 04          	add    $0x4,%rbx
  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
  400f35:	48 8d 6c 24 18       	lea    0x18(%rsp),%rbp
  400f3a:	eb db                	jmp    400f17 <phase_2+0x1b>
  400f3c:	48 83 c4 28          	add    $0x28,%rsp
  400f40:	5b                   	pop    %rbx
  400f41:	5d                   	pop    %rbp
  400f42:	c3                   	retq

phase_2段的代码首先将rsp对应地址中存放的值与1比较,如果相等则跳过引爆炸弹的代码,那么首元素必定为1。
然后跳转至400f30处,将rsp+0x4rsp+0x18的值分别存放到了rbx与rbp,此后跳转至400f17,将rbx的地址减4中存放的内容复制到了eax中,rbx的地址减4也就意味着与rsp相等,它的值也就是第一个读入的值。下一行将eax的值乘二,接下来将乘二后的值与rbx也就是第二个值进行比较,如果相同则跳过引爆代码。此后将rbx加4,指向下一个数存放的位置,一直循环直到rbx的值大于边界rbp的值为止。
可知,后一个数为前一个数的2倍时炸弹不引爆,输入的六个数分别为1,2,4,8,16,32

phase_3

0000000000400f43 <phase_3>:
  400f43:	48 83 ec 18          	sub    $0x18,%rsp
  400f47:	48 8d 4c 24 0c       	lea    0xc(%rsp),%rcx
  400f4c:	48 8d 54 24 08       	lea    0x8(%rsp),%rdx
  400f51:	be cf 25 40 00       	mov    $0x4025cf,%esi
  400f56:	b8 00 00 00 00       	mov    $0x0,%eax
  400f5b:	e8 90 fc ff ff       	callq  400bf0 <__isoc99_sscanf@plt>  

在调用{% label default@400bf0 __isoc99_sscanf@plt %}之前将%esi赋值为立即数0x4025cf,{% label default@x /s 0x4025cf %}查看0x4025cf处的值,为{% label default@"%d %d" %},读入两个整形值。这两个值存放在哪里呢?之前将rsp+0xc与rsp+0x8的值分别给rcx与rdx,推测输入的两个数同样存放在栈中。
为了验证这一推测,{% label default@break *0x400f60 %}设置断点,{% label default@x/8xd $rsp %}查看rsp开始6字节的内容,如下所示

0x7ffffffee0a8: 1       0       0       0       2       0       0       0

接下来查看调用输入结束后的汇编代码

  400f60:   83 f8 01                cmp    $0x1,%eax
  400f63:   7f 05                   jg     400f6a <phase_3+0x27>
  400f65:   e8 d0 04 00 00          callq  40143a <explode_bomb>
  400f6a:   83 7c 24 08 07          cmpl   $0x7,0x8(%rsp)
  400f6f:   77 3c                   ja     400f
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值