实验介绍
- 使用所学知识拆除Binary Bombs来增强对程序的机器级表示、汇编语言、调试器和逆向工程等理解。
- Binary Bombs(二进制炸弹)是一个可执行程序,是C语言编译链接成的,包含phase1~phase6共6个阶段(还有隐藏阶段)。
- 各阶段要求输入一个答案,若正确,该阶段炸弹被拆除,否则爆炸。
- 你需要拆除尽可能多的炸弹
- 实验提供一个bomb.c和bomb可执行文件,但是,bomb.c中只有主函数,和一些彩蛋。
- bomb有一个命令行参数,为读入的文件。所以你可以将答案写入到一个txt文件,每个答案一行。
实验技巧
gdb调试
- (gdb)info reg查看所有寄存器的信息
- (gdb)info frame查看栈的信息
- (gdb)b * 0x405040在0x405040处设置断点
- (gdb)b phase_1在函数phase_1处设置断点
- (gdb)x/2s 0x405010输出0x405010开始的两个字符串
- (gdb)stepi执行一条指令
- (gdb)nexti类似于stepi,但以函数调用为单位
- (gdb)c继续(遇到断点后)
- (gdb)run ans.txt命令行参数运行
- (gdb)q退出
- (gdb)finish运行到当前函数返回
- (gdb)delete删除所有断点
- (gdb)delete 5删除断点 5
- (gdb)layout asm展示当前的汇编语言(非常的好用,ctrl + L 刷新)
- (gdb)p *(int *) 0x405012输出位于地址0x405012的整数
- (gdb)p $rax输出%rax的值
- (gdb)p /x $rax以十六进制输出%rax的值
- (gdb)p *(int *)($rbp + 0x8)输出地址%rbp + 0x8的整数
- (gdb)disas phase_1反汇编phase_1函数
我的实验经验
- 先反汇编objdump -d bomb > asm.txt。然后把asm.txt的内容复制粘贴到word。用word来看汇编语言,方便涂色标注
- 一边分析汇编语言,一边利用gdb调试。
- 先熟读CSAPP第三章,最好把习题做完
phase_1
密码如下:I am not part of the problem. I am a Republican.
破解过程:
- 在phase_1函数处设置断点。
- 随便输出一个答案,如 abcdef。
- 观察断点信息,input_strings可知,答案确实是一个字符串。
- 反汇编观察到 strings_not_equal,推测是在判断字符串是否相等。然后,test命令测试返回值,如果非0,则爆炸。
- 0为真,1为假,那么非0对于strings_not_equal,应该是字符串不等,所以现在要找到那个与输出的字符串匹配的字符串。
- 观察到,传递给寄存器%esi的值0x403150
- 打印此处的字符串: x/2s 0x403150
- 得到答案
汇编代码:
点击查看代码- 00000000004013f9 <phase_1>:
- 4013f9: 55 push %rbp
- 4013fa: 48 89 e5 mov %rsp,%rbp
- 4013fd: be 50 31 40 00 mov $0x403150,%esi
- 401402: e8 3d 04 00 00 callq 401844 <strings_not_equal>
- 401407: 85 c0 test %eax,%eax
- 401409: 75 02 jne 40140d <phase_1+0x14>
- 40140b: 5d pop %rbp
- 40140c: c3 retq
- 40140d: e8 2e 05 00 00 callq 401940 <explode_bomb>
- 401412: eb f7 jmp 40140b <phase_1+0x12>****
复制代码 phase_2
密码如下:0 1 3 6 10 15
破解过程:
<ol>在phase_2设置断点。
运行,参数为ans.txt,其中写有刚刚得到的第一个的答案。
先随便输入,这里输入一个数 5。
反汇编观察,一开始调用了函数,那么可以先把输入改为6个数
继续观察下面的汇编语言,发现 -30(%rbp)不就是存放第一个数的位置吗?这里判断第一个数必须为0,否则炸弹爆炸
在后面,%ebx先赋值为1,然后判断是否大于5,是一个循环,然后根据输入的6个数,每轮打印发现规律。
得出代码:for(int i = 1; i > 31 + (c - b)] / 2 + b\).
化简一下,\(res = (c - b) / 2 + b\).
再看后面的分支,和分支的执行:- 0000000000401414 <phase_2>:
- 401414: 55 push %rbp
- 401415: 48 89 e5 mov %rsp,%rbp
- 401418: 53 push %rbx
- 401419: 48 83 ec 28 sub $0x28,%rsp
- 40141d: 48 8d 75 d0 lea -0x30(%rbp),%rsi
- 401421: e8 3c 05 00 00 callq 401962 <read_six_numbers>
- 401426: 83 7d d0 00 cmpl $0x0,-0x30(%rbp)
- 40142a: 78 07 js 401433 <phase_2+0x1f>
- 40142c: bb 01 00 00 00 mov $0x1,%ebx
- 401431: eb 0f jmp 401442 <phase_2+0x2e>
- 401433: e8 08 05 00 00 callq 401940 <explode_bomb>
- 401438: eb f2 jmp 40142c <phase_2+0x18>
- 40143a: e8 01 05 00 00 callq 401940 <explode_bomb>
- 40143f: 83 c3 01 add $0x1,%ebx
- 401442: 83 fb 05 cmp $0x5,%ebx
- 401445: 7f 17 jg 40145e <phase_2+0x4a>
- 401447: 48 63 c3 movslq %ebx,%rax
- 40144a: 8d 53 ff lea -0x1(%rbx),%edx
- 40144d: 48 63 d2 movslq %edx,%rdx
- 401450: 89 d9 mov %ebx,%ecx
- 401452: 03 4c 95 d0 add -0x30(%rbp,%rdx,4),%ecx
- 401456: 39 4c 85 d0 cmp %ecx,-0x30(%rbp,%rax,4)
- 40145a: 74 e3 je 40143f <phase_2+0x2b>
- 40145c: eb dc jmp 40143a <phase_2+0x26>
- 40145e: 48 83 c4 28 add $0x28,%rsp
- 401462: 5b pop %rbx
- 401463: 5d pop %rbp
- 401464: c3 retq
复制代码
- \(5 = 2 * 2 + 1\) , \(res = (14 - 0) / 2 + 0 = 7\) 当前func4(a, 0, 14, 7) 则递归func4(a, 8, 14, 7)
- \(2 = 2 * 1\) , \(res = (14 - 8) / 2 + 8 = 11\) 当前func4(a, 8, 14, 11) 则递归func4(a, 8, 10, 11)
- \(1 = 2 * 0 + 1\) , \(res = (10 - 8) / 2 + 8 = 9\) 当前func4(a, 8, 10, 9) 则递归func4(a, 10, 10, 9)
- \(0 = 0\) ,递归终止条件,此时$ res = (10 - 10) / 2 + 10 = 10$
好,那么可以得出 a = 10
汇编代码:
点击查看代码- 401489: 8b 45 fc mov -0x4(%rbp),%eax
- 40148c: 83 f8 07 cmp $0x7,%eax
- 40148f: 77 7b ja 40150c <phase_3+0xa7>
复制代码 phase_5
密码如下:ionefg
破解过程:
- 4014cf: 39 45 f8 cmp %eax,-0x8(%rbp)
- 4014d2: 74 05 je 4014d9 <phase_3+0x74>
- 4014d4: e8 67 04 00 00 callq 401940 <explode_bomb>
- 4014d9: c9 leaveq
复制代码 推测输入为字符串,且长度为6
- 0000000000401465 <phase_3>:
- 401465: 55 push %rbp
- 401466: 48 89 e5 mov %rsp,%rbp
- 401469: 48 83 ec 10 sub $0x10,%rsp
- 40146d: 48 8d 4d f8 lea -0x8(%rbp),%rcx
- 401471: 48 8d 55 fc lea -0x4(%rbp),%rdx
- 401475: be 1f 33 40 00 mov $0x40331f,%esi
- 40147a: b8 00 00 00 00 mov $0x0,%eax
- 40147f: e8 8c fc ff ff callq 401110 <__isoc99_sscanf@plt>
- 401484: 83 f8 01 cmp $0x1,%eax
- 401487: 7e 11 jle 40149a <phase_3+0x35>
- 401489: 8b 45 fc mov -0x4(%rbp),%eax
- 40148c: 83 f8 07 cmp $0x7,%eax
- 40148f: 77 7b ja 40150c <phase_3+0xa7>
- 401491: 89 c0 mov %eax,%eax
- 401493: ff 24 c5 c0 31 40 00 jmpq *0x4031c0(,%rax,8)
- 40149a: e8 a1 04 00 00 callq 401940 <explode_bomb>
- 40149f: eb e8 jmp 401489 <phase_3+0x24>
- 4014a1: b8 00 00 00 00 mov $0x0,%eax
- 4014a6: 2d 7b 02 00 00 sub $0x27b,%eax
- 4014ab: 05 2c 01 00 00 add $0x12c,%eax
- 4014b0: 2d 60 03 00 00 sub $0x360,%eax
- 4014b5: 05 60 03 00 00 add $0x360,%eax
- 4014ba: 2d 60 03 00 00 sub $0x360,%eax
- 4014bf: 05 60 03 00 00 add $0x360,%eax
- 4014c4: 2d 60 03 00 00 sub $0x360,%eax
- 4014c9: 83 7d fc 05 cmpl $0x5,-0x4(%rbp)
- 4014cd: 7f 05 jg 4014d4 <phase_3+0x6f>
- 4014cf: 39 45 f8 cmp %eax,-0x8(%rbp)
- 4014d2: 74 05 je 4014d9 <phase_3+0x74>
- 4014d4: e8 67 04 00 00 callq 401940 <explode_bomb>
- 4014d9: c9 leaveq
- 4014da: c3 retq
- 4014db: b8 95 02 00 00 mov $0x295,%eax
- 4014e0: eb c4 jmp 4014a6 <phase_3+0x41>
- 4014e2: b8 00 00 00 00 mov $0x0,%eax
- 4014e7: eb c2 jmp 4014ab <phase_3+0x46>
- 4014e9: b8 00 00 00 00 mov $0x0,%eax
- 4014ee: eb c0 jmp 4014b0 <phase_3+0x4b>
- 4014f0: b8 00 00 00 00 mov $0x0,%eax
- 4014f5: eb be jmp 4014b5 <phase_3+0x50>
- 4014f7: b8 00 00 00 00 mov $0x0,%eax
- 4014fc: eb bc jmp 4014ba <phase_3+0x55>
- 4014fe: b8 00 00 00 00 mov $0x0,%eax
- 401503: eb ba jmp 4014bf <phase_3+0x5a>
- 401505: b8 00 00 00 00 mov $0x0,%eax
- 40150a: eb b8 jmp 4014c4 <phase_3+0x5f>
- 40150c: e8 2f 04 00 00 callq 401940 <explode_bomb>
- 401511: b8 00 00 00 00 mov $0x0,%eax
- 401516: eb b1 jmp 4014c9 <phase_3+0x64>
复制代码- 401562: be 1f 33 40 00 mov $0x40331f,%esi
- 401567: b8 00 00 00 00 mov $0x0,%eax
- 40156c: e8 9f fb ff ff callq 401110 <__isoc99_sscanf@plt>
复制代码 可以看出,它取出字符串中每一个字符,然后转为[0, 15]的一个数,然后从地址0x403200 加这个数的偏移量,然后取出一个东西,再把它放入栈的内存中,注意!这里的%dl说明是一个字节,那不还是字符嘛
好,先打印下0x403200处的字符串
发现打印出的一段奇怪的字符串。
但是,根据刚刚分析出的[0,15]的偏移量,我们取出前16个字符
得到:maduiersnfotvbyl
- 再将断点设在循环内,每次打印出%dl , 发现对于输入的abcdef,得到了aduier的ASCII码,再联系一下ASCII码的十六进制,a 为0x61。和0xf做与运算得到 0x1 。
- 发现,输出的字符串中的字符的ASCII码对0x60的偏移量 与 原字符串的字符的下标是相等的。
- 继续向下看
- 401576:8b 45 fc mov -0x4(%rbp),%eax
- 401579:85 c0 test %eax,%eax
- 40157b:78 05 js 401582 <phase_4+0x30>
- 40157d:83 f8 0e cmp $0xe,%eax
- 401580:7e 05 jle 401587 <phase_4+0x35>
- 401582:e8 b9 03 00 00 callq 401940 <explode_bomb>
- 401587:ba 0e 00 00 00 mov $0xe,%edx
复制代码 发现又是字符串匹配,先看看0x4031ae处的字符串
根据前面得到的结论。先取出这些字符,看在原字符串中的下标。
得到:9 15 14 5 6 7,然后加上0x60, 查阅ASCII码
得到:ionefg
汇编代码:
点击查看代码- 401594: e8 7f ff ff ff callq 401518 <func4>
- 401599: 83 f8 05 cmp $0x5,%eax
- 40159c: 75 06 jne 4015a4 <phase_4+0x52>
复制代码 phase_6
密码如下:2 6 4 3 1 5
破解过程:
- 设置断点,运行,反汇编
- 解读汇编代码知:
- 读6个数
- 二重循环,判断是否每个数大于6,判断是否和其他数相等。即,输入的应该为1~6的排列
- 将每个数i转化为\(j = 7 – i\)
- 取出链表的第j个元素的值,放入栈中
- 遍历一遍放入栈的6个链表元素,判断是否为降序
- 链表的发现:
- 40159e: 83 7d f8 05 cmpl $0x5,-0x8(%rbp)
- 4015a2: 74 05 je 4015a9 <phase_4+0x57>
- 4015a4: e8 97 03 00 00 callq 401940 <explode_bomb>
复制代码 发现是链式结构,设置断点,打印出:
发现nodej也是在提示
第一个为链表值,第二个为链表游标,第三个为next指针
- 那么,将链表值按降序排序,得到游标为5 1 3 4 6 2
- 再,由 \(j = 7 – i\), 得到答案 2 6 4 3 1 5
汇编代码:
点击查看代码- 40151c: 89 d1 mov %edx,%ecx
- 40151e: 29 f1 sub %esi,%ecx
- 401520: 89 c8 mov %ecx,%eax
- 401522: c1 e8 1f shr $0x1f,%eax// 逻辑右移31
- 401525:01c8 add %ecx,%eax 401527: d1 f8 sar %eax //算术右移
- 401529: 01 f0 add %esi,%eax
复制代码 secret_phase
密码如下:47
破解过程:
- if(a < res) func4(a, b, res – 1, res), res *= 2, return res
- else if(a > res) func(a, res + 1, c, res), res = res * 2 + 1; return res
- else return 0
复制代码 在0x401ad0处设置断点,然后打印出0x3c9c(%rip)
发现分别为 1 2 3 4 5 6
则可以推断出,要在6个炸弹都拆后才可以进入后边。- 0000000000401518 <func4>:
- 401518: 55 push %rbp
- 401519: 48 89 e5 mov %rsp,%rbp
- 40151c: 89 d1 mov %edx,%ecx
- 40151e: 29 f1 sub %esi,%ecx
- 401520: 89 c8 mov %ecx,%eax
- 401522: c1 e8 1f shr $0x1f,%eax
- 401525: 01 c8 add %ecx,%eax
- 401527: d1 f8 sar %eax
- 401529: 01 f0 add %esi,%eax
- 40152b: 39 f8 cmp %edi,%eax
- 40152d: 7f 09 jg 401538 <func4+0x20>
- 40152f: 7c 13 jl 401544 <func4+0x2c>
- 401531: b8 00 00 00 00 mov $0x0,%eax
- 401536: 5d pop %rbp
- 401537: c3 retq
- 401538: 8d 50 ff lea -0x1(%rax),%edx
- 40153b: e8 d8 ff ff ff callq 401518 <func4>
- 401540: 01 c0 add %eax,%eax
- 401542: eb f2 jmp 401536 <func4+0x1e>
- 401544: 8d 70 01 lea 0x1(%rax),%esi
- 401547: e8 cc ff ff ff callq 401518 <func4>
- 40154c: 8d 44 00 01 lea 0x1(%rax,%rax,1),%eax
- 401550: eb e4 jmp 401536 <func4+0x1e>
- 0000000000401552 <phase_4>:
- 401552: 55 push %rbp
- 401553: 48 89 e5 mov %rsp,%rbp
- 401556: 48 83 ec 10 sub $0x10,%rsp
- 40155a: 48 8d 4d f8 lea -0x8(%rbp),%rcx
- 40155e: 48 8d 55 fc lea -0x4(%rbp),%rdx
- 401562: be 1f 33 40 00 mov $0x40331f,%esi
- 401567: b8 00 00 00 00 mov $0x0,%eax
- 40156c: e8 9f fb ff ff callq 401110 <__isoc99_sscanf@plt>
- 401571: 83 f8 02 cmp $0x2,%eax
- 401574: 75 0c jne 401582 <phase_4+0x30>
- 401576: 8b 45 fc mov -0x4(%rbp),%eax
- 401579: 85 c0 test %eax,%eax
- 40157b: 78 05 js 401582 <phase_4+0x30>
- 40157d: 83 f8 0e cmp $0xe,%eax
- 401580: 7e 05 jle 401587 <phase_4+0x35>
- 401582: e8 b9 03 00 00 callq 401940 <explode_bomb>
- 401587: ba 0e 00 00 00 mov $0xe,%edx
- 40158c: be 00 00 00 00 mov $0x0,%esi
- 401591: 8b 7d fc mov -0x4(%rbp),%edi
- 401594: e8 7f ff ff ff callq 401518 <func4>
- 401599: 83 f8 05 cmp $0x5,%eax
- 40159c: 75 06 jne 4015a4 <phase_4+0x52>
- 40159e: 83 7d f8 05 cmpl $0x5,-0x8(%rbp)
- 4015a2: 74 05 je 4015a9 <phase_4+0x57>
- 4015a4: e8 97 03 00 00 callq 401940 <explode_bomb>
- 4015a9: c9 leaveq
- 4015aa: c3 retq
复制代码 先打印出这三个地址的字符串:
可以推断出,输入为两个整型变量和一个字符串。
且这个字符串必须为DrEvil。但是,phase_4和phase_3的输入都是两个整数
那么我们在判断字符串相等处,设置断点,打印出值观察:
10 和 5!
那么就确定为phase_4的答案后加上DrEvil
- 4015b7: e8 74 02 00 00 callq 401830 <string_length>
- 4015bc: 83 f8 06 cmp $0x6,%eax
- 4015bf: 75 24 jne 4015e5 <phase_5+0x3a>
复制代码 那么现在由返回值5逆推- 4015c1: b8 00 00 00 00 mov $0x0,%eax
- 4015c6: 83 f8 05 cmp $0x5,%eax//循环了6次
- 4015c9: 7f 21 jg 4015ec <phase_5+0x41>
复制代码 则可以调试打印出:
汇编代码:
点击查看代码- 4015cb: 48 63 c8 movslq %eax,%rcx
- 4015ce: 0f b6 14 0b movzbl (%rbx,%rcx,1),%edx
- // 逐个取你输的字符
- 4015d2: 83 e2 0f and $0xf,%edx // 转为[0,15]
- 4015d5: 0f b6 92 00 32 40 00 movzbl 0x403200(%rdx),%edx
- 4015dc: 88 54 0d e9 mov %dl,-0x17(%rbp,%rcx,1)
- 4015e0: 83 c0 01 add $0x1,%eax
复制代码 后记
做了一遍挺痛苦,然后写实验报告梳理了一遍思路,还是挺有收获的。
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |