CSAPP Bomb Lab 达成
这是我第一个完成的 lab, 这篇博客其实是边做边记的解决过程改的, 所以比较简略, 其他 Lab 的记录博客会详细一点, 这篇博客以后有时间也会补充
Phase 0x1
Border relations with Canada have never been better.
根据调用约定, gdb 直接读 phase_1()
的 $rdi
即可.
Phase 0x2
1 2 4 8 16 32
利用断点跳到 read_six_number
后, 发现核心代码 add %eax %eax
, 即不断 \(\times 2\)
Phase 0x3
5 206
rsp+8
, rsp+12
分别是输入的两个数, int
占四字节.
发现一堆 mov
, jmp
, 里只有第五个的差能整除
\(8\) 并且 mov
过去的值是
206
(最后几行是核心代码 cmp 0xc(%rsp), %eax
)
Phase 0x4
7 0
打断点到 phase_4()
,
阅读汇编得大概逻辑:
- 输入两个数, 输入的第一个数 <= 14
%rdi
: 输入的第一个数%rsi
: \(0\)%rdx
: \(14\)- 调用
func4(x1, 0, 14, 0);
进入 func4() 继续阅读汇编, 顺便翻译一下(伪代码),
是个比较麻烦的递归函数: 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20func4(rdi, rsi, rdx, rcx):
rax = rdx - rsi
rcx = rax shr 31
rax += rcx
rax sar= 1
rcx = rax + rsi
// summary:
// rax = ((rdx - rsi) + (rdx - rsi) shr 31) sar 1
// rcx = ((rdx - rsi) + (rdx - rsi) shr 31) sar 1 + rsi
if (rdi <= rcx)
// 跳到ff2
if(rdi >= rcx)
return 0;
else
rax = func4(rdi, rsi = rcx + 1, rdx, rcx)
return (rax = 2 * rax + 1)
else
rax = fun4(rdi, rsi, rdx = rcx - 1, rcx)
return 2 * rax
优化后得: 1
2
3
4
5
6
7
8
9f (x1, $2, $3):
if x1 <= $2 + ($3 - $2)/2:
if x1 == $2 + ($3 - $2)/2: return 0
else: return 2 * f(x1, ($3 - $2)/2 + 1, $3) + 1
else:
return 2 * f(x1, $2, $2 + ($3 - $2)/2 - 1)
// 简单模拟一下看看
10 0 14
return 2 * f(10, 0, 6)
再后面的逻辑:
1 | if(func4(..) == 0 && ($rsp + 8) == 0) { |
然后发现其实令 \(x1 = \$2 + (\$3 - \$2) \div 2\) 即 \(0 + (14 - 2) \div 2 = 7\) 就行了
Phase 0x5
y_^EFG
字符串长度为 6
简单把汇编翻译一下伪代码:
1 | rbx = rdi(input) |
简单模拟一下:
1 | 11 |
1 | @: 0x4024b0 |
input[i]
ASCII 取后四位+ 0x4024b0
- 令一个字符c的ASCII的十六进制后四位分别为以上的
%rdx
64 位,%edx
32 位,$dl
8 位p /x $dl
输出0x61
, 这里十六进制的每一位都是四位二进制:6
是 \(4\) bit,1
也是 \(4\) bit, 十六进制最大 \(15_{16} = 1111_2\)- 所以只要ASCII 是
0x*9
,0x*f
,0x*e
,0x*5
,0x*6
,0x*7
的字符就可以了
这里随便选的 y_^EFG
Phase 0x6
1 | r13 = <+8>rsp (init - 50) |
这个难度有点大.
总之是先查6个数都<=6 且不能重复
然后将每个数 x 变为 7 - x
然后根据新的xi安排在0x6032d0处的一个链表, 安排完要求顺序值递减
查看一下这个链表:
1 | (gdb) x/24w 0x6032d0 |
递减的话就是 3 4 5 6 1 2
根据7映射回去就是
4 3 2 1 6 5
读入6个数字(%rsp
也变了)
以下伪代码, <>
用于标记行号,
这汇编写的链表可读性有点高啊
1 | r14 = <+23>rsp |