CSAPP3e - x86-64 assembly code analysis - Bomb Lab: 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>
  400f0a:	83 3c 24 01          	cmpl   $0x1,(%rsp)
  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>
  400f17:	8b 43 fc             	mov    -0x4(%rbx),%eax        #jump from 400f3a
  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         #jump from 400f0e
  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   
在400f02,rsi指向了和rsp一样的地方,然后调用read_six_numbers这个函数,从名字上看出这个函数是要读入6个数字的,它的代码是

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  

可以看见这个函数将从rsi所指地址赋给rdx开始,将rdx rcx r8 r9存储每隔4个字节的地址,但是不是有六个数字吗?仔细看得知还有两个参数将会在rsp压栈时存好(因为寄存器不够用了),它们分别在40146b和401474被赋予了rsi+16和rsi+20的值,加上这两个参数总结起来从rdx开始每个参数所存地址间隔4字节,正好也是int数所占大小,而注意在调用read_six_numbers这个函数时rsi实际上存储着在phase_2内的rsp所指地址

然后把0x4025c3这个地址赋给rsi,接着将rax赋值为0。然后调用ssanf这个函数,查找资料可知这个函数的原型是:int sscanf(const char *buffer,const char *format,[argument ]...);

第一个参数buffer表明要格式读取的字符串,这个已经在main调用read_line时存在rdi里

format这个参数存在rsi中,通过x/s命令读0x4025c3这个被赋给rsi的地址可看到是"%d %d %d %d %d %d"这样一个格式字符串,说明要读取6个整形数

之前将rdx这一系列参数的地址准备好都是为了sscanf的格式对应的后面的参数。看到这里就知道,read_six_numbers的作用实际上是把我们输入的6个数字存储到从phase_2内的rsp所指地址开始的连续6个int型整数中。注意在401492我们发现必须读6个或以上数字,否则直接触雷

在400f0a处,我们发现输入的第一个数字必须为1,否则无法跳过400f10的爆炸

成功后跳转到400f30,重要的是将rsp的4字节之后所处地址给了rbx,回到400f17,rax则存着rsp自身,将rax翻倍后需要与rbx相等,否则又会爆炸

这里能看出,我们输入的第二个数必须是第一个数的两倍,也就是2

接下来400f25回继续进行rbx后移4字节,rax存储rbx在后移前的地址,回头接着比较rax所指数的两倍是否和rbx所指的相等... 也就是,下一个参数要接着翻倍

这实际上是一个for循环,其退出条件在400f35和400f29处,可以看到当rbx已经偏移了5次到达原先地址+24字节时,循环结束,这时正好对比了我们输入的6个数字

也就是说我们应该输入的是一个等比数列: 1 2 4 8 16 32 经验证确实如此,第二个phase就是这样



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值