CSAPP实验二——bomb lab实验

实验前准备

在linux操作系统上安装GDB调试器。由于我是在Ubuntu虚拟机上进行实验,所以只需要在终端输入如下安装指令即可快速安装。
sudo apt install gdb

在可执行程序所在的目录下进入终端,输入gdb bomb即可启动调试过程(bomb是可执行程序名称),可以输入quit结束GDB调试。

第一部分(phase_1)

使用disas phase_1反汇编phase_1函数

   0x0000000000400ee0 <+0>:		sub    $0x8,%rsp
   0x0000000000400ee4 <+4>:		mov    $0x402400,%esi 			//修改%esi的值作为参数传入后面函数
   0x0000000000400ee9 <+9>:		callq  0x401338 <strings_not_equal>
   0x0000000000400eee <+14>:	test   %eax,%eax     #修改条件码
   0x0000000000400ef0 <+16>:	je     0x400ef7 <phase_1+23>  	//根据条件码进行跳转,如果%eax寄存器里存放的是0则跳过爆炸的程序
   0x0000000000400ef2 <+18>:	callq  0x40143a <explode_bomb>
   0x0000000000400ef7 <+23>:	add    $0x8,%rsp
   0x0000000000400efb <+27>:	retq   

发现第一部分还是很简单的,基本操作就是调用strings_not_equal函数,根据返回值来决定是否引爆炸弹。至于strings_not_equal函数,从名字就可以看出来是实现比较两字符串是否相等的功能,通过disas strings_not_equal也可以验证一下猜想。

比较的两个字符串一个是用户输入的字符串,一个是地址存放在%esi寄存器里的内存中的值,也就是地址为0x402400的内存值。

可以使用x/s 0x402400来查看对应的字符串,得到以下内容:

0x402400: “Border relations with Canada have never been better.”

所以只要输入的字符串与之完全一样,则可以通过,进入下一关。

第二部分(phase_2)

使用disas phase_2反汇编phase_2函数

   0x0000000000400efc <+0>:		push   %rbp
   0x0000000000400efd <+1>:		push   %rbx
   0x0000000000400efe <+2>:		sub    $0x28,%rsp
   0x0000000000400f02 <+6>:		mov    %rsp,%rsi
   0x0000000000400f05 <+9>:		callq  0x40145c <read_six_numbers>
   0x0000000000400f0a <+14>:	cmpl   $0x1,(%rsp)  			//将第一个输入与1比较
   0x0000000000400f0e <+18>:	je     0x400f30 <phase_2+52>    //确定第一个数字必须为1
   0x0000000000400f10 <+20>:	callq  0x40143a <explode_bomb>
   0x0000000000400f15 <+25>:	jmp    0x400f30 <phase_2+52>
   0x0000000000400f17 <+27>:	mov    -0x4(%rbx),%eax		  //eax寄存器存放上一个输入数字的值
   0x0000000000400f1a <+30>:	add    %eax,%eax			  //上一个输入数字*2
   0x0000000000400f1c <+32>:	cmp    %eax,(%rbx)			  //当前数字与上一个数字*2比较
   0x0000000000400f1e <+34>:	je     0x400f25 <phase_2+41>  //只有相等才不会爆炸
   0x0000000000400f20 <+36>:	callq  0x40143a <explode_bomb>
   0x0000000000400f25 <+41>:	add    $0x4,%rbx			  //存放下一个输入数字所在内存位置的指针值,从而进入下一次循环
   0x0000000000400f29 <+45>:	cmp    %rbp,%rbx			  //看是否到达循环的终点
   0x0000000000400f2c <+48>:	jne    0x400f17 <phase_2+27>  //未到终点,进入下一次循环
   0x0000000000400f2e <+50>:	jmp    0x400f3c <phase_2+64>  //到达终点,结束循环
   0x0000000000400f30 <+52>:	lea    0x4(%rsp),%rbx		  //第二个输入存放的内存位置
   0x0000000000400f35 <+57>:	lea    0x18(%rsp),%rbp        //0x18=24,控制循环的终点
   0x0000000000400f3a <+62>:	jmp    0x400f17 <phase_2+27>
   0x0000000000400f3c <+64>:	add    $0x28,%rsp
   0x0000000000400f40 <+68>:	pop    %rbx
   0x0000000000400f41 <+69>:	pop    %rbp
   0x0000000000400f42 <+70>:	retq   

通过进一步查看read_six_numbers函数的汇编代码,可以知道其完成的是读取用户输入的六个整数,每个数字占用四个字节大小空间,所以最终循环的终点为栈指针偏移4*6=0x18=24的位置。

这部分代码实现的是一个循环,将输入的六个数字依次与其前一位的两倍进行比较。当且仅当第一个数字为1,后一位依次是前一位的两倍的情况下,才不会引起爆炸。所以得到第二问的答案为

1 2 4 8 16 32

第三部分(phase_3)

前两部分内容都算简单,下面来看第三块

   0x0000000000400f43 <+0>:		sub    $0x18,%rsp
   0x0000000000400f47 <+4>:		lea    0xc(%rsp),%rcx
   0x0000000000400f4c <+9>:		lea    0x8(%rsp),%rdx
   0x0000000000400f51 <+14>:	mov    $0x4025cf,%esi
   0x0000000000400f56 <+19>:	mov    $0x0,%eax
   0x0000000000400f5b <+24>:	callq  0x400bf0 <__isoc99_sscanf@plt>
   0x0000000000400f60 <+29>:	cmp    $0x1,%eax
   0x0000000000400f63 <+32>:	jg     0x400f6a <phase_3+39>
   0x0000000000400f65 <+34>:	callq  0x40143a <explode_bomb>
   0x0000000000400f6a <+39>:	cmpl   $0x7,0x8(%rsp)		//第一个输入与7比较
   0x0000000000400f6f <+44>:	ja     0x400fad <phase_3+106>	//用ja而不是jg,暗示这一部分可能和switch语句有关
   0x0000000000400f71 <+46>:	mov    0x8(%rsp),%eax
   0x0000000000400f75 <+50>:	jmpq   *0x402470(,%rax,8)		//根据第一个输入的值来进行jmp的间接跳转
   0x0000000000400f7c <+57>:	mov    $0xcf,%eax				//第一个输入为0时跳转到这里		
   0x0000000000400f81 <+62>:	jmp    0x400fbe <phase_
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值