在前面两篇文章中,我们已经分析完了六个phase,接下来分析最后一个phase。
实验过程
secret phase 破解
在此之前,我们分析bomb.c文件,发现一件有趣的事情:
在文件执行的过程中,我们似乎并没有察觉到phase_defused()函数的动静,接下来我们看看这个函数干了什么。
这里要注意:
这是一个防止栈溢出的操作。把%fs段偏移0x28处的一个数据存储到了%rsp上面0x68距离处(金丝雀)
903:将%esi置为0x402619,查看其代表含义
为输入两个数字和一个字符串,回看我们之前的几个phase,没有一个phase是这样的输入。
905:调用了scanf函数,输入
这里我们可以发现一个奇怪的事情,在前面几个phase中,只有phase_3和phase_4调用了scanf函数,并且都不约而同地没有限制输入参数的数量!所以,我们可以猜测,这里的三个输入与这两个phase的输入有关。
果然,接下来用%eax作为参数个数限制器,若参数数量不为3则直接跳过了隐藏的关卡,只有输入参数数量为3,即输入形式为“%d %d %s”形式才有可能发现隐藏关卡。
关键来了:
接下来就是字符串的比较,只有输入字符串等于给定字符串,函数才能继续执行,即在phase_3或者phase_4中的输入后面接着输入“DrEvil”。
分别查看内容:
出现了之前没有出现过的提示,说明我们找到了隐藏关卡的入口!
可是入口在哪个phase呢?
我们尝试不同的phase:
<phase_3>
不是phase_3
<phase_4>
关卡的入口在phase_4
找到隐藏关卡入口后,我们开始分析secret_phase
从命令行读入数据,初始化%edx为10,%esi为0,将读入的数据放入%rdi中。
调用strtol函数,将输入的字符串数据(把输入当成字符串处理)转化为长整型数。
转化后的数值放入%rbx中
输入数值的限定条件:小于等于1000
将输入数放入%esi(后续这个寄存器将作为输入数寄存器进行比较操作)
查看其含义,%edi所存地址对应的值为0x24(36)
调用fun7,返回值为2,函数才能成功
接下来则查看函数fun7
test测试若比较数的地址为空,则返回值为-1
将比较数放入%ebx(%ebx比较数寄存器)
记输入数为n,比较数为m
比较n与m的大小关系:
n > m 则m取距离%rdi偏移为16处地址的值,再次调用fun7(这个被调用的fun7返回值记为a,则外层函数的返回值为2a+1)
n = m 则返回值为0;
n < m 则m取距离%rdi偏移为8处地址的值,再次调用fun7(这个被调用的fun7返回值记为b, 则外层函数的返回值为2b)
这是一个递归调用
我们需要使得最终的返回值为2
则 最外层的函数满足条件:m0 > n 即输入数n 小于 %rdi存放地址对应的值0x24
此时中间层函数需满足条件:m1 < n 且该函数返回值为1
最里层函数需满足条件: m2 = n 且该函数返回值为0
最外层:n小于36
中间层:此时m取距离%rdi偏移为8处地址的值
则n大于8
最里层:此时m取距离%rdi偏移为16处地址的值
则n=22(0x16)
在secret_phase这一关,输入22
secret_phase破解!
个人感想:这次认认真真搞完了bomb实验,烧脑是的确烧脑,但对于汇编的阅读能力,代码的调试能力都有很大的帮助,总体而言,这是一个非常棒的实验!
PS:断点设置时的phase_1,phase_2这些应该先在符号表中查看
在其中找到与我们需要的,如图中所示
至此,实验bomb完成。