二进制拆弹(炸弹炸掉了我的头发 T.T)
文章目录
- 所需要使用的调试工具
- 开始进入拆弹过程
- phase_1
- phase_2
- pahse_3
- phase_4
- phase_5
- phase_6
- secret_phase
所需要使用的调试工具
1. gdb工具
- 使用 break *地址来设置断点,使用c指令从断点继续执行
- 使用 info registers 指令观察寄存器状态
- 使用 x/s 指令用字符串类型显示内存中值*
2.objdump工具
使用 objdump -d execfile > exfiles.s 对可执行文件进行反汇编并输入到一个文件中
使用objdump -t execfile 对可执行文件中符号表进行提取
Strings工具
使用strings bomb 可以将可执行文件中的所有可见字符打印出来
开始进入拆弹过程
phase_1
input = read_line(); /* Get input */phase_1(input); /* Run the phase */phase_defused(); /* Drat! They figured it out!* Let me know how they did it. */printf("Phase 1 defused. How about the next one?\n");
可以看到phase_1的C代码要求我们首先输入一个字符串,然后再进行比较
所以我们可以使用gdb在phase_1开始处设置断点并进行一次操作、查看寄存器的值
(gdb) break *0x400ee0
Breakpoint 1 at 0x400ee0
(gdb) run
Starting program: /home/legend/demo/bomb/bomb
Welcome to my fiendish little bomb. You have 6 phases with
which to blow yourself up. Have a nice day!
My first try!
My first try!就是随便打的,主要看它存入了哪个寄存器(不出意外是%rdi)
Breakpoint 1, 0x0000000000400ee0 in phase_1 ()
(gdb) info registers
rsi 0x603780 6305664
rdi 0x603780 6305664
(gdb) x/s 0x603780
0x603780 <input_strings>: "My first try!"
因为后面程序中改变了%rsi。所以可以推断,输入的字符串确实存入了%rdi 寄存器
可以看到在后续代码里%rsi的值被改变,此刻我们再使用x/s查看其值发现是一个字符串
(gdb) x/s 0x402400
0x402400: "Border relations with Canada have never been better."
接下来我们要进行对phase_1的分析
对应的汇编程序
0000000000400ee0 <phase_1>:400ee0: 48 83 ec 08 sub $0x8,%rsp400ee4: be 00 24 40 00 mov $0x402400,%esi400ee9: e8 4a 04 00 00 callq 401338 <strings_not_equal>400eee: 85 c0 test %eax,%eax400ef0: 74 05 je 400ef7 <phase_1+0x17>400ef2: e8 43 05 00 00 callq 40143a <explode_bomb>400ef7: 48 83 c4 08 add $0x8,%rsp400efb: c3 retq
看到它调用了<string_not_equal>
截取一个重要部分
0000000000401338 <strings_not_equal>:401338: 41 54 push %r1240133a: 55 push %rbp40133b: 53 push %rbx40133c: 48 89 fb mov %rdi,%rbx40133f: 48 89 f5 mov %rsi,%rbp401342: e8 d4 ff ff ff callq 40131b <string_length>401347: 41 89 c4 mov %eax,%r12d40134a: 48 89 ef mov %rbp,%rdi40134d: e8 c9 ff ff ff callq 40131b <string_length>401352: ba 01 00 00 00 mov $0x1,%edx401357: 41 39 c4 cmp %eax,%r12d40135a: 75 3f jne 40139b <strings_not_equal+0x63>40139b: 89 d0 mov %edx,%eax40139d: 5b pop %rbx40139e: 5d pop %rbp40139f: 41 5c pop %r124013a1: c3 retq
对stringlength分析会得出该函数是用来返回字符串长度的
可以看到在not_equal函数里当我们键入的字符串长度与%rsi不同时,可以看到函数返回1;
可以推测出当两字符串相同时返回0
test设置条件码后je根据ZF条件码可以跳过炸弹启动程序
即只有我们键入的string和程序存入%rsi的string相同时才会执行je
所以可以得到我们看到的%rsi中的字符串就是keys
Welcome to my fiendish little bomb. You have 6 phases with
which to blow yourself up. Have a nice day!
Border relations with Canada have never been better.
Phase 1 defused. How about the next one?
解决!Yep!
phase_2
该阶段的问题主要是理解代码中的循环
0000000000400efc <phase_2>:400efc: 55 push %rbp400efd: 53 push %rbx400efe: 48 83 ec 28 sub $0x28,%rsp400f02: 48 89 e6 mov %rsp,%rsi400f05: e8 52 05 00 00 callq 40145c <read_six_numbers>
先看函数中调用的<read_six_numbers>
000000000040145c <read_six_numbers>:40145c: 48 83 ec 18 sub $0x18,%rsp401460: 48 89 f2 mov %rsi,%rdx401463: 48 8d 4e 04 lea 0x4(%rsi),%rcx401467: 48 8d 46 14 lea 0x14(%rsi),%rax40146b: 48 89 44 24 08 mov %rax,0x8(%rsp)401470: 48 8d 46 10 lea 0x10(%rsi),%rax401474: 48 89 04 24 mov %rax,(%rsp)401478: 4c 8d 4e 0c lea 0xc(%rsi),%r940147c: 4c 8d 46 08 lea 0x8(%rsi),%r8401480: be c3 25 40 00 mov $0x4025c3,%esi401485: b8 00 00 00 00 mov $0x0,%eax40148a: e8 61 f7 ff ff callq 400bf0 <__isoc99_sscanf@plt>40148f: 83 f8 05 cmp $0x5,%eax401492: 7f 05 jg 401499 <read_six_numbers+0x3d>401494: e8 a1 ff ff ff callq 40143a <explode_bomb>401499: 48 83 c4 18 add $0x18,%rsp40149d: c3 retq
可直接从<read_six_numbers>的后面开始看。
不难得到当输入字符数量少于6个时<read_six_numbers>会直接引爆炸弹。
所以keys的长度应该要大于等于6个字符。
再回头看<phase_2>中的主体代码
400f0a: 83 3c 24 01 cmpl $0x1,(%rsp)400f0e: 74 20 je 400f30 <phase_2+0x34>400f10: e8 25 05 00 00 callq 40143a <explode_bomb>400f15: eb 19 jmp 400f30 <phase_2+0x34>400f17: 8b 43 fc mov -0x4(%rbx),%eax400f1a: 01 c0 add %eax,%eax400f1c: 39 03 cmp %eax,(%rbx)400f1e: 74 05 je 400f25 <phase_2+0x29>400f20: e8 15 05 00 00 callq 40143a <explode_bomb>400f25: 48 83 c3 04 add $0x4,%rbx400f29: 48 39 eb cmp %rbp,%rbx400f2c: 75 e9 jne 400f17 <phase_2+0x1b>400f2e: eb 0c jmp 400f3c <phase_2+0x40>400f30: 48 8d 5c 24 04 lea 0x4(%rsp),%rbx400f35: 48 8d 6c 24 18 lea 0x18(%rsp),%rbp400f3a: eb db jmp 400f17 <phase_2+0x1b>400f3c: 48 83 c4 28 add $0x28,%rsp400f40: 5b pop %rbx400f41: 5d pop %rbp400f42: c3 retq
因为我们的目的是要得到keys
所以这里的一个处理技巧是:
我们不去管引爆炸弹的情况,只按照可以jump的条件分析。
只要我们遵循着它的跳跃进行一轮就会发现
这个循环的条件为输入的keys中后一位是前一位的2倍,且第一位为1,数据为int型
可从如下代码得出
400f0a: 83 3c 24 01 cmpl $0x1,(%rsp)//可以看出rsp即栈顶中存的为数字1,400f17: 8b 43 fc mov -0x4(%rbx),%eax400f1a: 01 c0 add %eax,%eax400f1c: 39 03 cmp %eax,(%rbx)400f1e: 74 05 je 400f25 <phase_2+0x29>400f20: e8 15 05 00 00 callq 40143a <explode_bomb>
并且要求长度至少为6
可从我们对<read_six_numbers>得出
或者从如下截取的两段代码得出
400f30: 48 8d 5c 24 04 lea 0x4(%rsp),%rbx
400f35: 48 8d 6c 24 18 lea 0x18(%rsp),%rbp
//rbp为rsp+24,rbx为rsp+4400f25: 48 83 c3 04 add $0x4,%rbx
400f29: 48 39 eb cmp %rbp,%rbx
//再根据比较条件,可以看出至少要24/4位的keys
结果
可以看到长度大于6后就不再进行判断了(255也过了)
Phase 1 defused. How about the next one?
1 2 4 8 16 32 64 128 255
That's number 2. Keep going!
phase_2解决!Yep!
pahse_3
该部分考查对switch的理解
0000000000400f43 <phase_3>:400f43: 48 83 ec 18 sub $0x18,%rsp400f47: 48 8d 4c 24 0c lea 0xc(%rsp),%rcx400f4c: 48 8d 54 24 08 lea 0x8(%rsp),%rdx400f51: be cf 25 40 00 mov $0x4025cf,%esi400f56: b8 00 00 00 00 mov $0x0,%eax400f5b: e8 90 fc ff ff callq 400bf0 <__isoc99_sscanf@plt>400f60: 83 f8 01 cmp $0x1,%eax400f63: 7f 05 jg 400f6a <phase_3+0x27>400f65: e8 d0 04 00 00 callq 40143a <explode_bomb>
从上面这一部分中可以看到我们输入的keys的长度不能少于两位,否则引爆炸弹
400f6a: 83 7c 24 08 07 cmpl $0x7,0x8(%rsp)400f6f: 77 3c ja 400fad <phase_3+0x6a>400f71: 8b 44 24 08 mov 0x8(%rsp),%eax
再对上述代码主体进行分析,发现代码将%rax的值变成了我们第一个输入进的数字,且这个数字不能大于7
400f75: ff 24 c5 70 24 40 00 jmpq *0x402470(,%rax,8)
%rax会影响我们跳转的地址。
接下来使用gdb工具对%rax不同值对应内存地址中的值取出,对应下面的各个情况
在此只举%rax=2的例子,其余6个值也可行
发现对应地址
(gdb) x/u *0x402480
0x400f83 <phase_3+64>: 184
400f7c: b8 cf 00 00 00 mov $0xcf,%eax
400f81: eb 3b jmp 400fbe <phase_3+0x7b>
400f83: b8 c3 02 00 00 mov $0x2c3,%eax
400f88: eb 34 jmp 400fbe <phase_3+0x7b>
400f8a: b8 00 01 00 00 mov $0x100,%eax
400f8f: eb 2d jmp 400fbe <phase_3+0x7b>
400f91: b8 85 01 00 00 mov $0x185,%eax
400f96: eb 26 jmp 400fbe <phase_3+0x7b>
400f98: b8 ce 00 00 00 mov $0xce,%eax
400f9d: eb 1f jmp 400fbe <phase_3+0x7b>
400f9f: b8 aa 02 00 00 mov $0x2aa,%eax
400fa4: eb 18 jmp 400fbe <phase_3+0x7b>
400fa6: b8 47 01 00 00 mov $0x147,%eax
400fab: eb 11 jmp 400fbe <phase_3+0x7b>
400fad: e8 88 04 00 00 callq 40143a <explode_bomb>
400fb2: b8 00 00 00 00 mov $0x0,%eax
400fb7: eb 05 jmp 400fbe <phase_3+0x7b>
400fb9: b8 37 01 00 00 mov $0x137,%eax
在我们的举例中,%rax=0x2c3,十进制707
400fbe: 3b 44 24 0c cmp 0xc(%rsp),%eax
400fc2: 74 05 je 400fc9 <phase_3+0x86>
400fc4: e8 71 04 00 00 callq 40143a <explode_bomb>
400fc9: 48 83 c4 18 add $0x18,%rsp
400fcd: c3 retq
再看上述代码,可以发现,当%rax的值与我们输入的第二个数字相同时,就得到了keys
所以该phase共有7个keys可供选择
结果
That's number 2. Keep going!
2 707
Halfway there!
phase_3完成!Yep!
phase_4
这个阶段考查的是递归函数
先看phase_4在调用fun_4前的代码
000000000040100c <phase_4>:40100c: 48 83 ec 18 sub $0x18,%rsp401010: 48 8d 4c 24 0c lea 0xc(%rsp),%rcx401015: 48 8d 54 24 08 lea 0x8(%rsp),%rdx40101a: be cf 25 40 00 mov $0x4025cf,%esi40101f: b8 00 00 00 00 mov $0x0,%eax401024: e8 c7 fb ff ff callq 400bf0 <__isoc99_sscanf@plt>401029: 83 f8 02 cmp $0x2,%eax40102c: 75 07 jne 401035 <phase_4+0x29>40102e: 83 7c 24 08 0e cmpl $0xe,0x8(%rsp)401033: 76 05 jbe 40103a <phase_4+0x2e>401035: e8 00 04 00 00 callq 40143a <explode_bomb>40103a: ba 0e 00 00 00 mov $0xe,%edx40103f: be 00 00 00 00 mov $0x0,%esi401044: 8b 7c 24 08 mov 0x8(%rsp),%edi401048: e8 81 ff ff ff callq 400fce <func4>
这段代码比较简单,从phase_4中看到我们输入的keys是两个数字
且第一个输入的数字应该小于等于14
现在主要是去分析fun_4的功能
此时传入的%rdx=14,%rsi=0,%rdi=我们输入的第一个数字
0000000000400fce <func4>:400fce: 48 83 ec 08 sub $0x8,%rsp400fd2: 89 d0 mov %edx,%eax400fd4: 29 f0 sub %esi,%eax400fd6: 89 c1 mov %eax,%ecx400fd8: c1 e9 1f shr $0x1f,%ecx400fdb: 01 c8 add %ecx,%eax400fdd: d1 f8 sar %eax400fdf: 8d 0c 30 lea (%rax,%rsi,1),%ecx400fe2: 39 f9 cmp %edi,%ecx400fe4: 7e 0c jle 400ff2 <func4+0x24>400fe6: 8d 51 ff lea -0x1(%rcx),%edx400fe9: e8 e0 ff ff ff callq 400fce <func4>400fee: 01 c0 add %eax,%eax400ff0: eb 15 jmp 401007 <func4+0x39>400ff2: b8 00 00 00 00 mov $0x0,%eax400ff7: 39 f9 cmp %edi,%ecx400ff9: 7d 0c jge 401007 <func4+0x39>400ffb: 8d 71 01 lea 0x1(%rcx),%esi400ffe: e8 cb ff ff ff callq 400fce <func4>401003: 8d 44 00 01 lea 0x1(%rax,%rax,1),%eax401007: 48 83 c4 08 add $0x8,%rsp40100b: c3 retq
此时我们一直跟随着可跳转的代码,发现当rdi==1时,就可以直接跳出递归,且此时%rax=0
继续看phase_4的后一段代码
40104d: 85 c0 test %eax,%eax40104f: 75 07 jne 401058 <phase_4+0x4c>401051: 83 7c 24 0c 00 cmpl $0x0,0xc(%rsp)401056: 74 05 je 40105d <phase_4+0x51>401058: e8 dd 03 00 00 callq 40143a <explode_bomb>40105d: 48 83 c4 18 add $0x18,%rsp401061: c3 retq
察看jne语句可知%rax=0不会引爆炸弹,所以第一个输入的数字可以为1
继续向下看,看到另一个cmpl语句,此时我们可以确定输入的第二个数字一定为0
所以我们的keys就是1 0
Halfway there!
1 0
So you got that one. Try this one.
phase_4完成!Yep!
phase_5
感觉这段主要是考察寄存器的细节和栈的存储,特点并不是很鲜明,但很有趣,有种解密的感觉
0000000000401062 <phase_5>:401062: 53 push %rbx401063: 48 83 ec 20 sub $0x20,%rsp401067: 48 89 fb mov %rdi,%rbx40106a: 64 48 8b 04 25 28 00 mov %fs:0x28,%rax401071: 00 00 401073: 48 89 44 24 18 mov %rax,0x18(%rsp)401078: 31 c0 xor %eax,%eax40107a: e8 9c 02 00 00 callq 40131b <string_length>40107f: 83 f8 06 cmp $0x6,%eax401082: 74 4e je 4010d2 <phase_5+0x70>401084: e8 b1 03 00 00 callq 40143a <explode_bomb>
可以看到我们输入的keys是六位的
401089: eb 47 jmp 4010d2 <phase_5+0x70>40108b: 0f b6 0c 03 movzbl (%rbx,%rax,1),%ecx40108f: 88 0c 24 mov %cl,(%rsp)401092: 48 8b 14 24 mov (%rsp),%rdx401096: 83 e2 0f and $0xf,%edx401099: 0f b6 92 b0 24 40 00 movzbl 0x4024b0(%rdx),%edx4010a0: 88 54 04 10 mov %dl,0x10(%rsp,%rax,1)4010a4: 48 83 c0 01 add $0x1,%rax4010a8: 48 83 f8 06 cmp $0x6,%rax4010ac: 75 dd jne 40108b <phase_5+0x29>
可以看到在这段程序不断取我们输入keys的,并且将每一位的低4位写入%rdx
然后通过movzbl 0x4024b0(%rdx),%edx得到真正的keys
所以我们使用gdb工具查看0x4024b0中究竟存储的是什么
x/s 0x4024b0
0x4024b0 <array.3449>:"maduiersnfotvbylSo you think you can stop the bomb with ctrl-c, do you?"
我们就是在这个字段中寻找六个字符,凑成keys
4010ae: c6 44 24 16 00 movb $0x0,0x16(%rsp)4010b3: be 5e 24 40 00 mov $0x40245e,%esi4010b8: 48 8d 7c 24 10 lea 0x10(%rsp),%rdi4010bd: e8 76 02 00 00 callq 401338 <strings_not_equal>4010c2: 85 c0 test %eax,%eax4010c4: 74 13 je 4010d9 <phase_5+0x77>4010c6: e8 6f 03 00 00 callq 40143a <explode_bomb>4010cb: 0f 1f 44 00 00 nopl 0x0(%rax,%rax,1)4010d0: eb 07 jmp 4010d9 <phase_5+0x77>4010d2: b8 00 00 00 00 mov $0x0,%eax4010d7: eb b2 jmp 40108b <phase_5+0x29>4010d9: 48 8b 44 24 18 mov 0x18(%rsp),%rax4010de: 64 48 33 04 25 28 00 xor %fs:0x28,%rax4010e5: 00 00 4010e7: 74 05 je 4010ee <phase_5+0x8c>4010e9: e8 42 fa ff ff callq 400b30 <__stack_chk_fail@plt>4010ee: 48 83 c4 20 add $0x20,%rsp4010f2: 5b pop %rbx4010f3: c3 retq
哈哈,可以看到出现了<string_not_equal>函数,那么0x40245e中存储的就是我们需要从上述字段中寻找的各个字符
使用gdb查看0x40245e中存储了什么
(gdb) x/s 0x40245e
0x40245e: "flyers"
嗡嗡嗡,全是苍蝇啊
maduiersnfotvbylSo you think you can stop the bomb with ctrl-c, do you?
再看这里面的字符,我们分别发现在9,15,14,5,6,7这六个位置
所以我们输入字符的二进制低四位应该是:
1001
1111
1110
0101
0110
0111
再去找ASCII表
附一个 ASCII表的链接
可以得到我们输入的字符是:就字母区段来说应该是ionefg或者IONEFG,或者是这几个字母按顺序的大小写混写
当然还有可能是许多其他字符和数字的组合,这里不一一列举
哇哈哈哈,成功了!!!
phase_5完成!Yep!
phase_6
淦,好长啊!
这一部分是考察对链表的重新链接
00000000004010f4 <phase_6>:4010f4: 41 56 push %r144010f6: 41 55 push %r134010f8: 41 54 push %r124010fa: 55 push %rbp4010fb: 53 push %rbx4010fc: 48 83 ec 50 sub $0x50,%rsp401100: 49 89 e5 mov %rsp,%r13401103: 48 89 e6 mov %rsp,%rsi401106: e8 51 03 00 00 callq 40145c <read_six_numbers>
由<read_six_numbers>可以得知我们的keys长度至少为6
40110b: 49 89 e6 mov %rsp,%r1440110e: 41 bc 00 00 00 00 mov $0x0,%r12d401114: 4c 89 ed mov %r13,%rbp401117: 41 8b 45 00 mov 0x0(%r13),%eax40111b: 83 e8 01 sub $0x1,%eax40111e: 83 f8 05 cmp $0x5,%eax401121: 76 05 jbe 401128 <phase_6+0x34>401123: e8 12 03 00 00 callq 40143a <explode_bomb>401128: 41 83 c4 01 add $0x1,%r12d40112c: 41 83 fc 06 cmp $0x6,%r12d401130: 74 21 je 401153 <phase_6+0x5f>401132: 44 89 e3 mov %r12d,%ebx401135: 48 63 c3 movslq %ebx,%rax401138: 8b 04 84 mov (%rsp,%rax,4),%eax40113b: 39 45 00 cmp %eax,0x0(%rbp)40113e: 75 05 jne 401145 <phase_6+0x51>401140: e8 f5 02 00 00 callq 40143a <explode_bomb>401145: 83 c3 01 add $0x1,%ebx401148: 83 fb 05 cmp $0x5,%ebx40114b: 7e e8 jle 401135 <phase_6+0x41>40114d: 49 83 c5 04 add $0x4,%r13401151: eb c1 jmp 401114 <phase_6+0x20>
阅读上述代码发现这是实现了确保每个数字都小于6且大于0
401153: 48 8d 74 24 18 lea 0x18(%rsp),%rsi401158: 4c 89 f0 mov %r14,%rax40115b: b9 07 00 00 00 mov $0x7,%ecx401160: 89 ca mov %ecx,%edx401162: 2b 10 sub (%rax),%edx401164: 89 10 mov %edx,(%rax)401166: 48 83 c0 04 add $0x4,%rax40116a: 48 39 f0 cmp %rsi,%rax40116d: 75 f1 jne 401160 <phase_6+0x6c>
这段代码实现了7-每个数字的功能
40116f: be 00 00 00 00 mov $0x0,%esi401174: eb 21 jmp 401197 <phase_6+0xa3>401176: 48 8b 52 08 mov 0x8(%rdx),%rdx40117a: 83 c0 01 add $0x1,%eax40117d: 39 c8 cmp %ecx,%eax40117f: 75 f5 jne 401176 <phase_6+0x82>401181: eb 05 jmp 401188 <phase_6+0x94>401183: ba d0 32 60 00 mov $0x6032d0,%edx401188: 48 89 54 74 20 mov %rdx,0x20(%rsp,%rsi,2)40118d: 48 83 c6 04 add $0x4,%rsi401191: 48 83 fe 18 cmp $0x18,%rsi401195: 74 14 je 4011ab <phase_6+0xb7>401197: 8b 0c 34 mov (%rsp,%rsi,1),%ecx40119a: 83 f9 01 cmp $0x1,%ecx40119d: 7e e4 jle 401183 <phase_6+0x8f>40119f: b8 01 00 00 00 mov $0x1,%eax4011a4: ba d0 32 60 00 mov $0x6032d0,%edx4011a9: eb cb jmp 401176 <phase_6+0x82>
相当于把一个链表中的不同值传入栈中
设 order为数字的次序, value为数字的值
这段代码实现了当value等于1时将0x6032d0传入rsp+32+(order-1) * 8
value大于1时,将0x6032d0+8 * (value-1)值传入rsp+32+(order-1) * 8
我们再看一看链表中的结点元素
(gdb) p/s *0x6032d0@24
$2 = {332, 1, 6304480, 0, 168, 2, 6304496, 0, 924, 3, 6304512, 0, 691, 4, 6304528, 0,477, 5, 6304544, 0, 443, 6, 0, 0}
现在可以看到这六个结点的值分别为332,168,924,691,477,443
4011ab: 48 8b 5c 24 20 mov 0x20(%rsp),%rbx4011b0: 48 8d 44 24 28 lea 0x28(%rsp),%rax4011b5: 48 8d 74 24 50 lea 0x50(%rsp),%rsi4011ba: 48 89 d9 mov %rbx,%rcx4011bd: 48 8b 10 mov (%rax),%rdx4011c0: 48 89 51 08 mov %rdx,0x8(%rcx)4011c4: 48 83 c0 08 add $0x8,%rax4011c8: 48 39 f0 cmp %rsi,%rax4011cb: 74 05 je 4011d2 <phase_6+0xde>4011cd: 48 89 d1 mov %rdx,%rcx4011d0: eb eb jmp 4011bd <phase_6+0xc9>4011d2: 48 c7 42 08 00 00 00 movq $0x0,0x8(%rdx)
这段代码实现了将链表直接相连接,并且将最后的指针为0(NULL)
4011d9: 00
4011da: bd 05 00 00 00 mov $0x5,%ebp
4011df: 48 8b 43 08 mov 0x8(%rbx),%rax
4011e3: 8b 00 mov (%rax),%eax
4011e5: 39 03 cmp %eax,(%rbx)
4011e7: 7d 05 jge 4011ee <phase_6+0xfa>
4011e9: e8 4c 02 00 00 callq 40143a <explode_bomb>
4011ee: 48 8b 5b 08 mov 0x8(%rbx),%rbx
4011f2: 83 ed 01 sub $0x1,%ebp
4011f5: 75 e8 jne 4011df <phase_6+0xeb>
4011f7: 48 83 c4 50 add $0x50,%rsp
4011fb: 5b pop %rbx
4011fc: 5d pop %rbp
4011fd: 41 5c pop %r12
4011ff: 41 5d pop %r13
401201: 41 5e pop %r14
401203: c3 retq
这段代码实现了判断rsp+32链表必须是递减的,否则直接引爆炸弹
现在我们可以知道排序应该为3 4 5 6 1 2
所以我们输入的值应该为4 3 2 1 6 5(因为前面的排序是用7-输入数字得到的顺序)
phase_6完成 ! Yep!
secret_phase
PDF中写道还有一个secret_phase,在汇编文件里先找了找,果真发现了secret_phase
看到这里我首先想到的是怎么进入这个secret,可以看到这里面并没有给我们提供接口
然后,嘿嘿,我就用了 ctrl+f 神器搜索了一下secret_phase这个词
没想到这个接口竟然藏在每个阶段都在使用的phase_defused里面
最危险的地方就是最安全的地方???
由于过长这里只截取了一段用于推出接口的代码
00000000004015c4 <phase_defused>:4015f0: be 19 26 40 00 mov $0x402619,%esi4015f5: bf 70 38 60 00 mov $0x603870,%edi4015fa: e8 f1 f5 ff ff callq 400bf0 <__isoc99_sscanf@plt>4015ff: 83 f8 03 cmp $0x3,%eax401602: 75 31 jne 401635 <phase_defused+0x71>401604: be 22 26 40 00 mov $0x402622,%esi401609: 48 8d 7c 24 10 lea 0x10(%rsp),%rdi40160e: e8 25 fd ff ff callq 401338 <strings_not_equal>401613: 85 c0 test %eax,%eax401615: 75 1e jne 401635 <phase_defused+0x71>401617: bf f8 24 40 00 mov $0x4024f8,%edi40161c: e8 ef f4 ff ff callq 400b10 <puts@plt>401621: bf 20 25 40 00 mov $0x402520,%edi401626: e8 e5 f4 ff ff callq 400b10 <puts@plt>40162b: b8 00 00 00 00 mov $0x0,%eax401630: e8 0d fc ff ff callq 401242 <secret_phase>401635: bf 58 25 40 00 mov $0x402558,%edi
(gdb) x/s 0x603870
0x603870 <input_strings+240>: "1 0"
(gdb) x/s 0x402619
0x402619: "%d %d %s"
充满好奇地看了看这两个地址的内容,发现,淦,这不就是phase_4的keys吗!
(gdb) x/s 0x402622
0x402622: "DrEvil"
这时向后看,它将0x402622的内容和0x10(%rsp)进行了比较
看一下里面的内容。啊,这就有那味了,应该是要我们输入的开关,那么在哪输入呢…
啊哈!phase_4的keys再加上这个DrEvil就是三个输入,那应该就可以打开这个隐藏过程了
嘿嘿,我们来试一试!
Halfway there!
1 0 DrEvil
So you got that one. Try this one.
ionefg
Good work! On to the next...
4 3 2 1 6 5
Curses, you've found the secret phase!
But finding it and solving it are quite different...
_看来我们已经成功进入了,接下来是解密的时候了!!!
先看secret_phase
0000000000401242 <secret_phase>:401242: 53 push %rbx401243: e8 56 02 00 00 callq 40149e <read_line>
Curses, you've found the secret phase!
But finding it and solving it are quite different...
6(gdb) info registers
rax 0x603960 6306144(gdb) x/s 0x603960
0x603960 <input_strings+480>: "6"
利用gdb工具得出read_line将我们的输入存入%rax返回
401248: ba 0a 00 00 00 mov $0xa,%edx40124d: be 00 00 00 00 mov $0x0,%esi401252: 48 89 c7 mov %rax,%rdi401255: e8 76 f9 ff ff callq 400bd0 <strtol@plt>、
再次通过gdb工具调查strtol@plt的功能
Curses, you've found the secret phase!
But finding it and solving it are quite different...
66Breakpoint 1, 0x000000000040125a in secret_phase ()
(gdb) info registers
rax 0x42 66
可以看到该函数是将输入的字符串变成常数返回
40125a: 48 89 c3 mov %rax,%rbx40125d: 8d 40 ff lea -0x1(%rax),%eax401260: 3d e8 03 00 00 cmp $0x3e8,%eax401265: 76 05 jbe 40126c <secret_phase+0x2a>401267: e8 ce 01 00 00 callq 40143a <explode_bomb>
从这段代码可以得知输入的数字应该小于1001
40126c: 89 de mov %ebx,%esi40126e: bf f0 30 60 00 mov $0x6030f0,%edi401273: e8 8c ff ff ff callq 401204 <fun7>401278: 83 f8 02 cmp $0x2,%eax40127b: 74 05 je 401282 <secret_phase+0x40>40127d: e8 b8 01 00 00 callq 40143a <explode_bomb>401282: bf 38 24 40 00 mov $0x402438,%edi401287: e8 84 f8 ff ff callq 400b10 <puts@plt>40128c: e8 33 03 00 00 callq 4015c4 <phase_defused>401291: 5b pop %rbx401292: c3 retq
可以看到只有fun7的返回值为2才不会引爆炸弹,所以我们重点研究它
这是secret_phase中调用的fun7
0000000000401204 <fun7>:401204: 48 83 ec 08 sub $0x8,%rsp401208: 48 85 ff test %rdi,%rdi40120b: 74 2b je 401238 <fun7+0x34>40120d: 8b 17 mov (%rdi),%edx40120f: 39 f2 cmp %esi,%edx401211: 7e 0d jle 401220 <fun7+0x1c>401213: 48 8b 7f 08 mov 0x8(%rdi),%rdi401217: e8 e8 ff ff ff callq 401204 <fun7>40121c: 01 c0 add %eax,%eax40121e: eb 1d jmp 40123d <fun7+0x39>401220: b8 00 00 00 00 mov $0x0,%eax401225: 39 f2 cmp %esi,%edx401227: 74 14 je 40123d <fun7+0x39>401229: 48 8b 7f 10 mov 0x10(%rdi),%rdi40122d: e8 d2 ff ff ff callq 401204 <fun7>401232: 8d 44 00 01 lea 0x1(%rax,%rax,1),%eax401236: eb 05 jmp 40123d <fun7+0x39>401238: b8 ff ff ff ff mov $0xffffffff,%eax40123d: 48 83 c4 08 add $0x8,%rsp401241: c3 retq
可以看到对于不同情况,rdi只有两个选项,即+16或者+8,这时候还没有头绪,就先用gdb康康这里面存储的内容叭
(gdb) x/ 0x6030f0
0x6030f0 <n1>: 0x24
(gdb) x/ 0x6030f8
0x6030f8 <n1+8>: 0x603110 <n21>
(gdb) x/ 0x603100
0x603100 <n1+16>: 0x603130 <n22>
(gdb) x/ 0x603110
0x603110 <n21>: 0x8
(gdb) x/ 0x603130
0x603130 <n22>: 0x32
(gdb) x/ 0x603118
0x603118 <n21+8>: 0x603190 <n31>
(gdb) x/ 0x603120
0x603120 <n21+16>: 0x603150 <n32>
(gdb) x/ 0x603130
0x603130 <n22>: 0x32
(gdb) x/ 0x603138
0x603138 <n22+8>: 0x603170 <n33>
(gdb) x/ 0x603140
0x603140 <n22+16>: 0x6031b0 <n34>
(gdb) x/20a 0x6030f0
这… 貌似是一颗二叉树???<21>代表第二层第一个结点???
我们来画一画叭(均为10进制)
汇编可以改写为
int fun7(rdi,int input)
{int value=(%rdi);if(value==0)return -1;if(%rdi>input){%rdi=%rdi+8;fun7(%rdi,input);return_value=2*return_value;return return_value;}else{if(%rdi==input){return_value=0;return return_value;}%rdi=%rdi+16;fun7(%rdi,input);return_value=1+2*return_value;return return_value;}
}
要让返回值等于2,只有在最后出现2(1+2 * 0)才可以。即先返回0,再返回 1+2 * return,再返回2 * return。
所以最外层的0x24一定大于输入的值,而最内层一定是与输入相等
中间一层必须小于输入,我们可以在树中看到36,8,22这个序列正好符合
所以keys应该就是22,我们来试一试!
Curses, you've found the secret phase!
But finding it and solving it are quite different...
22
Wow! You've defused the secret stage!
Congratulations! You've defused the bomb!
NICE!!!
花费了数个夜晚,终于拆完了!
可惜我的头发啊啊啊啊!!!
二进制拆弹(炸弹炸掉了我的头发 T.T)相关推荐
- [逆向工程] 二进制拆弹Binary Bombs 快乐拆弹 详解
二进制拆弹 binary bombs 教你最快速解题,成功拆弹 最近计算机基础课,的实验lab2,二进制拆弹,可以说是拆的我很快乐了(sub n, %hair) 此处头发减n 我刚开始做的时候很是懵逼 ...
- 二进制拆弹实验详解linux,拆解二进制炸弹
拆解二进制炸弹 一.实验目的 1.理解C语言程序的机器级表示. 2.初步掌握GDB调试器的用法. 3.阅读C编译器生成的x86-64机器代码,理解不同控制结构生成的基本指令模式,过程的实现. 二. 实 ...
- 计算机系统二进制炸弹实验报告,二进制拿炸弹实验报告完整版.doc
课程名称:计算机系统原理实验 实验课时:32课时 实验项目名称:BombLab二进制炸弹 实验材料:可执行文件bomb.源代码bomb.c.说明README 实验环境:Linux操作系统(安装虚拟机和 ...
- CSAPP lab2 二进制拆弹 binary bombs phase_6
给出对应于7个阶段的7篇博客 phase_1 https://www.cnblogs.com/wkfvawl/p/10632044.html phase_2 https://www.cnblogs ...
- 汇编 二进制拆炸弹 r -t 3 -x 124
文章目录 注 实验环境: 实验内容 实验步骤 调试过程及实验 总结 附录 注 QUT大二汇编最后一个作业:拆炸弹 通过两天中间隙来做这个实验,不能交个实验报告就完事了,毕竟是第一次接触逆向工程,老师为 ...
- 计算机系统基础实验:二进制拆弹实验
一.实验目的: 学习并熟练使用 gdb 调试器和 objdump 理解汇编语言代码的行为或作用 提高阅读和理解汇编代码的能力 二.实验要求 实验共包括七个阶段,每个阶段考察机器级语言程序的不同方面,难 ...
- 二进制拆弹实验详解_Population Count算法-求二进制数中1的个数
所谓Population Count算法,即是指计算一个二进制数中1的个数的算法.具体来说,就是任意给定一个无符号整数N,求N的二进制表示中1的个数,比如N = 5(0101)时,返回2:N = 15 ...
- 二进制炸弹(arm)
x86上的二进制炸弹对于反汇编的练习来说还是比较经典的,由于网上有很多该程序的讲解,所以在此我打算写一下arm平台上的二进制拆炸弹这个游戏. 环境的搭建 由于是arm平台的环境,所以需要在linux环 ...
- 99. 激光炸弹(前缀和)
题目:输入N个宝物的位置和价值,给出一个炸弹的炸弹范围(是一个正方形)的边长,找出一颗炸弹最多能炸掉的最大价值 题目中的宝物放在一个(x,y)的点上,而我们的炸弹是炸一个(r,r)的范围,所以如果一个 ...
最新文章
- Nginx网站常见的跳转配置实例
- 色彩缤纷的python(改变字体颜色及样式)
- 4.4 使用STM32控制MC20进行GPS帧数据解析
- undefined reference to '__gxx_personality_v0'
- Spring配置文件约束头
- 前端学习(2502):vue指令v-if
- Python中文编码 - Python零基础入门教程
- BlueIdea 7周年 北京欢天喜地大聚会
- 支付宝集五福下周一开始;iPhone 面世 13 周年;Laravel 6.10.0 发布 | 极客头条
- VS2015 vs2017 密钥
- 图像的上采样与下采样
- python适合创业吗-python创业
- 高质量程序设计指南(笔记)
- Zinc 全文搜索引擎Elasticsearch轻量级替代品
- ppt学习06——排版
- 使用飞桨PaddleHub实现将视频动作转化为皮影戏
- WPS画报的电脑壁纸怎么下载
- 嵌入式uClinux及其应用开发(1)
- 工作环境搭建CheckList
- 【机器学习开放项目】NBA统计数据分析