这个实验的要做的是用gdb逆向一段code,通过查看汇编代码以及单步调试找出这段code需要你填入的字符串,好像每个人都不一样,所以每个人都需要找到自己的拆弹密码,很有意思。
实验一共有6关,我们一关关来看一下:
phase_1
打开bomb.c看些c源码(这里的核心方法已经被删除了,只能看到最外层的代码,但能得到一些线索)。
很容易就发现这个phase_1方法是第一题的核心方法,直接逆向它,看下它的汇编。
第一句话是在为函数栈开辟空间,第二句话是关键,讲一个立即数赋值给%esi,然后就调用strings not equal方法,推测很用可能这个寄存器中就存着我们拆弹的字符串,于是打断点,单步执行,查看%esi的里的内容:
没错,这就是我们拆弹的钥匙了,输入,第一个炸弹成功拆除!可以将答案放在一个文本文件中,方便之后的解题。
phase_2
实现逆向phase_2函数观察下
观察read_six_numbers发现这次是要我们输入6个数字,通过观察后发现输入的6个数字会依次3存在%rsp,%rsp+4,%rsp+8,%rsp+12...%rsp+24这些位置,那么cmpl $0x1,(%rsp)这句话就很明显可以得出第一个数字是1,再接下去看跳转到52,将%rsp+4也就是第二个数字放进%rbx中,将%rbp设置成%rsp+24(可以猜到%rbp使用来判断循环是否退出的寄存器),之后跳转到27,这里将第一个数赋值给%eax,将%eax*2去和第一个数对比,如果相等就继续,以此类推,可以发现这个循环就是用来判断输入的数字是否依次增大一倍的,所以第二题的拆弹密码就是:1 2 4 8 16 32
phase_3
我首先随意输入一个字符串,调试发现%esi中的字符串内容为"%d %d",由此得知此题需要我们输入两个数字,%eax是scanf的返回值,如果=1则代表非法输入,炸弹爆炸。我们输入两个数字,这里跳转就能通过了。然后发现第一个数字不能大于7,我们随意填了个0,重新调试再试试,然后发现jmp到了57,走下去会发现%eax就是第二个数的答案,所以此题答案为0 0xcf。
其实这道题最简单的解法就是输入两个数,跟着单步调试走,你很容易就能确定两个数字的内容,但是其实你再多看两眼,就会发现其实这里是一个switch结构,答案是不唯一的,跳转表存在*0x402470中,我们打印出这张跳转表,就能得知这道题的所有答案:第一个数字是index,第二个数字就是对应分支赋值给%eax的值。
phase_4
这道题是个递归,花了点时间,但是复杂度还行,只要一步步跟下来就能得出结果。
拆弹关键在func4函数中,发现func4返回的参数eax必须为0才能不爆炸,我们倒退进func4
发现只有当%ecx和%edi的值相等的时候才会将%eax赋值为0,而%edi就是我们的第一个参数,那么我们只需要知道%ecx的值即可,通过推导得出ecx的值可以为7 3 0。
返回phase_4继续走下去发现第二个数为0就能拆弹了。
phase_5
通过这段我们可以知道这一题是要我们输入一串长度为6的字符串。
这一段是核心代码,跳转至112后将%eax赋值为0后跳转到41,然后讲%rbx+%rax的值赋值给%ecx,%rbx是我们输入内容的基地址,%rax是索引,然后做的事情其实就是将当前字符截取底4位。55行这里有个奇怪的地址,将这个地址输出看下得到:,那么这里就是以当前字符低4位的值为索引去读取这个字符串,然后得到的字符放进以$rsp+16为起始地址的内存区域。
解下来可以跳出循环看76-91行了,查看81行的字符串为"flyers",%rdi就是我们循环得到的字符串,然后调用string_not _equal方法,得知只要我们循环得出的字符串等于“flyers”即可拆弹。
分别找到“flyers”在上述字符串中的索引,然后对照ASCII码表,可得到本题答案,答案不唯一,只要低4位符合条件的字符都能拆弹。
phase_6
这题在借助谷歌的力量后才不太顺利的完成了。。
先看第一部分
这部分没有什么难度,但也有一定复杂度,稍微花点时间理一下逻辑,就能发现它是要我们输入6个数字,然后这6个数字要求互不相等,并且都不大于6。
接下来就比较困难了,没想到是用到了链表,而且还涉及到数据对齐的知识。
链表存储在0x6032d0中,链表得到后再进行排序,最后我们可以得到排序后的链表其实是单调递减了,然后反推就能得出我们的答案啦~