实验目的
- 通过二进制炸弹实验,熟悉汇编语言
- 熟悉GDB调试工具
算法思路
编译环境
gcc version 7.5.0 (Ubuntu 7.5.0-3ubuntu1~18.04)
GNU gdb (Ubuntu 8.1.1-0ubuntu1) 8.1.1
GDB命令
1. gdb bomb 进入调试
2. b phase_1 在函数phase_1打断点
b *0x1000 在具体地址打断点
3. c continue 继续调试,直到下一断点
4. si 单步调试
5. disas 反汇编
Phase_1
代码
00000000000015e7 <phase_1>:
15e7: f3 0f 1e fa endbr64
15eb: 48 83 ec 08 sub $0x8,%rsp
15ef: 48 8d 35 5a 1b 00 00 lea 0x1b5a(%rip),%rsi # 3150 <_IO_stdin_used+0x150>
15f6: e8 56 05 00 00 callq 1b51 <strings_not_equal>
15fb: 85 c0 test %eax,%eax
15fd: 75 05 jne 1604 <phase_1+0x1d>
15ff: 48 83 c4 08 add $0x8,%rsp
1603: c3 retq
1604: e8 38 08 00 00 callq 1e41 <explode_bomb>
1609: eb f4 jmp 15ff <phase_1+0x18>
0000000000001b51 <strings_not_equal>:
1b51: f3 0f 1e fa endbr64
1b55: 41 54 push %r12
1b57: 55 push %rbp
1b58: 53 push %rbx
1b59: 48 89 fb mov %rdi,%rbx
1b5c: 48 89 f5 mov %rsi,%rbp
1b5f: e8 cc ff ff ff callq 1b30 <string_length>
1b64: 41 89 c4 mov %eax,%r12d
1b67: 48 89 ef mov %rbp,%rdi
1b6a: e8 c1 ff ff ff callq 1b30 <string_length>
1b6f: 89 c2 mov %eax,%edx
1b71: b8 01 00 00 00 mov $0x1,%eax
1b76: 41 39 d4 cmp %edx,%r12d
1b79: 75 31 jne 1bac <strings_not_equal+0x5b>
1b7b: 0f b6 13 movzbl (%rbx),%edx
1b7e: 84 d2 test %dl,%dl
1b80: 74 1e je 1ba0 <strings_not_equal+0x4f>
1b82: b8 00 00 00 00 mov $0x0,%eax
1b87: 38 54 05 00 cmp %dl,0x0(%rbp,%rax,1)
1b8b: 75 1a jne 1ba7 <strings_not_equal+0x56>
1b8d: 48 83 c0 01 add $0x1,%rax
1b91: 0f b6 14 03 movzbl (%rbx,%rax,1),%edx
1b95: 84 d2 test %dl,%dl
1b97: 75 ee jne 1b87 <strings_not_equal+0x36>
1b99: b8 00 00 00 00 mov $0x0,%eax
1b9e: eb 0c jmp 1bac <strings_not_equal+0x5b>
1ba0: b8 00 00 00 00 mov $0x0,%eax
1ba5: eb 05 jmp 1bac <strings_not_equal+0x5b>
1ba7: b8 01 00 00 00 mov $0x1,%eax
1bac: 5b pop %rbx
1bad: 5d pop %rbp
1bae: 41 5c pop %r12
1bb0: c3 retq
答案
Border relations with Canada have never been better.
解答
由函数名“string_not_equal”可知,phase_1涉及字符串操作。
对phase_1反汇编,发现读入字符串地址为:
15ef: 48 8d 35 5a 1b 00 00 lea 0x1b5a(%rip),%rsi # 0x555555557150
使用GDB调试命令,得到字符串,留待观察。
x/s 0x555555557150
>>0x555555557150 :"Border relations with Canada have never been better."
在string_not_equal函数中,发现有以下程序段:
1b59: 48 89 fb mov %rdi,%rbx
1b76: 41 39 d4 cmp %edx,%r12d
1b79: 75 31 jne 1bac <strings_not_equal+0x5b>
分析知,应该是将输入的字符串与既定的字符串进行比较,而既定的字符串存在%rdi中。那么可知,地址0x555555557150中存入的就是要输入的字符串。
Phase_2
代码
000000000000160b <phase_2>:
160b: f3 0f 1e fa endbr64
160f: 55 push %rbp
1610: 53 push %rbx
1611: 48 83 ec 28 sub $0x28,%rsp
1615: 64 48 8b 04 25 28 00 mov %fs:0x28,%rax
161c: 00 00
161e: 48 89 44 24 18 mov %rax,0x18(%rsp)
1623: 31 c0 xor %eax,%eax
1625: 48 89 e6 mov %rsp,%rsi
1628: e8 56 08 00 00 callq 1e83 <read_six_numbers>
162d: 83 3c 24 00 cmpl $0x0,(%rsp)
1631: 75 07 jne 163a <phase_2+0x2f>
1633: 83 7c 24 04 01 cmpl $0x1,0x4(%rsp)
1638: 74 05 je 163f <phase_2+0x34>
163a: e8 02 08 00 00 callq 1e41 <explode_bomb>
163f: 48 89 e3 mov %rsp,%rbx
1642: 48 8d 6c 24 10 lea 0x10(%rsp),%rbp
1647: eb 0e jmp 1657 <phase_2+0x4c>
1649: e8 f3 07 00 00 callq 1e41 <explode_bomb>
164e: 48 83 c3 04 add $0x4,%rbx
1652: 48 39 eb cmp %rbp,%rbx
1655: 74 0c je 1663 <phase_2+0x58>
1657: 8b 43 04 mov 0x4(%rbx),%eax
165a: 03 03 add (%rbx),%eax
165c: 39 43 08 cmp %eax,0x8(%rbx)
165f: 74 ed je 164e <phase_2+0x43>
1661: eb e6 jmp 1649 <phase_2+0x3e>
1663: 48 8b 44 24 18 mov 0x18(%rsp),%rax
1668: 64 48 33 04 25 28 00 xor %fs:0x28,%rax
166f: 00 00
1671: 75 07 jne 167a <phase_2+0x6f>
1673: 48 83 c4 28 add $0x28,%rsp
1677: 5b pop %rbx
1678: 5d pop %rbp
1679: c3 retq
167a: e8 d1 fb ff ff callq 1250 <__stack_chk_fail@plt>
答案
0 1 1 2 3 5
解答
看到函数read_six_number,则试图进入函数。
1628: e8 56 08 00 00 callq 1e83 <read_six_numbers>
disas反汇编phase_2,将断点打在0x1628处。si进入函数。
disas
b *0000555555555628
c
si
disas反汇编read_six_number,发现几行关键代码如下:
1ea4: 48 8d 35 5e 15 00 00 lea 0x155e(%rip),%rsi # 3409 <array.3471+0x229>
1eb0: e8 3b f4 ff ff callq 12f0 <__isoc99_sscanf@plt>
1eb9: 83 f8 05 cmp $0x5,%eax
1ebc: 7e 05 jle 1ec3 <read_six_numbers+0x40>
1ea4:读入格式字符串,对注释地址0x555555557490进行反汇编。说明需要输入6个整数。
x/s 0x555555557490
>>0x555555557490 :"%d %d %d %d %d %d"
1eb0:调用sscanf函数。C 库函数 int sscanf(const char *str, const char *format, …) 从字符串读取格式化输入。
1eb9:%eax中存入读取整数的数量,对此进行反汇编。
p $eax
>>$1 = 6
说明读入6个整数,不会爆炸。
之后进入对于数组的推断。由之后频繁的%rsp操作和其位移可知,输入数组结果存储在%rsp中。
162d: 83 3c 24 00 cmpl $0x0,(%rsp)
1631: 75 07 jne 163a <phase_2+0x2f>
由以上汇编代码知,0x0(%rsp)中存值0。
1633: 83 7c 24 04 01 cmpl $0x1,0x4(%rsp)
1638: 74 05 je 163f <phase_2+0x34>
163a: e8 02 08 00 00 callq 1e41 <explode_bomb>
由以上汇编代码知,若0x4(%rsp)中存值1,则跳转,否则爆炸。
163f: 48 89 e3 mov %rsp,%rbx
1642: 48 8d 6c 24 10 lea 0x10(%rsp),%rbp
1647: eb 0e jmp 1657 <phase_2+0x4c>
164e: 48 83 c3 04 add $0x4,%rbx
1652: 48 39 eb cmp %rbp,%rbx
1655: 74 0c je 1663 <phase_2+0x58>
1657: 8b 43 04 mov 0x4(%rbx),%eax
165a: 03 03 add (%rbx),%eax
165c: 39 43 08 cmp %eax,0x8(%rbx)
165f: 74 ed je 164e <phase_2+0x43>
1661: eb e6 jmp 1649 <phase_2+0x3e>
163f:将%rsp存入%rbx
1642:将%rsp+16存入%rbp
1657-165c:%eax=0x4(%rbx)+(%rbx),将结果与0x10(%rbx)(第三个值比较)。
若相等则进行循环,%rbx向后位移0x4,直到%rbp==%rbx,即%rbx移动到倒数第二个。
由此可知,设数组为a[6],则a[n+2]=a[n+1]+a[n]。根据前两个值,可以得出结论,数组为{0,1,1,2,3,5}。
Phase_3
代码
000000000000167f <phase_3>:
167f: f3 0f 1e fa endbr64
1683: 48 83 ec 18 sub $0x18,%rsp
1687: 64 48 8b 04 25 28 00 mov %fs:0x28,%rax
168e: 00 00
1690: 48 89 44 24 08 mov %rax,0x8(%rsp)
1695: 31 c0 xor %eax,%eax
1697: 48 8d 4c 24 04 lea 0x4(%rsp),%rcx
169c: 48 89 e2 mov %rsp,%rdx
169f: 48 8d 35 6f 1d 00 00 lea 0x1d6f(%rip),%rsi # 3415 <array.3471+0x235>
16a6: e8 45 fc ff ff callq 12f0 <__isoc99_sscanf@plt>
16ab: 83 f8 01 cmp $0x1,%eax
16ae: 7e 1e jle 16ce <phase_3+0x4f>
16b0: 83 3c 24 07 cmpl $0x7,(%rsp)
16b4: 0f 87 9a 00 00 00 ja 1754 <phase_3+0xd5>
16ba: 8b 04 24 mov (%rsp),%eax
16bd: 48 8d 15 fc 1a 00 00 lea 0x1afc(%rip),%rdx # 31c0 <_IO_stdin_used+0x1c0>
16c4: 48 63 04 82 movslq (%rdx,%rax,4),%rax
16c8: 48 01 d0 add %rdx,%rax
16cb: 3e ff e0 notrack jmpq *%rax
16ce: e8 6e 07 00 00 callq 1e41 <explode_bomb>
16d3: eb db jmp 16b0 <phase_3+0x31>
16d5: b8 8a 00 00 00 mov $0x8a,%eax
16da: 2d a5 01 00 00 sub $0x1a5,%eax
16df: 05 5c 01 00 00 add $0x15c,%eax
16e4: 2d b8 03 00 00 sub $0x3b8,%eax
16e9: 05 b8 03 00 00 add $0x3b8,%eax
16ee: 2d b8 03 00 00 sub $0x3b8,%eax
16f3: 05 b8 03 00 00 add $0x3b8,%eax
16f8: 2d b8 0