最近在学深入理解计算机系统这本书,第三章的实验是拆弹实验,所以记录一下。
拆弹实验总的来说不是很难,主要是要会运用gdb来查看汇编代码和寄存器。实验环境是linux系统。
常用的指令:
break 设置断点,接函数名或者*地址
x 查看地址中的数据,后面可以接/c(数据为字符串),/d(数据为数字)
disas 查看当前函数的汇编代码
i r 查看寄存器的值
stepi n 运行n步(会进入别的函数)
nexti n 运行n部(跳过别的函数,只在当前函数)
其他的可以百度找到,炸弹实验用这几个足够了。
每个人的炸弹实验可能不一样,但是重要的是方法还有思路。
Phase_1:
在phase_1中停顿可以看出0x400f04处将$0x402470移入了寄存器,然后调用函数strings_not_equal,所以我们查看0x402470。
得出答案
Phase_2:
让gdb停在phase_2处
disas查看汇编代码
比较显眼的函数是read_six_numbers,所以我们输入六个数,
然后直接nexti 5跳到read_six_numbers.
查看寄存器,注意rsp的值
可以看出rsp存着我们输入的数,所以往后运行
可以看出第一个数为0,第二个数为1
根据这两行看出第三个数等于第一个和第二个相加
根据终止条件,所以可以得出是斐波那契数列。
Phase_3:
Phase_3比较长,所以先试着输入111 222
前面部分是在传参,这里有一个0x4024ce,查看一下,发现是与输入的匹配,所以更改一下输入为数字、字符、数字
我再一次输入是4,a,5
这里是对比输入参数数量,所以向后跳
查看0x8(%rsp),发现是第一个输入
直到跳到这
指向第三个输入,如果不等于0x396就bomb,所以更改第三个输入为918
成功跳到这,发现是对比,所以查看一下寄存器
发现是对比输入的字符和111,所以更改第二个输入为o(ascii为111)
通过
Phase_4:
照样先任意输入111 222
比较短,一开始还是照样传参,有一个0x40266f需要注意,查看一下
发现是传入两个数字,所以继续向下
这里对比参数个数,然后比较0xe和0x8(%rsp),查看一下
发现是第一个输入,所以第一个输入要小于等于0xe,所以更改为13
运行到这,发现调用fun4,要使返回结果为3,所以运行
fun4汇编代码,传入的是第一个输入,而且发现是递归,说明第一输入需要满足一定条件
发现每次fun4返回会改变返回值,返回值等于3才行
所以运行后发现第一个输入需要为13
第二个输入需要为3,所以通过
Phase_5:
先随意输入两个数111 222
前面还是一样设置参数,调用
函数
说明长度必须为6,修改输入为123456
查看寄存器
%rbx存的是输入的字符串
根据这一段汇编代码可以看出每次取输入字符中的一个,保留最后四位二进制数,然后作为0x402520地址的移位加到%rdx中,最后和0x3d比较,也就是十进制的61,所以我们查看0x402520等地址。
所以组合为12+12+12+12+12+1,查找输入的ascii码最后为4和3的,所以答案为dddddc
Phase_6:
先看代码,我们又看到了熟悉的
运行到这个位置,发现下面是一个比较,先将%eax-1再和5比较。所以是%eax小于6,也就是第一个输入的小于6
运行到这里看出第二个输入不等于第一个。
这一段汇编就是进行一些比较,输入必须得小于1,看到一个关键的0x6042f0,查看他
发现是一个结点
继续运行,发现一大段代码是将自己输入对应结点
直接往下运行,直接跳到0x40121e查看
此时输入一一对应,而且链表按输入顺序连接,再往下看。
这里进行比较,所以说必须前一个结点小于后一个节点。
按顺序所以答案是 1 3 2 6 4 5,完成解题
其实还有个隐藏炸弹题,后面再写
拆弹完成