本文主要是介绍bupt拆解二进制炸弹bomb,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
一、实验目的
1.理解C语言程序的机器级表示。
2.初步掌握GDB调试器的用法。
3.阅读C编译器生成的x86-64机器代码,理解不同控制结构生成的基本指令模式,过程的实现。
- 实验环境
- Windows PowerShell(10.120.11.12)
- Linux
- Objdump命令反汇编
- GDB调试工具
- 。。。。。
三、实验内容
登录bupt1服务器,在home目录下可以找到Evil博士专门为你量身定制的一个bomb,当运行时,它会要求你输入一个字符串,如果正确,则进入下一关,继续要求你输入下一个字符串;否则,炸弹就会爆炸,输出一行提示信息并向计分服务器提交扣分信息。因此,本实验要求你必须通过反汇编和逆向工程对bomb执行文件进行分析,找到正确的字符串来解除这个的炸弹。
本实验通过要求使用课程所学知识拆除一个“binary bombs”来增强对程序的机器级表示、汇编语言、调试器和逆向工程等方面原理与技能的掌握。 “binary bombs”是一个Linux可执行程序,包含了5个阶段(或关卡)。炸弹运行的每个阶段要求你输入一个特定字符串,你的输入符合程序预期的输入,该阶段的炸弹就被拆除引信;否则炸弹“爆炸”,打印输出 “BOOM!!!”。炸弹的每个阶段考察了机器级程序语言的一个不同方面,难度逐级递增。
为完成二进制炸弹拆除任务,需要使用gdb调试器和objdump来反汇编bomb文件,可以单步跟踪调试每一阶段的机器代码,也可以阅读反汇编代码,从中理解每一汇编语言代码的行为或作用,进而设法推断拆除炸弹所需的目标字符串。实验2的具体内容见实验2说明。
四、实验步骤及实验分析
建议按照:准备工作、阶段1、阶段2、¼等来组织内容
各阶段需要有操作步骤、运行截图、分析过程的内容
首先将炸弹解压,用tar -xvf bomb215.tar 命令
拆解完成后进入炸弹文件夹里,
运用gdb调试炸弹,一开始我先将源码打印出来,源码如下
(gdb) list
73 input = read_line(); /* Get input */
74 phase_1(input); /* Run the phase */
75 phase_defused(); /* Drat! They figured it out!
76 * Let me know how they did it. */
77 printf("Phase 1 defused. How about the next one?\n");
78
79 /* The second phase is harder. No one will ever figure out
80 * how to defuse this... */
81 input = read_line();
82 phase_2(input);
(gdb)
83 phase_defused();
84 printf("That's number 2. Keep going!\n");
85
86 /* I guess this is too easy so far. Some more complex code will
87 * confuse people. */
88 input = read_line();
89 phase_3(input);
90 phase_defused();
91 printf("Halfway there!\n");
92
(gdb)
93 /* Oh yeah? Well, how good is your math? Try on this saucy problem! */
94 input = read_line();
95 phase_4(input);
96 phase_defused();
97 printf("So you got that one. Try this one.\n");
100 input = read_line();
101 phase_5(input);
102 phase_defused();
(gdb)
103 printf("Good work! On to the next...\n");
107 input = read_line();
108 phase_6(input);
109 phase_defused();
(gdb)
113
114 return 0;
115 }
可以看到,第一个炸弹在键盘输入之后会进入phase_1(input) 里面,phase_1会传入我们输入的字符串,而phase_defused() 无参数,因此推断出phase_1 里会判断是否爆炸,而phase_defuse() 则是告知是否拆解炸弹成功
将断点打到phase_1 上,gdb调试进入phase_1 函数里,再查看里面的汇编代码
这个函数在爆炸前会调用<string_not_equal>函数,我们在此处打个断点进入,查看它的汇编代码
这个函数里会接连调用两次<string_length>的函数,因为如果两个字符串长度不同的话,那肯定不是我们想得到的答案。首先进入第一次调用,查看传入的参数,为我们输入的字符串,退出了,再查看第二次调用,x /s $rdi 查看第二次传入的参数,可以看到,此时rdi里的字符串即是本次炸弹的密码。
The bomblab forces students to learn how to use a debugger.
phase_2:
用objdump -d bomb 指令查看汇编代码
之后将这一大串汇编代码复制到文本编辑器里查看,并找到phase_2
phase_2 的前面几句话只是在做调用函数之前的栈缓存和扩容。之后看到调用函数是<read_six_numbers>意味着输入应该是读取6个数字。如果[rsp]里的值等于1 ,则不会爆炸,0x14(%rsp)是把rsp的地址加20,即若把rsp看成数组0号索引,0x14(%rsp) 是rsp[5] ,因为一个int类型大小是4个字节。前一步操作将[rsp] 里为1的值放入%rbx,再把%rbx放入%eax,说明%eax为1,400f7c内存指令将eax乘二了,此时eax为2,然后再比较0x4(%rbx)里的值。如此循环,每次循环eax里的值都会乘2,所以这个数列是1 2 4 8 16 32.
phase_3:
同样来看phase_3的汇编代码
进入<__isoc99_sscanf>函数里查看输入的格式
需要输入一个数字 一个字符 一个数字
400fdd那一行告诉我们输入的数要大于2,否则会爆炸,后面又有一个大于7,也爆炸,因此我选择了3.
jmpq是一个跳转到表的指令,相当于c里的switch。
查看*0x402760里面的数,为0x400ffa,刚好就在下一行$0x139为313 $0x6b 换成ascii码变为k
因此输入答案为3 k 313
phase_4:
下面是phase_4的汇编代码,后面写满了我的注释
同样是查看函数<isoc99_sscanf>函数寄存器里的参数,知道了输入为两个整型。
将汇编代码还原成c语言代码,试运行。从汇编代码中知道第一个参数是9.第一个参数是[rsp],第三个参数是[rsp+4],但是很奇怪的是第三个参数虽然存入了rdx里,但是却没有用。阅读phase_4的汇编代码401186行我知道了输入的一个数必须小于等于4并且大于等于2。将c语言代码运行,得到结果:
改变参数2,3,4,得到结果分别为176,264,352。此时查看phase_4里[rsp]和[rsp+4]的值,发现[rsp]存的是第二个输入的参数,[rsp]为输入的第一个参数。最终得到答案为176 2;264 3;352 4答案有三组。
phase_5:
最开始比较6和<string_length>的返回值,不相等则爆炸,说明输入的必须是6个字符串。之后下面就是一个循环,每次循环都会把输入的第i个字符的低四位字节取出,并将0x4027a0(,%rdx,4)中的值拿出来加到%ecx里。循环六次之后将ecx和$0x36也就是54 比较,如果相等的话就说明通过了。这段其实是一个加密的解密过程,查看0x4027a0数组里的元素,发现一种答案是2+10+10+10+10+12,查看ascii编码表的二进制表,
答案既可以是一个0,四个1,一个4的任意组合。
顺利通过。
这篇关于bupt拆解二进制炸弹bomb的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!