Lab要求:使用gdb获取程序内部信息,理解由反汇编器生成的汇编代码
Phase_1
注意到phase_1函数带了一个参数进入,保存在%rdi 中,然后给了%esi 赋了一个值,随后进入了一个叫string_not_equal的函数,合理猜测这函数就是字面意思。
先在函数进入前,阻拦一下,感觉0x402400应该就是要比较的字符串的首地址
去看一眼:
看到结果基本确定正确了,验证一下也确实正确。
Phase_2
同样地,phase_2也带了一个参数进入,又使用了一个%rsi 作为参数二,进入了一个 read_six_number的函数,同样怀疑是否就是字面意思。
值得注意的是,无论在命令行中输入了什么,都会以字符串的形式先保存,而这也是为什么又调用了read_six_numbers,在read_six_lines 中调用了scanf将字符串转换为int,再往图片的下部看发现调用的格式控制字符串是"%d %d %d %d %d %d"。
再想,读成数字保存在哪里?由于输入了两个参数,参数二是用%rsp 赋值的,sp是stack pointer的简写,显然是一处内存地址。
先输入一个"1 2 3 4 5 6"作为测试
在函数的出口设一个断点
查看进入函数时用于赋值参数二的%rsp,发现我的输入果然是保存在栈中。
首先发现,输入的第一个数必须为 1,不然就 call exlplode_bomb.
随后进入了一个以rbx为搜索指针,以rbp为结尾信号的循环,
循环体是,将%rbx的上一个数乘以二,与%rbx指向的数作比较,即:
if(input[i] != input[i-1] * 2) explode_bomb();
鉴于第一个数为1,每个数是上一个的2倍,且有6个数,
所以答案是"1 2 4 8 16 32"。
Phase_3
和之前的方法类似直接查看scanf的格式控制字符串,又在%rdi中地址所在内存找到了自己的输入。
圈1:scanf的返回值要大于1,不然BOOM!
圈2:input[0]要<=7,不然BOOM!
圈3:这是一个 地址跳转 指令!
到这里应该不难看出,答案不止一个,我们可以不断的修改%rip,在跳转指令执行前修改%rax值,再执行以查看跳转目的地。
- Input[0] = 1,则:
input[1]必须等于 0x137 = 311(dec)
- Input[0] = 2,则:
input[1]必须等于 0x2c3 = 707(dec)
太无聊了,就不继续了,但反正 input[0]=0、1…7 都是可以有答案的。
以1为例:
但值得一提的是,负数不行,编译器使用了一个很聪明的ja指令。
Phase_4
总之和 Phase_3 很像,也是输入两个数字,就不展开了,仍然是0x8(%rsp)里存input[0],0xc(%rsp)里存input[1]。
圈1:input[0] <= 14,和上一个Phase一样,负数是禁止的,编译器使用了一个jbe对一个signed int作unsigned int比较,这是一种比较隐蔽的技巧以剔除负数。
圈2:进入 func4 时,带了三个参数,参数一:input[0]、参数二:0、参数三:14。
圈3:离开func4之后才检查input[1],说明func4确实只与input[0]有关,正如参数表示的那样。
圈4:func4的返回值必须是0,不然就jump to BOOM!
Phase_4 是肯定有其他答案,但func4的迭代我感觉挺难看出它的用意的,本着详解的原则我尝试把它翻译成了C语言:
所以只有3个答案,“1 0”、“3 0”、“7 0”
没有问题!