一、实验要求
本实验设计为一个黑客拆解二进制炸弹的游戏。我们仅给黑客(同学)提供一个二进制可执行文件bomb_64和主函数所在的源程序bomb.c,不提供每个关卡的源代码。程序运行中有6个关卡(6个phase),每个关卡需要用户输入正确的字符串或数字才能通关,否则会引爆炸弹(打印出一条错误信息,并导致评分下降)!
要求同学运用GDB调试工具和objdump反汇编工具,通过分析汇编代码,找到在每个phase程序段中,引导程序跳转到“explode_bomb”程序段的地方,并分析其成功跳转的条件,以此为突破口寻找应该在命令行输入何种字符串来通关。
二、实验说明
6个关卡,难度随关卡升级而提升;
通过解读汇编代码来推断其对应的函数结构(推断过程不唯一),某些关卡答案不唯一;
尽力而为,能通几关就几关。
提示:
第一关(知识点:string,函数调用,栈)
第二关(知识点:循环语句,数组)
第三关(知识点: switch语句)
第四关(知识点:递归)
第五关(知识点:字串变换,ascii转换,寻址)
第六关(知识点:寻址)
(第1-5关,各15分。第6关10分。实验总结15分。)
注1:
当前用户可能对bomb文件没有执行权限,建议先用ls查看文件权限,若没有执行权限,请用chmod +x bomb命令增加当前用户对bomb文件的执行权限。
注2:
若用命令./bomb执行该文件提示no such file时,请先用 su szu 切换到szu账户,然后输入命令sudo apt-get install lib32z1,等待下载安装完毕即可。
三、实验环境:
1. 计算机(Intel CPU)
2. Linux64位操作系统(Ubuntu 17)
3. GDB调试工具
4. objdump反汇编工具
四、实验方法与步骤
1. 首先对bomb文件进行反汇编,并将结果输出到1.txt。
$ objdump -d bomb_64 > 1.txt
2.
为方便查阅汇编代码,在图形化界面中将txt结果用文本编辑器打开。(此步骤仅为了方便查看代码,你可以将代码copy到你常用的编译器上查看)
0000000000400e70 :
400e70: 48 83 ec 08 sub $0x8,%rsp
400e74: be f8 1a 40 00 mov $0x401af8,%esi
400e79: e8 bf 03 00 00 callq 40123d
400e7e: 85 c0 test %eax,%eax
400e80: 74 05 je 400e87
400e82: e8 b6 07 00 00 callq 40163d
400e87: 48 83 c4 08 add $0x8,%rsp
400e8b: c3 retq
2~4行部分代码是对字符串进行比较
第5行测试%eax == 0,相等为0
第7行引导程序跳转到“explode_bomb”程序段的地方
【代码分析】
首先是为新函数开辟一个帧,申请0x48的内存空间。
400e70: 48 83 ec 08 sub $0x8,%rsp
400e74: be f8 1a 40 00 mov $0x401af8,%esi
接下来调用了0x400e79位置的函数
函数的执行结束,否则调用
【通关操作】
若是输入错误,则会提示爆炸
【深入分析】
要是单纯只要找答案的童鞋可以略过以下部分!!!
000000000040123d :
40123d: 48 89 5c 24 e8 mov %rbx,-0x18(%rsp)
401242: 48 89 6c 24 f0 mov %rbp,-0x10(%rsp)
401247: 4c 89 64 24 f8 mov %r12,-0x8(%rsp)
40124c: 48 83 ec 18 sub $0x18,%rsp
401250: 48 89 fb mov %rdi,%rbx
401253: 48 89 f5 mov %rsi,%rbp
401256: e8 c6 ff ff ff callq 401221
40125b: 41 89 c4 mov %eax,%r12d
40125e: 48 89 ef mov %rbp,%rdi
401261: e8 bb ff ff ff callq 401221
401266: ba 01 00 00 00 mov $0x1,%edx
40126b: 41 39 c4 cmp %eax,%r12d
40126e: 75 36 jne 4012a6
:
401221: b8 00 00 00 00 mov $0x0,%eax
401226: 80 3f 00 cmpb $0x0,(%rdi)
401229: 74 10 je 40123b
40122b: 48 89 fa mov %rdi,%rdx
40122e: 48 83 c2 01 add $0x1,%rdx
401232: 89 d0 mov %edx,%eax
401234: 29 f8 sub %edi,%eax
401236: 80 3a 00 cmpb $0x0,(%rdx)
401239: 75 f3 jne 40122e
40123b: f3 c3 repz retq
string_length 中的代码:
是以%rdi中的内容为地址,然后与0比较(0即是字符串的终结符号“\0”)。所以字符串起始地址应该藏在%rdi中!
再看 strings_not_equal,分别有两次 string_length 调用,再结合函数名 strings_not_equal,可以想见是我们输入的字符串与藏在程序中的字符串进行比较!所以只要在0x401256,0x401261两处设置断点,打印出以%rdi中内容为起始地址的字符串。其中一个是我们输入的字符串,而另一个就是我们寻找的字符串。
现在,就让我们设置断点实操一下:
由于第一串字符是我们自己输入的,我在这里输入的是“hello bomb_mo!"
可以看到,我们之前得到的答案出现了。