• 这个 lab 开始还没那么好开始, 反正就先从熟悉 gdb 开始吧
  • 这里就是写些题解, 自己独立完成一遍会对其理解更深
  • 可以看看第一个, 清楚是怎么开始的
  • 然后加油捏

Lab_bomb

首先对 bomb 进行反编译

1
objdump -d bomb > bomb.asm 

然后可以在 bomb.asm 里面找到 <phase_1> 等内容

在用 gdb 打开 bomb

1
gdb bomb 

Phase_1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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          call   401338 <strings_not_equal>

  400eee:       85 c0                   test   %eax,%eax

  400ef0:       74 05                   je     400ef7 <phase_1+0x17>

  400ef2:       e8 43 05 00 00          call   40143a <explode_bomb>

  400ef7:       48 83 c4 08             add    $0x8,%rsp

  400efb:       c3                      ret
  • 先观察
    • 第一条命令 sub%rsp 下移了 8 个字节, 相当于在栈上分配了 8 个字节的空间
    • 然后用 mov$0x402400 的内容移动到 %esi 中, 这是常用于函数传递参数的寄存器
    • 再调用了一个在 401338 的函数, 总之就是一个比较字符串是否相等的函数
    • 若是相等则在 %eax 返回 0
    • 后面的 testje , 前者是对 %eax 进行位与操作, 先判断是否为 0, 若为 0 则会将零标志位 (ZF)设置为 0, 再通过后者跳转至 400ef7 进行释放以及接下来的返回, 否则就会进行到 400ef2 触发爆炸
  • 然后我们可以在其中某个位置设置断点来查看
  • 比如在第一个 call 这里
1
(gdb) b *0x400ee9
  • 然后再运行
  • 这里第一次可以随便输点东西
1
2
3
4
5
6
7
8
9
Welcome to my fiendish little bomb. You have 6 phases with

which to blow yourself up. Have a nice day!

llllluo



Breakpoint 1, 0x0000000000400ee9 in phase_1 ()
  • 现在就可以看看几个寄存器的数值了
1
2
3
(gdb) x/s $rsi

0x402400: "Border relations with Canada have never been better."
  • 可以看到这就是答案, 当然也可以看看别的
1
2
3
(gdb) x/s $rdi

0x603780 <input_strings>: "llllluo"
  • 这是刚才输入的
  • 然后我们到下一关

Phase_2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
0000000000400efc <phase_2>:
400efc: 55 pushq %rbp
400efd: 53 pushq %rbx
400efe: 48 83 ec 28 subq $40, %rsp
400f02: 48 89 e6 movq %rsp, %rsi
400f05: e8 52 05 00 00 callq 0x40145c <read_six_numbers>
400f0a: 83 3c 24 01 cmpl $1, (%rsp)
400f0e: 74 20 je 0x400f30 <phase_2+0x34>
400f10: e8 25 05 00 00 callq 0x40143a <explode_bomb>
400f15: eb 19 jmp 0x400f30 <phase_2+0x34>
400f17: 8b 43 fc movl -4(%rbx), %eax
400f1a: 01 c0 addl %eax, %eax // *2
400f1c: 39 03 cmpl %eax, (%rbx)
400f1e: 74 05 je 0x400f25 <phase_2+0x29>
400f20: e8 15 05 00 00 callq 0x40143a <explode_bomb>
400f25: 48 83 c3 04 addq $4, %rbx
400f29: 48 39 eb cmpq %rbp, %rbx
400f2c: 75 e9 jne 0x400f17 <phase_2+0x1b>
400f2e: eb 0c jmp 0x400f3c <phase_2+0x40>
400f30: 48 8d 5c 24 04 leaq 4(%rsp), %rbx //计算下一个数地址
400f35: 48 8d 6c 24 18 leaq 24(%rsp), %rbp
400f3a: eb db jmp 0x400f17 <phase_2+0x1b>
400f3c: 48 83 c4 28 addq $40, %rsp
400f40: 5b popq %rbx
400f41: 5d popq %rbp
400f42: c3 retq
  • 可以尝试出其在函数 read_six_numbers 里面就进行了爆破, 所以我们在这里设个断点
  • 且可以找到数字串 0\341\377\377\377\177
  • 并且找到 %d %d %d %d %d %d
  • 大致判断是输入六个数, 其实大于五个就都没问题
  • 可以尝试随便输六个数进去, 刚好看到后面有个 cmpl $1, (%rsp), 所以试试第一个数输入 1
  • 把断点设在 0x400f0a, 可以看到
1
2
3
(gdb) x/d $rsp

0x7fffffffe380: 1
  • 确实是等于 1, 那么接着往后运行
  • 我们可以看到在 0x400f30 处程序计算了下一个数的地址并将其存入了 %rbx, 通过 gdb 也可以看到
  • 后面一步先不管它
  • 之后跳转到 0x400f17 可以看到 %eax 存入的应该是上一个数的值并且运行了 %eax+=%eax
  • 后面还有第二个数和 %eax 的比较, 所以可以推测第二个数就是 2
  • 然后判定一下是否结束
  • 反正就试试
1
2
3
1 2 4 8 16 32

That's number 2.  Keep going!
  • 成功了

Phase_3

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
0000000000400f43 <phase_3>:
400f43: 48 83 ec 18 subq $24, %rsp
400f47: 48 8d 4c 24 0c leaq 12(%rsp), %rcx
400f4c: 48 8d 54 24 08 leaq 8(%rsp), %rdx
400f51: be cf 25 40 00 movl $4203983, %esi # imm = 0x4025CF
400f56: b8 00 00 00 00 movl $0, %eax
400f5b: e8 90 fc ff ff callq 0x400bf0 <__isoc99_sscanf@plt>
400f60: 83 f8 01 cmpl $1, %eax
400f63: 7f 05 jg 0x400f6a <phase_3+0x27>
400f65: e8 d0 04 00 00 callq 0x40143a <explode_bomb>
400f6a: 83 7c 24 08 07 cmpl $7, 8(%rsp)
400f6f: 77 3c ja 0x400fad <phase_3+0x6a>
400f71: 8b 44 24 08 movl 8(%rsp), %eax
400f75: ff 24 c5 70 24 40 00 jmpq *4203632(,%rax,8)
400f7c: b8 cf 00 00 00 movl $207, %eax
400f81: eb 3b jmp 0x400fbe <phase_3+0x7b>
400f83: b8 c3 02 00 00 movl $707, %eax # imm = 0x2C3
400f88: eb 34 jmp 0x400fbe <phase_3+0x7b>
400f8a: b8 00 01 00 00 movl $256, %eax # imm = 0x100
400f8f: eb 2d jmp 0x400fbe <phase_3+0x7b>
400f91: b8 85 01 00 00 movl $389, %eax # imm = 0x185
400f96: eb 26 jmp 0x400fbe <phase_3+0x7b>
400f98: b8 ce 00 00 00 movl $206, %eax
400f9d: eb 1f jmp 0x400fbe <phase_3+0x7b>
400f9f: b8 aa 02 00 00 movl $682, %eax # imm = 0x2AA
400fa4: eb 18 jmp 0x400fbe <phase_3+0x7b>
400fa6: b8 47 01 00 00 movl $327, %eax # imm = 0x147
400fab: eb 11 jmp 0x400fbe <phase_3+0x7b>
400fad: e8 88 04 00 00 callq 0x40143a <explode_bomb>
400fb2: b8 00 00 00 00 movl $0, %eax
400fb7: eb 05 jmp 0x400fbe <phase_3+0x7b>
400fb9: b8 37 01 00 00 movl $311, %eax # imm = 0x137
400fbe: 3b 44 24 0c cmpl 12(%rsp), %eax
400fc2: 74 05 je 0x400fc9 <phase_3+0x86>
400fc4: e8 71 04 00 00 callq 0x40143a <explode_bomb>
400fc9: 48 83 c4 18 addq $24, %rsp
400fcd: c3 retq
  • 同样将断点设在未知函数和爆炸前
  • 看到 %esi 里面是 %d %d
  • 可以根据前面的经验推断未知函数是判断是否有两个输入的, 而事实也大抵如此
  • 然后可以看到在 0x400f6a 处比较第一个数与 7 的关系并在其不大于 7 时能顺利绕过爆炸, 再结合后面看到不循环的几个情况, 可以推测在 0x400f75 处的跳转是根据第一个数跳转到各个情况并且是单向线性的
  • 那么我们就可以直接试试比如第一种情况
1
2
3
4
5
That's number 2.  Keep going!

0 207

Halfway there!
  • 果然如此
  • 其它输入也同理

Phase_4

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
0000000000400fce <func4>:
400fce: 48 83 ec 08 subq $8, %rsp //开栈
400fd2: 89 d0 movl %edx, %eax %eax = %edx = 14
400fd4: 29 f0 subl %esi, %eax // %eax -= %esi = 0
400fd6: 89 c1 movl %eax, %ecx // %ecx = %eax = 0
400fd8: c1 e9 1f shrl $31, %ecx // 逻辑右移
400fdb: 01 c8 addl %ecx, %eax // %eax += %ecx = 14
400fdd: d1 f8 sarl %eax // 默认右移一位, 算术右移, %eax /= 2 = 7
400fdf: 8d 0c 30 leal (%rax,%rsi), %ecx //%eax 是 %rax 低32位部分 就 7
400fe2: 39 f9 cmpl %edi, %ecx // 俩都是 7
400fe4: 7e 0c jle 0x400ff2 <func4+0x24>
400fe6: 8d 51 ff leal -1(%rcx), %edx // 不是 7 就 -1
400fe9: e8 e0 ff ff ff callq 0x400fce <func4>
400fee: 01 c0 addl %eax, %eax
400ff0: eb 15 jmp 0x401007 <func4+0x39>
400ff2: b8 00 00 00 00 movl $0, %eax
400ff7: 39 f9 cmpl %edi, %ecx
400ff9: 7d 0c jge 0x401007 <func4+0x39>
400ffb: 8d 71 01 leal 1(%rcx), %esi
400ffe: e8 cb ff ff ff callq 0x400fce <func4>
401003: 8d 44 00 01 leal 1(%rax,%rax), %eax
401007: 48 83 c4 08 addq $8, %rsp
40100b: c3 retq

000000000040100c <phase_4>:
40100c: 48 83 ec 18 subq $24, %rsp // 开栈
401010: 48 8d 4c 24 0c leaq 12(%rsp), %rcx
401015: 48 8d 54 24 08 leaq 8(%rsp), %rdx
40101a: be cf 25 40 00 movl $4203983, %esi # imm = 0x4025CF
40101f: b8 00 00 00 00 movl $0, %eax
401024: e8 c7 fb ff ff callq 0x400bf0 <__isoc99_sscanf@plt> // 返回输入数个数
401029: 83 f8 02 cmpl $2, %eax
40102c: 75 07 jne 0x401035 <phase_4+0x29> // %eax = 2 = 输入为两个数
40102e: 83 7c 24 08 0e cmpl $14, 8(%rsp) // a1 <= 14
401033: 76 05 jbe 0x40103a <phase_4+0x2e> // be = below or equal
401035: e8 00 04 00 00 callq 0x40143a <explode_bomb>
40103a: ba 0e 00 00 00 movl $14, %edx // %edx = 14
40103f: be 00 00 00 00 movl $0, %esi // %esi = 0
401044: 8b 7c 24 08 movl 8(%rsp), %edi // %edi = a1
401048: e8 81 ff ff ff callq 0x400fce <func4>
40104d: 85 c0 testl %eax, %eax // %eax != 0
40104f: 75 07 jne 0x401058 <phase_4+0x4c>
401051: 83 7c 24 0c 00 cmpl $0, 12(%rsp) // a2 = 0
401056: 74 05 je 0x40105d <phase_4+0x51>
401058: e8 dd 03 00 00 callq 0x40143a <explode_bomb>
40105d: 48 83 c4 18 addq $24, %rsp
401061: c3 retq
  • 直接看汇编代码可以得到
1
2
7 0 
So you got that one. Try this one.

Phase_5

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
0000000000401062 <phase_5>:
401062: 53 pushq %rbx // 将%rbx压入栈中
401063: 48 83 ec 20 subq $32, %rsp // 开栈
401067: 48 89 fb movq %rdi, %rbx // %rbx = %rdi
40106a: 64 48 8b 04 25 28 00 00 00 movq %fs:40, %rax
401073: 48 89 44 24 18 movq %rax, 24(%rsp)
401078: 31 c0 xorl %eax, %eax // XOR
40107a: e8 9c 02 00 00 callq 0x40131b <string_length> // 返回字符串长度
40107f: 83 f8 06 cmpl $6, %eax // 长度为 6
401082: 74 4e je 0x4010d2 <phase_5+0x70>
401084: e8 b1 03 00 00 callq 0x40143a <explode_bomb>
401089: eb 47 jmp 0x4010d2 <phase_5+0x70>

// loop(%rax -> i = 0; i++; i <= 6)
40108b: 0f b6 0c 03 movzbl (%rbx,%rax), %ecx
40108f: 88 0c 24 movb %cl, (%rsp)
401092: 48 8b 14 24 movq (%rsp), %rdx
401096: 83 e2 0f andl $15, %edx // %edx = 1111 & %edx
401099: 0f b6 92 b0 24 40 00 movzbl 4203696(%rdx), %edx // maduiersnfotvbyl 后四位分别对应
4010a0: 88 54 04 10 movb %dl, 16(%rsp,%rax) // 将每个字符放到%rsp+16+%rax里面
4010a4: 48 83 c0 01 addq $1, %rax
4010a8: 48 83 f8 06 cmpq $6, %rax
4010ac: 75 dd jne 0x40108b <phase_5+0x29>
// loop end

4010ae: c6 44 24 16 00 movb $0, 22(%rsp) // 22 = 16 + 6, end signal
4010b3: be 5e 24 40 00 movl $4203614, %esi # imm = 0x40245E // "flyers" -> 9 15 14 5 6 7; 1001 1111 1110 0101 0110 1000 ;9 f e 5 6 7
4010b8: 48 8d 7c 24 10 leaq 16(%rsp), %rdi // rdi = input
4010bd: e8 76 02 00 00 callq 0x401338 <strings_not_equal> // %rsi & %rdi
4010c2: 85 c0 testl %eax, %eax // %eax = 0
4010c4: 74 13 je 0x4010d9 <phase_5+0x77>
4010c6: e8 6f 03 00 00 callq 0x40143a <explode_bomb>
4010cb: 0f 1f 44 00 00 nopl (%rax,%rax)
4010d0: eb 07 jmp 0x4010d9 <phase_5+0x77>
4010d2: b8 00 00 00 00 movl $0, %eax // %eax = 0
4010d7: eb b2 jmp 0x40108b <phase_5+0x29>
4010d9: 48 8b 44 24 18 movq 24(%rsp), %rax
4010de: 64 48 33 04 25 28 00 00 00 xorq %fs:40, %rax
4010e7: 74 05 je 0x4010ee <phase_5+0x8c>
4010e9: e8 42 fa ff ff callq 0x400b30 <__stack_chk_fail@plt>
4010ee: 48 83 c4 20 addq $32, %rsp
4010f2: 5b popq %rbx
4010f3: c3 retq
  • 这里是在 0x40108b 开始的 loop 里面与 4203696 里面的 16 个字符串相对应
  • 通过查 ascii 表可以找到答案
  • 示例
1
2
9?.567           
Good work! On to the next...

Phase_5

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
00000000004010f4 <phase_6>:
4010f4: 41 56 pushq %r14
4010f6: 41 55 pushq %r13
4010f8: 41 54 pushq %r12
4010fa: 55 pushq %rbp
4010fb: 53 pushq %rbx
4010fc: 48 83 ec 50 subq $80, %rsp // 开栈,分配

401100: 49 89 e5 movq %rsp, %r13
401103: 48 89 e6 movq %rsp, %rsi // %rsp -> %r13 -> %rsi
401106: e8 51 03 00 00 callq 0x40145c <read_six_numbers> // input = 6*, %rsi = 0
40110b: 49 89 e6 movq %rsp, %r14
40110e: 41 bc 00 00 00 00 movl $0, %r12d // %r12d = 0

// loop_2
401114: 4c 89 ed movq %r13, %rbp
401117: 41 8b 45 00 movl (%r13), %eax
40111b: 83 e8 01 subl $1, %eax // %eax - 1
40111e: 83 f8 05 cmpl $5, %eax
401121: 76 05 jbe 0x401128 <phase_6+0x34> // %eax <= 5
401123: e8 12 03 00 00 callq 0x40143a <explode_bomb>
401128: 41 83 c4 01 addl $1, %r12d // %r12d += 1
40112c: 41 83 fc 06 cmpl $6, %r12d
401130: 74 21 je 0x401153 <phase_6+0x5f> // 遍历完 6 个数后跳出 loop_2
401132: 44 89 e3 movl %r12d, %ebx
// loop_1(%ebx -> i = 0; i++; i >= 5)
401135: 48 63 c3 movslq %ebx, %rax // slq -> sign extension long to quad
401138: 8b 04 84 movl (%rsp,%rax,4), %eax
40113b: 39 45 00 cmpl %eax, (%rbp)
40113e: 75 05 jne 0x401145 <phase_6+0x51>
401140: e8 f5 02 00 00 callq 0x40143a <explode_bomb>
401145: 83 c3 01 addl $1, %ebx
401148: 83 fb 05 cmpl $5, %ebx
40114b: 7e e8 jle 0x401135 <phase_6+0x41>
// loop_1 end 不能等于 %rbp 指向的一个数
40114d: 49 83 c5 04 addq $4, %r13 // 指向下一个数
401151: eb c1 jmp 0x401114 <phase_6+0x20>
// loop_2 end
// 总之上面就是就是让这六个数各不相同

401153: 48 8d 74 24 18 leaq 24(%rsp), %rsi // %rsi 指向最后一个数的末尾
401158: 4c 89 f0 movq %r14, %rax // 指向第一个数
40115b: b9 07 00 00 00 movl $7, %ecx // %ecx = $7
// loop
401160: 89 ca movl %ecx, %edx // %edx = $7
401162: 2b 10 subl (%rax), %edx // %edx -= (%rax)
401164: 89 10 movl %edx, (%rax) // (%rax) = 7 - %rax
401166: 48 83 c0 04 addq $4, %rax // 指向下一个数
40116a: 48 39 f0 cmpq %rsi, %rax // 查看是否到末尾
40116d: 75 f1 jne 0x401160 <phase_6+0x6c>
// loop end %rax 指到最后一个数末尾停下
40116f: be 00 00 00 00 movl $0, %esi // %esi = 0
401174: eb 21 jmp 0x401197 <phase_6+0xa3> // 跳入下面的循环
// 这里数字变为 7 - a_x

// LOOP
401176: 48 8b 52 08 movq 8(%rdx), %rdx // %rdx += 8
40117a: 83 c0 01 addl $1, %eax // %eax += 1
40117d: 39 c8 cmpl %ecx, %eax // 7, %eax
40117f: 75 f5 jne 0x401176 <phase_6+0x82> //
401181: eb 05 jmp 0x401188 <phase_6+0x94>
// loop
401183: ba d0 32 60 00 movl $6304464, %edx # imm = 0x6032D0 // "332, 168, 924, 691, 477, 443" -> "3, 4, 5, 6, 1, 2" -> "4, 3, 2, 1, 6, 5"
401188: 48 89 54 74 20 movq %rdx, 32(%rsp,%rsi,2) // %rdx -> %rsp + 2*%rsi + 32
40118d: 48 83 c6 04 addq $4, %rsi // %rsi += 4
401191: 48 83 fe 18 cmpq $24, %rsi // 6 次后
401195: 74 14 je 0x4011ab <phase_6+0xb7> // 跳出 LOOP
401197: 8b 0c 34 movl (%rsp,%rsi), %ecx // %ecx = %rsp + %rsi; %ecx 指向下一个数
40119a: 83 f9 01 cmpl $1, %ecx
40119d: 7e e4 jle 0x401183 <phase_6+0x8f> // 到 a_x <= 1
// loop end
40119f: b8 01 00 00 00 movl $1, %eax // 初始化 %eax
4011a4: ba d0 32 60 00 movl $6304464, %edx # imm = 0x6032D0
4011a9: eb cb jmp 0x401176 <phase_6+0x82>
// LOOP END
// 存在一个链表, 读取到栈中

4011ab: 48 8b 5c 24 20 movq 32(%rsp), %rbx // (%rsp + 32) -> %rbx
4011b0: 48 8d 44 24 28 leaq 40(%rsp), %rax // %rax 指到下一个特殊值添加处
4011b5: 48 8d 74 24 50 leaq 80(%rsp), %rsi // %rsi 指向开栈栈底
4011ba: 48 89 d9 movq %rbx, %rcx // %rbx -> %rcx

// loop
4011bd: 48 8b 10 movq (%rax), %rdx
4011c0: 48 89 51 08 movq %rdx, 8(%rcx)
4011c4: 48 83 c0 08 addq $8, %rax
4011c8: 48 39 f0 cmpq %rsi, %rax // 到顶则停下跳出 loop
4011cb: 74 05 je 0x4011d2 <phase_6+0xde>
4011cd: 48 89 d1 movq %rdx, %rcx
4011d0: eb eb jmp 0x4011bd <phase_6+0xc9>
// loop end
4011d2: 48 c7 42 08 00 00 00 00 movq $0, 8(%rdx) // %rdx + 8 = 0
4011da: bd 05 00 00 00 movl $5, %ebp // %ebp = 5

// loop
4011df: 48 8b 43 08 movq 8(%rbx), %rax
4011e3: 8b 00 movl (%rax), %eax
4011e5: 39 03 cmpl %eax, (%rbx) // %eax >= (%rbx)
4011e7: 7d 05 jge 0x4011ee <phase_6+0xfa> // %rbx+8 >= %rbx
4011e9: e8 4c 02 00 00 callq 0x40143a <explode_bomb>
4011ee: 48 8b 5b 08 movq 8(%rbx), %rbx // %rbx += 8
4011f2: 83 ed 01 subl $1, %ebp // %ebp -= 1; 计数
4011f5: 75 e8 jne 0x4011df <phase_6+0xeb> // %ebp = 0 -> 5 - 1 * 5
// loop end 循环 5 次, 进行次序检测, 值为链表上的为准

4011f7: 48 83 c4 50 addq $80, %rsp // 归还栈
4011fb: 5b popq %rbx
4011fc: 5d popq %rbp
4011fd: 41 5c popq %r12
4011ff: 41 5d popq %r13
401201: 41 5e popq %r14
401203: c3 retq
  • 链表
1
2
3
4
5
6
7
(gdb) x/24qd 0x6032d0
0x6032d0 <node1>: 332 1 6304480 0
0x6032e0 <node2>: 168 2 6304496 0
0x6032f0 <node3>: 924 3 6304512 0
0x603300 <node4>: 691 4 6304528 0
0x603310 <node5>: 477 5 6304544 0
0x603320 <node6>: 443 6 0 0
1
2
4 3 2 1 6 5
Congratulations! You've defused the bomb!
  • 结束了!!!