计算机系统 实验三 逆向工程实验
Posted 上山打老虎D
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了计算机系统 实验三 逆向工程实验相关的知识,希望对你有一定的参考价值。
计算机系统(2) 实验三 逆向工程实验
一、 实验目标与要求:
- 理解程序(控制语句、函数、返回值、堆栈结构)是如何运行的
- 掌握GDB调试工具和objdump反汇编工具
二、实验环境:
- 计算机(Intel CPU)
- Linux64位操作系统(Ubuntu 17)
- GDB调试工具
- objdump反汇编工具
三、实验方法与步骤:
本实验设计为一个黑客拆解二进制炸弹的游戏。我们仅给黑客(同学)提供一个二进制可执行文件bomb_64和主函数所在的源程序bomb_64.c,不提供每个关卡的源代码。程序运行中有6个关卡(6个phase),每个关卡需要用户输入正确的字符串或数字才能通关,否则会引爆炸弹(打印出一条错误信息,并导致评分下降)!
要求同学运用GDB调试工具和objdump反汇编工具,通过分析汇编代码,找到在每个phase程序段中,引导程序跳转到“explode_bomb”程序段的地方,并分析其成功跳转的条件,以此为突破口寻找应该在命令行输入何种字符串来通关。
本实验需解决Phase_1(15分)、Phase_2(15分)、Phase_3(15分)、Phase_4(15分)、Phase_5(15分)、Phase_6(10分)。通过截图+文字的形式把实验过程写在实验报告上,最后并撰写实验结论与心得(15分)。
四、实验过程及内容:
- 进行反汇编:
首先需要对二进制文件进行反汇编。在terminal中输入如下代码:
objdump -d bomb_64 > 1.txt
将事先编译好的二进制文件进行反汇编,并将汇编代码重定向到1.txt文件中。
此时只需对反汇编出来的代码进行分析,并完成六个关卡即可。
- 对六个关卡进行一一破解:
(1)phase1:(string,函数调用,栈)
①获取汇编代码:
②分析代码逻辑:
-
首先,第340行为函数调用进行开栈。第341行将0x401af8地址中的内容复制到%esi寄存器。第342行调用函数,判断字符串是否相等,若返回值为零,则跳转到400e87地址处;若不为零,则跳转到explode_bomb函数。
-
因此可以此处即为,判断输入是否与0x401af8中的字符串相等,相等则成功,不相等则炸弹爆炸,因此只需找到即可。
-
接下来,使用gdb进行获取0x401af8地址中的字符串。在gdb中输入如下代码:p(char *) 0x401af8
因此,只要输入Science isn’ t about why,it’ s about why not?即可
③进行测试:
输入Science isn’ t about why,it’ s about why not?
答案正确!
(2)phase2:(循环语句,数组)
①获取汇编代码:
②分析代码逻辑: -
从代码的第356行,可以看到该函数首先调用了函数读入了6个数字,因此该关卡的答案由6个数组构成。并且可以看到,该读入6个数字的函数存放在内存地址为401743的地方,可以进入该地址查看read_six_numbers函数。
-
在主调函数phase_2中,可以发现,读入的6个数字将被存放在从%rsp指向的地址开始向上的位置。
-
如上的代码中用mov将0xc(%rbp)存入%eax中,并通过cmp比较两个值,如果两个值相等得到结果0,跳转到0x400eca,否则将执行<explode_bomb>函数引爆炸弹。
-
然后使用rbp作为迭代指针,rbp+12为迭代终点,一共迭代三次,而每次我们都将M[rbp] 和 M[rbp+12] 处的数据比对,如果不等则bomb。而对于int型,刚好是4字节,三个即为12字节。因此,这段函数正在判断读入的6个数字中前三个数字是否与后三个数字对应相等。
-
r12寄存器在运行前被之前清零,每次运行又 += M[rbx],即在计算累加和。又根据后文test $r12d $r12d,可得,输入的6个数要满足累加和不等于0,否则将引爆炸弹。
-
综上,本题不引爆炸弹安全拆弹的条件是输入6个累加和不为零的数字,并满足前三个数字与后三个数字对应相等。
③进行测试:
根据上面的分析,可知1 1 1 1 1 1为一种合法的情况,进行输出并测试。
(3)phase3:(switch语句)
①获取汇编代码:
②分析代码逻辑:
-
首先,在scanf调用前,传入第三第四个参数了,并存在rsp+8和rsp+12位置,从间距来看应该是int,然后又向esi传入常量,推测是scanf格式确定的字符串。因此可以利用gdb查看0x401ebe内存下的值。
这说明,本任务的输入为两个整数。 -
第11行中判断输入的第一个整数是否比7小,否则直接bomb。
-
第14行进行跳转,目的地址是M[0x401b60 + rax*8],其中rax是输入的第一个整数。当跳转到对应的地址后,将eax赋对应值,并跳转到第33行判断是否与第二个输入整数相等,如果不等则bomb。因此,程序大致为一switch型程序。现在我们只需找出switch对应的8个值即可。
-
利用gdb分别查看对应第一个输入为0~7时跳转的目的地址值
- 因此,本题即为一个switch型函数,只要输入满足switch对应的8组数值即可。因此,合法输入如下:
(4)phase4:(递归)
①获取汇编代码:
②分析代码逻辑:
- 同样首先观察参数,发现这次scanf只读了一个参数,根据前面的经验不难看出,0x401ec1存储的是scanf的常字符串,使用gdb查看0x401ec1中的值。这说明,本题的输入仅有一个整数。
-
主调函数的第14行判断fun_4的返回值是否为55,如果不是则bomb;
-
接下来观察被调函数fun_4。首先是压栈保存数据,再将传入的参数与1对比,小于等于1则跳转到0x400fb2,退出函数并返回。否则将传入的参数减一后再次调用func4函数,再将返回值存放在%ebp里,然后将原始参数减二后再次递归调用func4函数,将返回值与上一次递归得到的返回值%ebp相加存在%eax中。结合数学分析,该函数是求斐波那契数列第n项的值。
-
因此,只需找出斐波那契数列第几项的值为55即可,通过数学计算,是第9项。因此答案为9.
③进行测试:
通过上面的分析,输入9即可
(5)phase5:(字串变换,ascii转换,寻址)
①获取汇编代码:
②分析代码逻辑:
- 首先观察scanf的输入,两个lea语句将scanf的第三第四个参数确定,采用与前面相同的方法,使用gdb对scanf的参数进行查看如下:
-
第14行对输入进行了截断,将第一个输出截断到0~15的,因此如果第一个输出被截断后等于15,将直接爆炸。
-
通过阅读后面的语句,可以发现存在一个循环,edx每次++,eax每次指向内存中的一个地址,又因为eax和rax是同一个,则相当于 k = next[k]这种数组跳转语句,并且偏移的单位是4字节,刚好是一个int,这更加确定了这里出现的是数组跳转语句。我们通过gdb查看这个数组。
-
使用gdb查看连续数组,结果如下:
可绘制表格如下:
i | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
[i] | 10 | 2 | 14 | 7 | 8 | 12 | 15 | 11 | 0 | 4 | 1 | 13 | 3 | 9 | 6 | 5 |
因此,继续对代码进行分析可知总跳转次数为12。并且,第二个输入值必须等于每次跳转的目标的累加和,而且最后一次跳转的结果是15。因此可以从15进行逆推12次并累加。
因此有11+13+9+4+8+0+10+1+2+14+6+15 = 93。因此最终答案为7 93
③进行测试:
输入7 93
答案正确!我们现在只剩下最后一题需要解决了!
(6)phase6:(寻址)
①获取汇编代码:
②分析代码逻辑:
-
通过观察代码,可以知道,如果程序执行401112语句将会引爆炸弹,所以需要满足跳转条件,即,当edx==rax时跳转。
-
上面的代码将edx赋值为0xa,而esi为0。然后调用strtol函数。该函数的功能为把string转化为long,然后,存储到0x602780中。
-
于是猜测phase 6的功能是,将输入的字符串转化为数字后,经过func 6的处理,使其与某个值相等。func 6函数异常复杂,太多映射令人头疼。故而考虑利用gdb调试来测试rax和edx之间的关系。
-
在cmp %edx,(%rax)处(0x40110e)添加断点,查看%rax的值:
- 任意输入一个数字,例如123456:
- 输入rax与edx进行查看,可以发现,edx等于我们所输入的值123456,而rax等于673。因此 ,需要让二者相等,可以直接输入673进行尝试。
③进行测试:
五、实验结论:
经过上面的六次拆弹,将6个炸弹全部成功拆除如下:
以上是关于计算机系统 实验三 逆向工程实验的主要内容,如果未能解决你的问题,请参考以下文章