上个月就开始搞CSAPP了,之前书没看好,LAB做起来也磕磕绊绊.把书的第三章重新看了遍后,再来做.
另外,大概也要定个计划把汇编学了
之前GDB一直不太会用,通过这个机会也是学习了下,后面希望提升自己的学习力,什么不会遇上了能快速的学习.
注意不要让bomb爆炸,虽然我们不会被扣分…..我一开始都是直接炸来炸去的…..
每做完一个部分,就可以将答案保持在solution.txt中,避免重复输入,使用set args ./solution.txt来设置答案
phase_1
1 | (gdb) disassemble phase_1 |
补个知识
- 常用寄存器有16个,分为x86通用寄存器以及r8-r15寄存器。
- 通用寄存器中,函数执行前后必须保持原始的寄存器有3个:是rbx、rbp、rsp。rx寄存器中,最后4个必须保持原值:r12、r13、r14、r15。
保持原值的意义是为了让当前函数有可信任的寄存器,减小在函数调用过程中的保存&恢复操作。除了rbp、rsp用于特定用途外,其余5个寄存器可随意使用。 - 通用寄存器中,不必假设保存值可随意使用的寄存器有5个:是rax、rcx、rdx、rdi、rsi。其中rax用于第一个返回寄存器(当 然也可以用于其它用途),rdx用于第二个返回寄存器(在调用函数时也用于第三个参数寄存器)。rcx用于第四个参数。rdi用于第一个参数。rsi用于 第二个函数参数。
- r8、r9分配用于第5、第6个参数。
第一题还是不难的,注意到1
20x0000000000400ee4 <+4>: mov $0x402400,%esi
0x0000000000400ee9 <+9>: callq 0x401338 <strings_not_equal>
从0x402400读入一个数到%esi,然后作为第二个参数传入函数中1
2(gdb) x/s 0x402400
0x402400: "Border relations with Canada have never been better."
1 | break phase_1 |
发现第一个参数就是我们输入的,和第二个$0x402400处的对比,然后return 0就不会炸
phase_2
1 | (gdb) disas phase_2 |
提醒还是有的,注意<read_six_numbers>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20(gdb) disas read_six_numbers
Dump of assembler code for function read_six_numbers:
0x000000000040145c <+0>: sub $0x18,%rsp
0x0000000000401460 <+4>: mov %rsi,%rdx
0x0000000000401463 <+7>: lea 0x4(%rsi),%rcx
0x0000000000401467 <+11>: lea 0x14(%rsi),%rax
0x000000000040146b <+15>: mov %rax,0x8(%rsp)
0x0000000000401470 <+20>: lea 0x10(%rsi),%rax
0x0000000000401474 <+24>: mov %rax,(%rsp)
0x0000000000401478 <+28>: lea 0xc(%rsi),%r9
0x000000000040147c <+32>: lea 0x8(%rsi),%r8
0x0000000000401480 <+36>: mov $0x4025c3,%esi
0x0000000000401485 <+41>: mov $0x0,%eax
0x000000000040148a <+46>: callq 0x400bf0 <__isoc99_sscanf@plt>
0x000000000040148f <+51>: cmp $0x5,%eax
0x0000000000401492 <+54>: jg 0x401499 <read_six_numbers+61>
0x0000000000401494 <+56>: callq 0x40143a <explode_bomb>
0x0000000000401499 <+61>: add $0x18,%rsp
0x000000000040149d <+65>: retq
End of assembler dump.
可以看出,这个函数是读了6个32位整数,首先有0x18 = 24 = 6 x 4,4x8位就是32位,另外下面的代码也有读入过程.
继续看phase_2
cmpl $0x1,(%rsp)`比较第一个数 和 1
直接写注释来的好.(⊙﹏⊙)
大概就是1乘以2 ,然后重复…
答案就是1 2 4 8 16 32
然后设置断点验证即可
phase_3
不肝了,今天1.30睡的,明天7.00起,要不然给自己耳光.对应刚刚才写了的随想,肝帝计划,计划容易一时,难在坚持,加油,明早继续更
2.00睡不着,起来更
1 | (gdb) disas phase_3 |
注意到jmpq *0x402470(,%rax,8)我们可以发现程序使用了跳转表1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16(gdb) x/1xg 0x402470
0x402470: 0x0000000000400f7c
(gdb) x/1xg 0x402478
0x402478: 0x0000000000400fb9
(gdb) x/1xg 0x402480
0x402480: 0x0000000000400f83
(gdb) x/1xg 0x402488
0x402488: 0x0000000000400f8a
(gdb) x/1xg 0x402490
0x402490: 0x0000000000400f91
(gdb) x/1xg 0x402498
0x402498: 0x0000000000400f98
(gdb) x/1xg 0x4024a0
0x4024a0: 0x0000000000400f9f
(gdb) x/1xg 0x4024a8
0x4024a8: 0x0000000000400fa6
1 | %rax(输入参数1) 跳转地址 0xc(%rsp)(输入参数2) |
ok啦
phase_4
1 | (gdb) disas phase_4 |
注意到jne 0x401058 <phase_4+76>,发现这个函数jump到了自己,应该是个递归函数disas func41
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25(gdb) disas func4
Dump of assembler code for function func4:
0x0000000000400fce <+0>: sub $0x8,%rsp
0x0000000000400fd2 <+4>: mov %edx,%eax
0x0000000000400fd4 <+6>: sub %esi,%eax
0x0000000000400fd6 <+8>: mov %eax,%ecx
0x0000000000400fd8 <+10>: shr $0x1f,%ecx
0x0000000000400fdb <+13>: add %ecx,%eax
0x0000000000400fdd <+15>: sar %eax
0x0000000000400fdf <+17>: lea (%rax,%rsi,1),%ecx
0x0000000000400fe2 <+20>: cmp %edi,%ecx
0x0000000000400fe4 <+22>: jle 0x400ff2 <func4+36>
0x0000000000400fe6 <+24>: lea -0x1(%rcx),%edx
0x0000000000400fe9 <+27>: callq 0x400fce <func4>
0x0000000000400fee <+32>: add %eax,%eax
0x0000000000400ff0 <+34>: jmp 0x401007 <func4+57>
0x0000000000400ff2 <+36>: mov $0x0,%eax
0x0000000000400ff7 <+41>: cmp %edi,%ecx
0x0000000000400ff9 <+43>: jge 0x401007 <func4+57>
0x0000000000400ffb <+45>: lea 0x1(%rcx),%esi
0x0000000000400ffe <+48>: callq 0x400fce <func4>
0x0000000000401003 <+53>: lea 0x1(%rax,%rax,1),%eax
0x0000000000401007 <+57>: add $0x8,%rsp
0x000000000040100b <+61>: retq
End of assembler dump.
1 | int func4(int a, int b, int c) |
因此phase_4破译可能结果为:
0 0
1 0
3 0
7 0
phase_5
1 | (gdb) disas phase_5 |
1 | (gdb) disas string_length |
这个可以说是phase_1的升版本了,注意到movzbl (%rbx,%rax,1),%ecx 复制输入字符串的第%rax个字符到%ecx中每次取该字符串的一个字符,然后比对,然后+1,并且由开始的代码可知.字符串是6字符1
2
3
4(gdb) x/s 0x4024b0
0x4024b0 <array.3449>: "maduiersnfotvbylSo you think you can stop the bomb with ctrl-c, do you?"
(gdb) x/s 0x40245e
0x40245e: "flyers"
phase_6
第6个好难啊 QAQ
1 | (gdb) disas phase_6 |