二进制拆弹(炸弹炸掉了我的头发 T.T)

所需要使用的调试工具

1. gdb工具

  1. 使用 break *地址来设置断点,使用c指令从断点继续执行
  2. 使用 info registers 指令观察寄存器状态
  3. 使用 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,%rsp
  400ee4:	be 00 24 40 00       	mov    $0x402400,%esi
  400ee9:	e8 4a 04 00 00       	callq  401338 <strings_not_equal>
  400eee:	85 c0                	test   %eax,%eax
  400ef0:	74 05                	je     400ef7 <phase_1+0x17>
  400ef2:	e8 43 05 00 00       	callq  40143a <explode_bomb>
  400ef7:	48 83 c4 08          	add    $0x8,%rsp
  400efb:	c3                   	retq   

看到它调用了<string_not_equal>
截取一个重要部分

0000000000401338 <strings_not_equal>:
  401338:	41 54                	push   %r12
  40133a:	55                   	push   %rbp
  40133b:	53                   	push   %rbx
  40133c:	48 89 fb             	mov    %rdi,%rbx
  40133f:	48 89 f5             	mov    %rsi,%rbp
  401342:	e8 d4 ff ff ff       	callq  40131b <string_length>
  401347:	41 89 c4             	mov    %eax,%r12d
  40134a:	48 89 ef             	mov    %rbp,%rdi
  40134d:	e8 c9 ff ff ff       	callq  40131b <string_length>
  401352:	ba 01 00 00 00       	mov    $0x1,%edx
  401357:	41 39 c4             	cmp    %eax,%r12d
  40135a:	75 3f                	jne    40139b <strings_not_equal+0x63>
  40139b:	89 d0                	mov    %edx,%eax
  40139d:	5b                   	pop    %rbx
  40139e:	5d                   	pop    %rbp
  40139f:	41 5c                	pop    %r12
  4013a1:	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   %rbp
  400efd:	53                   	push   %rbx
  400efe:	48 83 ec 28          	sub    $0x28,%rsp
  400f02:	48 89 e6             	mov    %rsp,%rsi
  400f05:	e8 52 05 00 00       	callq  40145c <read_six_numbers>

先看函数中调用的<read_six_numbers>

000000000040145c <read_six_numbers>:
  40145c:	48 83 ec 18          	sub    $0x18,%rsp
  401460:	48 89 f2             	mov    %rsi,%rdx
  401463:	48 8d 4e 04          	lea    0x4(%rsi),%rcx
  401467:	48 8d 46 14          	lea    0x14(%rsi),%rax
  40146b:	48 89 44 24 08       	mov    %rax,0x8(%rsp)
  401470:	48 8d 46 10          	lea    0x10(%rsi),%rax
  401474:	48 89 04 24          	mov    %rax,(%rsp)
  401478:	4c 8d 4e 0c          	lea    0xc(%rsi),%r9
  40147c:	4c 8d 46 08          	lea    0x8(%rsi),%r8
  401480:	be c3 25 40 00       	mov    $0x4025c3,%esi
  401485:	b8 00 00 00 00       	mov    $0x0,%eax
  40148a:	e8 61 f7 ff ff       	callq  400bf0 <__isoc99_sscanf@plt>
  40148f:	83 f8 05             	cmp    $0x5,%eax
  401492:	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,%rsp
  40149d:	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),%eax
  400f1a:	01 c0                	add    %eax,%eax
  400f1c:	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,%rbx
  400f29:	48 39 eb             	cmp    %rbp,%rbx
  400f2c:	75 e9                	jne    400f17 <phase_2+0x1b>
  400f2e:	eb 0c                	jmp    400f3c <phase_2+0x40>
  400f30:	48 8d 5c 24 04       	lea    0x4(%rsp),%rbx
  400f35:	48 8d 6c 24 18       	lea    0x18(%rsp),%rbp
  400f3a:	eb db                	jmp    400f17 <phase_2+0x1b>
  400f3c:	48 83 c4 28          	add    $0x28,%rsp
  400f40:	5b                   	pop    %rbx
  400f41:	5d                   	pop    %rbp
  400f42:	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),%eax
  400f1a:	01 c0                	add    %eax,%eax
  400f1c:	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+4

400f25:	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,%rsp
  400f47:	48 8d 4c 24 0c       	lea    0xc(%rsp),%rcx
  400f4c:	48 8d 54 24 08       	lea    0x8(%rsp),%rdx
  400f51:	be cf 25 40 00       	mov    $0x4025cf,%esi
  400f56:	b8 00 00 00 00       	mov    $0x0,%eax
  400f5b:	e8 90 fc ff ff       	callq  400bf0 <__isoc99_sscanf@plt>
  400f60:	83 f8 01             	cmp    $0x1,%eax
  400f63:	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,%rsp
  401010:	48 8d 4c 24 0c       	lea    0xc(%rsp),%rcx
  401015:	48 8d 54 24 08       	lea    0x8(%rsp),%rdx
  40101a:	be cf 25 40 00       	mov    $0x4025cf,%esi
  40101f:	b8 00 00 00 00       	mov    $0x0,%eax
  401024:	e8 c7 fb ff ff       	callq  400bf0 <__isoc99_sscanf@plt>
  401029:	83 f8 02             	cmp    $0x2,%eax
  40102c:	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,%edx
  40103f:	be 00 00 00 00       	mov    $0x0,%esi
  401044:	8b 7c 24 08          	mov    0x8(%rsp),%edi
  401048:	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,%rsp
  400fd2:	89 d0                	mov    %edx,%eax
  400fd4:	29 f0                	sub    %esi,%eax
  400fd6:	89 c1                	mov    %eax,%ecx
  400fd8:	c1 e9 1f             	shr    $0x1f,%ecx
  400fdb:	01 c8                	add    %ecx,%eax
  400fdd:	d1 f8                	sar    %eax
  400fdf:	8d 0c 30             	lea    (%rax,%rsi,1),%ecx
  400fe2:	39 f9                	cmp    %edi,%ecx
  400fe4:	7e 0c                	jle    400ff2 <func4+0x24>
  400fe6:	8d 51 ff             	lea    -0x1(%rcx),%edx
  400fe9:	e8 e0 ff ff ff       	callq  400fce <func4>
  400fee:	01 c0                	add    %eax,%eax
  400ff0:	eb 15                	jmp    401007 <func4+0x39>
  400ff2:	b8 00 00 00 00       	mov    $0x0,%eax
  400ff7:	39 f9                	cmp    %edi,%ecx
  400ff9:	7d 0c                	jge    401007 <func4+0x39>
  400ffb:	8d 71 01             	lea    0x1(%rcx),%esi
  400ffe:	e8 cb ff ff ff       	callq  400fce <func4>
  401003:	8d 44 00 01          	lea    0x1(%rax,%rax,1),%eax
  401007:	48 83 c4 08          	add    $0x8,%rsp
  40100b:	c3                   	retq  

此时我们一直跟随着可跳转的代码,发现当rdi==1时,就可以直接跳出递归,且此时%rax=0
继续看phase_4的后一段代码

 40104d:	85 c0                	test   %eax,%eax
  40104f:	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,%rsp
  401061:	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   %rbx
  401063:	48 83 ec 20          	sub    $0x20,%rsp
  401067:	48 89 fb             	mov    %rdi,%rbx
  40106a:	64 48 8b 04 25 28 00 	mov    %fs:0x28,%rax
  401071:	00 00 
  401073:	48 89 44 24 18       	mov    %rax,0x18(%rsp)
  401078:	31 c0                	xor    %eax,%eax
  40107a:	e8 9c 02 00 00       	callq  40131b <string_length>
  40107f:	83 f8 06             	cmp    $0x6,%eax
  401082:	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),%ecx
 40108f:	88 0c 24             	mov    %cl,(%rsp)
 401092:	48 8b 14 24          	mov    (%rsp),%rdx
 401096:	83 e2 0f             	and    $0xf,%edx
 401099:	0f b6 92 b0 24 40 00 	movzbl 0x4024b0(%rdx),%edx
 4010a0:	88 54 04 10          	mov    %dl,0x10(%rsp,%rax,1)
 4010a4:	48 83 c0 01          	add    $0x1,%rax
 4010a8:	48 83 f8 06          	cmp    $0x6,%rax
 4010ac:	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,%esi
  4010b8:	48 8d 7c 24 10       	lea    0x10(%rsp),%rdi
  4010bd:	e8 76 02 00 00       	callq  401338 <strings_not_equal>
  4010c2:	85 c0                	test   %eax,%eax
  4010c4:	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,%eax
  4010d7:	eb b2                	jmp    40108b <phase_5+0x29>
  4010d9:	48 8b 44 24 18       	mov    0x18(%rsp),%rax
  4010de:	64 48 33 04 25 28 00 	xor    %fs:0x28,%rax
  4010e5:	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,%rsp
  4010f2:	5b                   	pop    %rbx
  4010f3:	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   %r14
  4010f6:	41 55                	push   %r13
  4010f8:	41 54                	push   %r12
  4010fa:	55                   	push   %rbp
  4010fb:	53                   	push   %rbx
  4010fc:	48 83 ec 50          	sub    $0x50,%rsp
  401100:	49 89 e5             	mov    %rsp,%r13
  401103:	48 89 e6             	mov    %rsp,%rsi
  401106:	e8 51 03 00 00       	callq  40145c <read_six_numbers>

由<read_six_numbers>可以得知我们的keys长度至少为6

  40110b:	49 89 e6             	mov    %rsp,%r14
  40110e:	41 bc 00 00 00 00    	mov    $0x0,%r12d
  401114:	4c 89 ed             	mov    %r13,%rbp
  401117:	41 8b 45 00          	mov    0x0(%r13),%eax
  40111b:	83 e8 01             	sub    $0x1,%eax
  40111e:	83 f8 05             	cmp    $0x5,%eax
  401121:	76 05                	jbe    401128 <phase_6+0x34>
  401123:	e8 12 03 00 00       	callq  40143a <explode_bomb>
  401128:	41 83 c4 01          	add    $0x1,%r12d
  40112c:	41 83 fc 06          	cmp    $0x6,%r12d
  401130:	74 21                	je     401153 <phase_6+0x5f>
  401132:	44 89 e3             	mov    %r12d,%ebx
  401135:	48 63 c3             	movslq %ebx,%rax
  401138:	8b 04 84             	mov    (%rsp,%rax,4),%eax
  40113b:	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,%ebx
  401148:	83 fb 05             	cmp    $0x5,%ebx
  40114b:	7e e8                	jle    401135 <phase_6+0x41>
  40114d:	49 83 c5 04          	add    $0x4,%r13
  401151:	eb c1                	jmp    401114 <phase_6+0x20>

阅读上述代码发现这是实现了确保每个数字都小于6且大于0

  401153:	48 8d 74 24 18       	lea    0x18(%rsp),%rsi
  401158:	4c 89 f0             	mov    %r14,%rax
  40115b:	b9 07 00 00 00       	mov    $0x7,%ecx
  401160:	89 ca                	mov    %ecx,%edx
  401162:	2b 10                	sub    (%rax),%edx
  401164:	89 10                	mov    %edx,(%rax)
  401166:	48 83 c0 04          	add    $0x4,%rax
  40116a:	48 39 f0             	cmp    %rsi,%rax
  40116d:	75 f1                	jne    401160 <phase_6+0x6c>

这段代码实现了7-每个数字的功能

  40116f:	be 00 00 00 00       	mov    $0x0,%esi
  401174:	eb 21                	jmp    401197 <phase_6+0xa3>
  401176:	48 8b 52 08          	mov    0x8(%rdx),%rdx
  40117a:	83 c0 01             	add    $0x1,%eax
  40117d:	39 c8                	cmp    %ecx,%eax
  40117f:	75 f5                	jne    401176 <phase_6+0x82>
  401181:	eb 05                	jmp    401188 <phase_6+0x94>
  401183:	ba d0 32 60 00       	mov    $0x6032d0,%edx
  401188:	48 89 54 74 20       	mov    %rdx,0x20(%rsp,%rsi,2)
  40118d:	48 83 c6 04          	add    $0x4,%rsi
  401191:	48 83 fe 18          	cmp    $0x18,%rsi
  401195:	74 14                	je     4011ab <phase_6+0xb7>
  401197:	8b 0c 34             	mov    (%rsp,%rsi,1),%ecx
  40119a:	83 f9 01             	cmp    $0x1,%ecx
  40119d:	7e e4                	jle    401183 <phase_6+0x8f>
  40119f:	b8 01 00 00 00       	mov    $0x1,%eax
  4011a4:	ba d0 32 60 00       	mov    $0x6032d0,%edx
  4011a9:	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),%rbx
 4011b0:	48 8d 44 24 28       	lea    0x28(%rsp),%rax
 4011b5:	48 8d 74 24 50       	lea    0x50(%rsp),%rsi
 4011ba:	48 89 d9             	mov    %rbx,%rcx
 4011bd:	48 8b 10             	mov    (%rax),%rdx
 4011c0:	48 89 51 08          	mov    %rdx,0x8(%rcx)
 4011c4:	48 83 c0 08          	add    $0x8,%rax
 4011c8:	48 39 f0             	cmp    %rsi,%rax
 4011cb:	74 05                	je     4011d2 <phase_6+0xde>
 4011cd:	48 89 d1             	mov    %rdx,%rcx
 4011d0:	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,%esi
  4015f5:	bf 70 38 60 00       	mov    $0x603870,%edi
  4015fa:	e8 f1 f5 ff ff       	callq  400bf0 <__isoc99_sscanf@plt>
  4015ff:	83 f8 03             	cmp    $0x3,%eax
  401602:	75 31                	jne    401635 <phase_defused+0x71>
  401604:	be 22 26 40 00       	mov    $0x402622,%esi
  401609:	48 8d 7c 24 10       	lea    0x10(%rsp),%rdi
  40160e:	e8 25 fd ff ff       	callq  401338 <strings_not_equal>
  401613:	85 c0                	test   %eax,%eax
  401615:	75 1e                	jne    401635 <phase_defused+0x71>
  401617:	bf f8 24 40 00       	mov    $0x4024f8,%edi
  40161c:	e8 ef f4 ff ff       	callq  400b10 <puts@plt>
  401621:	bf 20 25 40 00       	mov    $0x402520,%edi
  401626:	e8 e5 f4 ff ff       	callq  400b10 <puts@plt>
  40162b:	b8 00 00 00 00       	mov    $0x0,%eax
  401630:	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   %rbx
  401243:	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,%edx
  40124d:	be 00 00 00 00       	mov    $0x0,%esi
  401252:	48 89 c7             	mov    %rax,%rdi
  401255:	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...
66

Breakpoint 1, 0x000000000040125a in secret_phase ()
(gdb) info registers 
rax            0x42     66

可以看到该函数是将输入的字符串变成常数返回

  40125a:	48 89 c3             	mov    %rax,%rbx
  40125d:	8d 40 ff             	lea    -0x1(%rax),%eax
  401260:	3d e8 03 00 00       	cmp    $0x3e8,%eax
  401265:	76 05                	jbe    40126c <secret_phase+0x2a>
  401267:	e8 ce 01 00 00       	callq  40143a <explode_bomb>

从这段代码可以得知输入的数字应该小于1001

  40126c:	89 de                	mov    %ebx,%esi
  40126e:	bf f0 30 60 00       	mov    $0x6030f0,%edi
  401273:	e8 8c ff ff ff       	callq  401204 <fun7>
  401278:	83 f8 02             	cmp    $0x2,%eax
  40127b:	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,%edi
  401287:	e8 84 f8 ff ff       	callq  400b10 <puts@plt>
  40128c:	e8 33 03 00 00       	callq  4015c4 <phase_defused>
  401291:	5b                   	pop    %rbx
  401292:	c3                   	retq   

可以看到只有fun7的返回值为2才不会引爆炸弹,所以我们重点研究它

这是secret_phase中调用的fun7

0000000000401204 <fun7>:
  401204:	48 83 ec 08          	sub    $0x8,%rsp
  401208:	48 85 ff             	test   %rdi,%rdi
  40120b:	74 2b                	je     401238 <fun7+0x34>
  40120d:	8b 17                	mov    (%rdi),%edx
  40120f:	39 f2                	cmp    %esi,%edx
  401211:	7e 0d                	jle    401220 <fun7+0x1c>
  401213:	48 8b 7f 08          	mov    0x8(%rdi),%rdi
  401217:	e8 e8 ff ff ff       	callq  401204 <fun7>
  40121c:	01 c0                	add    %eax,%eax
  40121e:	eb 1d                	jmp    40123d <fun7+0x39>
  401220:	b8 00 00 00 00       	mov    $0x0,%eax
  401225:	39 f2                	cmp    %esi,%edx
  401227:	74 14                	je     40123d <fun7+0x39>
  401229:	48 8b 7f 10          	mov    0x10(%rdi),%rdi
  40122d:	e8 d2 ff ff ff       	callq  401204 <fun7>
  401232:	8d 44 00 01          	lea    0x1(%rax,%rax,1),%eax
  401236:	eb 05                	jmp    40123d <fun7+0x39>
  401238:	b8 ff ff ff ff       	mov    $0xffffffff,%eax
  40123d:	48 83 c4 08          	add    $0x8,%rsp
  401241:	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!!!
花费了数个夜晚,终于拆完了!
可惜我的头发啊啊啊啊!!!

  • 15
    点赞
  • 38
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值