实验介绍
使用所学知识拆除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
破解过程:
在phase_2设置断点。
运行,参数为ans.txt,其中写有刚刚得到的第一个的答案。
先随便输入,这里输入一个数 5。
反汇编观察,一开始调用了<read_six_numbers>函数,那么可以先把输入改为6个数
继续观察下面的汇编语言,发现 -30(%rbp)不就是存放第一个数的位置吗?这里判断第一个数必须为0,否则炸弹爆炸
在后面,%ebx先赋值为1,然后判断是否大于5,是一个循环,然后根据输入的6个数,每轮打印发现规律。
得出代码:for(int i = 1; i <= 5; i ++) a[i] = a[i - 1] + i;。
则得出答案。
汇编代码:
点击查看代码
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
phase_3
密码如下:1 -1199
破解过程:
设置断点,运行,反汇编。
发现线索: 401475:be 1f 33 40 00 mov $0x40331f,%esi。
打印0x40331f处的字符串,得到:
结合后边的40147f:e88cfcff ff callq 401110 <__isoc99_sscanf@plt>可知,本题答案为两个整型变量
401489: 8b 45 fc mov -0x4(%rbp),%eax 40148c: 83 f8 07 cmp $0x7,%eax 40148f: 77 7b ja 40150c <phase_3+0xa7>
第一个输入的数不能大于7 结合后面的可猜测,是一个根据第一个输入的数的switch语句
那就输入 1 2 进行调试测试
观察到
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
是函数不爆炸的出口
在这里设置断点,打印出%eax,得到-1199。
得到答案,1 -1199。答案不唯一。
汇编代码:
点击查看代码
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>
phase_4
密码如下:10 5
破解过程:
设置断点,运行,反汇编
观察到
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>
调用scanf读入,那么先打印下0x40331f是什么
答案是两个整型变量
再根据下面这段汇编语言
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
得出,输入的第一个数范围:[0, 14]
由
401594: e8 7f ff ff ff callq 401518 <func4> 401599: 83 f8 05 cmp $0x5,%eax 40159c: 75 06 jne 4015a4 <phase_4+0x52>
可知func4的返回值必须为5
由
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>
可知,输入的第二个数必须为5
下面分析递归函数func4。
func4里每次都用到 %edi, %esi,%edx,%eax。
而我们输入的第一个数在一开始便是%edi 的值,%esi 一开始为0,%edx一开始为0xe,即为14。
不妨,将这四个寄存器, 记为 a,b,c,res
看看这几段
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
写为公式:\(res = [(c - b) >> 31 + (c - b)] / 2 + b\).
化简一下,\(res = (c - b) / 2 + b\).
再看后面的分支,和分支的执行:
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
现在从最终返回值5倒推一下:
\(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
则答案为 10, 5
汇编代码:
点击查看代码
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
phase_5
密码如下:ionefg
破解过程:
设置断点,运行,反汇编
观察到
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>
推测输入为字符串,且长度为6
再看接下来一段
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
可以看出,它取出字符串中每一个字符,然后转为[0, 15]的一个数,然后从地址0x403200 加这个数的偏移量,然后取出一个东西,再把它放入栈的内存中,注意!这里的%dl说明是一个字节,那不还是字符嘛
好,先打印下0x403200处的字符串
发现打印出的一段奇怪的字符串。
但是,根据刚刚分析出的[0,15]的偏移量,我们取出前16个字符
得到:maduiersnfotvbyl
再将断点设在循环内,每次打印出%dl , 发现对于输入的abcdef,得到了aduier的ASCII码,再联系一下ASCII码的十六进制,a 为0x61。和0xf做与运算得到 0x1 。
发现,输出的字符串中的字符的ASCII码对0x60的偏移量 与 原字符串的字符的下标是相等的。
继续向下看
4015f0: be ae 31 40 00 mov $0x4031ae,%esi 4015f5: 48 8d 7d e9 lea -0x17(%rbp),%rdi 4015f9: e8 46 02 00 00 callq 401844 <strings_not_equal> 4015fe: 85 c0 test %eax,%eax 401600: 75 07 jne 401609 <phase_5+0x5e>
发现又是字符串匹配,先看看0x4031ae处的字符串
根据前面得到的结论。先取出这些字符,看在原字符串中的下标。
得到:9 15 14 5 6 7,然后加上0x60, 查阅ASCII码
得到:ionefg
汇编代码:
点击查看代码
00000000004015ab <phase_5>: 4015ab: 55 push %rbp 4015ac: 48 89 e5 mov %rsp,%rbp 4015af: 53 push %rbx 4015b0: 48 83 ec 18 sub $0x18,%rsp 4015b4: 48 89 fb mov %rdi,%rbx 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> 4015c1: b8 00 00 00 00 mov $0x0,%eax // 循环6次 0~5 4015c6: 83 f8 05 cmp $0x5,%eax 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 4015e3: eb e1 jmp 4015c6 <phase_5+0x1b> 4015e5: e8 56 03 00 00 callq 401940 <explode_bomb> 4015ea: eb d5 jmp 4015c1 <phase_5+0x16> 4015ec: c6 45 ef 00 movb $0x0,-0x11(%rbp) 4015f0: be ae 31 40 00 mov $0x4031ae,%esi 4015f5: 48 8d 7d e9 lea -0x17(%rbp),%rdi 4015f9: e8 46 02 00 00 callq 401844 <strings_not_equal> 4015fe: 85 c0 test %eax,%eax 401600: 75 07 jne 401609 <phase_5+0x5e> 401602: 48 83 c4 18 add $0x18,%rsp 401606: 5b pop %rbx 401607: 5d pop %rbp 401608: c3 retq 401609: e8 32 03 00 00 callq 401940 <explode_bomb> 40160e: eb f2 jmp 401602 <phase_5+0x57>
phase_6
密码如下:2 6 4 3 1 5
破解过程:
设置断点,运行,反汇编
解读汇编代码知:
读6个数
二重循环,判断是否每个数大于6,判断是否和其他数相等。即,输入的应该为1~6的排列
将每个数i转化为\(j = 7 – i\)
取出链表的第j个元素的值,放入栈中
遍历一遍放入栈的6个链表元素,判断是否为降序
链表的发现:
4016be: ba d0 52 40 00 mov $0x4052d0,%edx // 链表头 4016c9: 48 89 d9 mov %rbx,%rcx 4016db: 48 89 51 08 mov %rdx,0x8(%rcx) //next指针
发现是链式结构,设置断点,打印出:
发现nodej也是在提示
第一个为链表值,第二个为链表游标,第三个为next指针
那么,将链表值按降序排序,得到游标为5 1 3 4 6 2
再,由 \(j = 7 – i\), 得到答案 2 6 4 3 1 5
汇编代码:
点击查看代码
0000000000401610 <phase_6>: 401610: 55 push %rbp 401611: 48 89 e5 mov %rsp,%rbp 401614: 41 55 push %r13 401616: 41 54 push %r12 401618: 53 push %rbx 401619: 48 83 ec 58 sub $0x58,%rsp 40161d: 48 8d 75 c0 lea -0x40(%rbp),%rsi 401621: e8 3c 03 00 00 callq 401962 <read_six_numbers> 401626: 41 bc 00 00 00 00 mov $0x0,%r12d // %r12d = 0 40162c: eb 29 jmp 401657 <phase_6+0x47> 40162e: e8 0d 03 00 00 callq 401940 <explode_bomb> 401633: eb 37 jmp 40166c <phase_6+0x5c> 401635: e8 06 03 00 00 callq 401940 <explode_bomb> 40163a: 83 c3 01 add $0x1,%ebx =============================================================== ------------------------------------------------------------ 40163d: 83 fb 05 cmp $0x5,%ebx // if(%ebx > 5) 401640: 7f 12 jg 401654 <phase_6+0x44> 401642: 49 63 c4 movslq %r12d,%rax // %rax = %r12d 401645: 48 63 d3 movslq %ebx,%rdx // %rdx = %ebx 401648: 8b 7c 95 c0 mov -0x40(%rbp,%rdx,4),%edi 40164c: 39 7c 85 c0 cmp %edi,-0x40(%rbp,%rax,4) 401650: 75 e8 jne 40163a <phase_6+0x2a> ----------------------------------------------------------- 401652: eb e1 jmp 401635 <phase_6+0x25> 401654: 45 89 ec mov %r13d,%r12d 401657: 41 83 fc 05 cmp $0x5,%r12d // cmp %r12d 5 40165b: 7f 19 jg 401676 <phase_6+0x66> // > 40165d: 49 63 c4 movslq %r12d,%rax // %rax = %r12d 401660: 8b 44 85 c0 mov -0x40(%rbp,%rax,4),%eax 401664: 83 e8 01 sub $0x1,%eax // %rax -= 1 401667: 83 f8 05 cmp $0x5,%eax // if rax > 5 40166a: 77 c2 ja 40162e <phase_6+0x1e> 40166c: 45 8d 6c 24 01 lea 0x1(%r12),%r13d // %r13d=(%r12d+1) 401671: 44 89 eb mov %r13d,%ebx // %ebx = %r13d 401674: eb c7 jmp 40163d <phase_6+0x2d> ================================================================ 401676: b8 00 00 00 00 mov $0x0,%eax // %eax = 0 40167b: eb 13 jmp 401690 <phase_6+0x80> // j = 7 - i ========================================================== 40167d: 48 63 c8 movslq %eax,%rcx 401680: ba 07 00 00 00 mov $0x7,%edx 401685: 2b 54 8d c0 sub -0x40(%rbp,%rcx,4),%edx 从第一个数开始 401689: 89 54 8d c0 mov %edx,-0x40(%rbp,%rcx,4) 40168d: 83 c0 01 add $0x1,%eax 401690: 83 f8 05 cmp $0x5,%eax 401693: 7e e8 jle 40167d <phase_6+0x6d> ========================================================== 401695: be 00 00 00 00 mov $0x0,%esi 40169a: eb 18 jmp 4016b4 <phase_6+0xa4> 40169c: 48 8b 52 08 mov 0x8(%rdx),%rdx 4016a0: 83 c0 01 add $0x1,%eax //二重循环,寻找第j个链表元素 ============================================================== 4016a3: 48 63 ce movslq %esi,%rcx 4016a6: 39 44 8d c0 cmp %eax,-0x40(%rbp,%rcx,4) 4016aa: 7f f0 jg 40169c <phase_6+0x8c> 4016ac: 48 89 54 cd 90 mov %rdx,-0x70(%rbp,%rcx,8) 4016b1: 83 c6 01 add $0x1,%esi 4016b4: 83 fe 05 cmp $0x5,%esi 4016b7: 7f 0c jg 4016c5 <phase_6+0xb5> 4016b9: b8 01 00 00 00 mov $0x1,%eax 4016be: ba d0 52 40 00 mov $0x4052d0,%edx // 链表头 4016c3: eb de jmp 4016a3 <phase_6+0x93> 4016c5: 48 8b 5d 90 mov -0x70(%rbp) 4016c9: 48 89 d9 mov %rbx,%rcx //%rcx = %rbx 4016cc: b8 01 00 00 00 mov $0x1,%eax // eax = 1 4016d1: eb 12 jmp 4016e5 <phase_6+0xd5> 4016d3: 48 63 d0 movslq %eax,%rdx // rdx = eax 4016d6: 48 8b 54 d5 90 mov -0x70(%rbp,%rdx,8),%rdx 4016db: 48 89 51 08 mov %rdx,0x8(%rcx) 4016df: 83 c0 01 add $0x1,%eax 4016e2: 48 89 d1 mov %rdx,%rcx // rcx = rdx 4016e5: 83 f8 05 cmp $0x5,%eax // while 循环 4016e8: 7e e9 jle 4016d3 <phase_6+0xc3> ========================================================= 4016ea: 48 c7 41 08 00 00 00 movq $0x0,0x8(%rcx) 4016f1: 00 4016f2: 41 bc 00 00 00 00 mov $0x0,%r12d 4016f8: eb 08 jmp 401702 <phase_6+0xf2> 4016fa: 48 8b 5b 08 mov 0x8(%rbx),%rbx 4016fe: 41 83 c4 01 add $0x1,%r12d 401702: 41 83 fc 04 cmp $0x4,%r12d 401706: 7f 11 jg 401719 <phase_6+0x109> 401708: 48 8b 43 08 mov 0x8(%rbx),%rax 40170c: 8b 00 mov (%rax),%eax 40170e: 39 03 cmp %eax,(%rbx) 401710: 7d e8 jge 4016fa <phase_6+0xea> // 这里是一重循环,判断是否前个元素大于等于后一个元素,即降序 // 否则爆炸 401712: e8 29 02 00 00 callq 401940 <explode_bomb> 401717: eb e1 jmp 4016fa <phase_6+0xea> 401719: 48 83 c4 58 add $0x58,%rsp 40171d: 5b pop %rbx 40171e: 41 5c pop %r12 401720: 41 5d pop %r13 401722: 5d pop %rbp 401723: c3 retq
secret_phase
密码如下:47
破解过程:
首先要找到入口,看phase_defused函数
0000000000401ac9 <phase_defused>: 401ac9: 83 3d 9c 3c 00 00 06 cmpl $0x6,0x3c9c(%rip) \#40576c <num_input_strings> 401ad0: 74 01 je 401ad3 <phase_defused+0xa>
在0x401ad0处设置断点,然后打印出0x3c9c(%rip)
发现分别为 1 2 3 4 5 6
则可以推断出,要在6个炸弹都拆后才可以进入后边。
401ae7: be 69 33 40 00 mov $0x403369,%esi 401aec: bf 70 58 40 00 mov $0x405870,%edi ---- 401b0c: be 72 33 40 00 mov $0x403372,%esi 401b11: 48 8d 7d b0 lea -0x50(%rbp),%rdi 401b15: e8 2a fd ff ff callq 401844 <strings_not_equal>
先打印出这三个地址的字符串:
可以推断出,输入为两个整型变量和一个字符串。
且这个字符串必须为DrEvil。但是,phase_4和phase_3的输入都是两个整数
那么我们在判断字符串相等处,设置断点,打印出值观察:
10 和 5!
那么就确定为phase_4的答案后加上DrEvil
成功进入隐藏关。
看secret_phase函数
000000000040175e <secret_phase>: 401767: e8 32 02 00 00 callq 40199e <read_line> 40176f: e8 cc f9 ff ff callq 401140 <atoi@plt
发现了readline函数和atoi函数,说明是输一个数字。(atoi函数作用为将字符串转为整型)
401776: 8d 40 ff lea -0x1(%rax),c%eax 401779: 3d e8 03 00 00 cmp $0x3e8,%eax //1000 40177e: 77 27 ja 4017a7 <secret_phase+0x49> 401780: 89 de mov %ebx,%esi 401782: bf f0 50 40 00 mov $0x4050f0,%edi//此处地址的值为36
401787: e8 98 ff ff ff callq 401724 <fun7> 40178c: 83 f8 05 cmp $0x5,%eax //返回值得为5
则输出值不超1001
输入进func7后,返回值必须为5
再看func7函数又是一个分支+递归。
直接写出伪代码:
记%rdi 为 p,%rax 为 res, %esi为 x,
则func7(* p, int res, int x) 。
一开始,\(*p = 36\), x为你输入的数。
if(x < *p) p = *(p + 8),func7(p, res, x), res *= 2,return res; else if(x > *p) p = *(p + 10),func7(p, res, x), res = res * 2 + 1,return res; else return 0;
那么现在由返回值5逆推
5 = 2 * 2 + 1 p = *p + 10 2 = 2 * 1 p = *p + 8 1 = 2 * 0 + 1 p = *p + 10 0 = 0 *p == x
则可以调试打印出:
\(0x2f = 47\)
汇编代码:
点击查看代码
0000000000401724 <fun7>: 401724: 48 85 ff test %rdi,%rdi 401727: 74 2f je 401758 <fun7+0x34> 401729: 55 push %rbp 40172a: 48 89 e5 mov %rsp,%rbp 40172d: 8b 07 mov (%rdi),%eax 40172f: 39 f0 cmp %esi,%eax 401731: 7f 09 jg 40173c <fun7+0x18> 401733: 75 14 jne 401749 <fun7+0x25> 401735: b8 00 00 00 00 mov $0x0,%eax 40173a: 5d &a标签: # BinaryBombs
留言评论