421 lines
18 KiB
Markdown
421 lines
18 KiB
Markdown
---
|
||
title: 高地特供版CSAPP Bomb Lab全流程攻略
|
||
date: 2025-02-24 15:09:11
|
||
tags: [技术, 学习, 生活]
|
||
---
|
||
|
||
这篇文章记录高地CSAPP课程Bomblab实验操作流程,仅供参考交流(答案是随机生成的和学号相关)。
|
||
|
||
笔者实验环境为Archlinux/CachyOS,使用lldb作为调试器(和gdb操作差不多),其余用到的工具主要为objdump,strings,neovim/helix和zellij,全程开源环境不使用IDA。
|
||
|
||
## **Phase_1**
|
||
|
||
### **静态分析**
|
||
|
||
#### **`strings`扫描**
|
||
```bash
|
||
strings bomb_linux
|
||
```
|
||
先用strings寻找可能与`phase_1`相关的字符串或函数名,运气好说不定能直接找到密码毕竟是第一题。
|
||

|
||
- 结果没有明文密码无法直接秒掉第一问,可惜。
|
||
- 但是找到`GenerateRandomString`函数可能与密码生成相关。
|
||
|
||
#### **用`objdump`反汇编**
|
||
```bash
|
||
objdump -d bomb_linux > bomb.asm
|
||
```
|
||
搜索`GenerateRandomString`和`phase_1`函数的汇编代码。
|
||
```assembly
|
||
401b53 <phase_1>:
|
||
401b53: endbr64
|
||
401b57: push %rbp
|
||
401b58: mov %rsp,%rbp
|
||
401b5b: sub $0x20,%rsp
|
||
401b5f: mov %rdi,-0x18(%rbp)
|
||
401b63: lea -0xb(%rbp),%rax
|
||
401b67: mov %rax,%rdi
|
||
401b6a: callq 401ac1 <GenerateRandomString> # 调用密码生成函数
|
||
401b6f: lea -0xb(%rbp),%rdx # 生成的字符串地址%rbp-0xb存入%rdx,即密码存储位置
|
||
401b73: mov -0x18(%rbp),%rax
|
||
401b77: mov %rdx,%rsi
|
||
401b7a: mov %rax,%rdi
|
||
401b7d: callq 401c0c <string_compare> # 调用字符串比较函数
|
||
401b82: test %eax,%eax
|
||
401b84: je 401b8d <phase_1+0x3a>
|
||
401b86: callq 401d67 <explode_bomb> # 比较失败则引爆炸弹
|
||
```
|
||
- `phase_1`调用`GenerateRandomString`生成一个字符串。
|
||
- 用户输入的字符串需要与此生成的字符串完全匹配。
|
||
|
||
---
|
||
|
||
### **动态调试**
|
||

|
||
下面是phase_1求解的完整流程:
|
||
```lldb
|
||
lldb bomb_linux <你的学号后六位>
|
||
(lldb) b phase_1 # 在phase_1入口断点
|
||
(lldb) run # 从入口开始执行
|
||
请输入第1级的密码:114514 # 随便输入触发断点
|
||
(lldb) b 0x401b6f # 在GenerateRandomString返回后断点
|
||
(lldb) continue # 继续执行
|
||
(lldb) x/s $rbp - 0xb # 计算字符串地址(-0xb偏移量)
|
||
0x7fffffffdaf5: "mJHurpQZtY" # 轻松拿下,这里是根据学号伪随机生成的哦
|
||
```
|
||
将得到的密码保存入bomb_<学号后六位>.txt即可,避免后续重复输入。
|
||
|
||
---
|
||
|
||
## **Phase_2**
|
||
|
||
### **静态分析**
|
||
|
||
这道题目还是比较一目了然的,观察`phase_2`代码不难发现其实构建了一张跳转表:
|
||
```assembly
|
||
0000000000401b8e <phase_2>:
|
||
401b8e: f3 0f 1e fa endbr64
|
||
401b92: 55 push %rbp
|
||
401b93: 48 89 e5 mov %rsp,%rbp
|
||
401b96: 48 83 ec 10 sub $0x10,%rsp
|
||
401b9a: 48 89 7d f8 mov %rdi,-0x8(%rbp)
|
||
401b9e: bf 10 00 00 00 mov $0x10,%edi
|
||
401ba3: e8 05 fb ff ff call 4016ad <GenerateRandomNumber>
|
||
401ba8: 48 8b 05 71 6c 00 00 mov 0x6c71(%rip),%rax # 408820 <rand_div>
|
||
401baf: 48 83 f8 0f cmp $0xf,%rax
|
||
401bb3: 0f 87 16 01 00 00 ja 401ccf <phase_2+0x141>
|
||
401bb9: 48 8d 14 85 00 00 00 lea 0x0(,%rax,4),%rdx
|
||
401bc0: 00
|
||
401bc1: 48 8d 05 4c 4a 00 00 lea 0x4a4c(%rip),%rax # 406614 <_IO_stdin_used+0x614>
|
||
401bc8: 8b 04 02 mov (%rdx,%rax,1),%eax
|
||
401bcb: 48 98 cltq
|
||
401bcd: 48 8d 15 40 4a 00 00 lea 0x4a40(%rip),%rdx # 406614 <_IO_stdin_used+0x614>
|
||
401bd4: 48 01 d0 add %rdx,%rax
|
||
401bd7: 3e ff e0 notrack jmp *%rax
|
||
401bda: 48 8b 45 f8 mov -0x8(%rbp),%rax
|
||
401bde: 48 89 c7 mov %rax,%rdi
|
||
401be1: e8 f2 00 00 00 call 401cd8 <phase_2_0>
|
||
401be6: e9 ea 00 00 00 jmp 401cd5 <phase_2+0x147>
|
||
401beb: 48 8b 45 f8 mov -0x8(%rbp),%rax
|
||
401bef: 48 89 c7 mov %rax,%rdi
|
||
401bf2: e8 8b 01 00 00 call 401d82 <phase_2_1>
|
||
401bf7: e9 d9 00 00 00 jmp 401cd5 <phase_2+0x147>
|
||
401bfc: 48 8b 45 f8 mov -0x8(%rbp),%rax
|
||
401c00: 48 89 c7 mov %rax,%rdi
|
||
...
|
||
```
|
||
这里面需要注意的关键点是rand_div,它会决定你的跳转方向,而你的学号又决定了它的取值。然后是`GenerateRandomNumber`这个函数的原理需要了解一下,而这个函数将在跳转前后分别调用一次,第一次决定你的跳转方向,第二次则决定了你的密码线索。
|
||
|
||
---
|
||
|
||
### **动态调试**
|
||
理解原理就没什么难度了,自己找几个断点打好然后关注一下`rand_div`的值就好,观察自己的学号向哪个函数跳转并理解相应函数计算即可,比如我这里向`phase_2_14`跳转:
|
||

|
||
|
||
而除了`phase_2_14`还有其他函数也是非常好理解的,第二题依旧可以轻松拿下。
|
||
|
||
---
|
||
## **Phase_3**
|
||
|
||
### **静态分析**
|
||
|
||
和Phase_2一样开局先跳转尽可能防止同学们答案雷同互相帮助(bushi
|
||
|
||
本体其实没有什么好说的,这里我跳转的方向是`Phase_3_5`简要解释一下可供参考:
|
||
|
||
```assembly
|
||
0000000000403001 <phase_3_5>:
|
||
403001: f3 0f 1e fa endbr64
|
||
403005: 55 push %rbp
|
||
403006: 48 89 e5 mov %rsp,%rbp
|
||
403009: 48 83 ec 20 sub $0x20,%rsp
|
||
40300d: 48 89 7d e8 mov %rdi,-0x18(%rbp)
|
||
403011: c7 45 fc 00 00 00 00 movl $0x0,-0x4(%rbp)
|
||
403018: c7 45 f8 00 00 00 00 movl $0x0,-0x8(%rbp)
|
||
40301f: 48 8d 4d f0 lea -0x10(%rbp),%rcx
|
||
403023: 48 8d 55 f4 lea -0xc(%rbp),%rdx
|
||
403027: 48 8b 45 e8 mov -0x18(%rbp),%rax
|
||
40302b: 48 8d 35 5a 36 00 00 lea 0x365a(%rip),%rsi # 40668c <_IO_stdin_used+0x68c>
|
||
403032: 48 89 c7 mov %rax,%rdi
|
||
403035: b8 00 00 00 00 mov $0x0,%eax
|
||
40303a: e8 51 e1 ff ff call 401190 <__isoc99_sscanf@plt>
|
||
40303f: 89 45 f8 mov %eax,-0x8(%rbp)
|
||
403042: 83 7d f8 01 cmpl $0x1,-0x8(%rbp)
|
||
403046: 7f 05 jg 40304d <phase_3_5+0x4c>
|
||
403048: e8 a9 2b 00 00 call 405bf6 <explode_bomb>
|
||
40304d: bf 08 00 00 00 mov $0x8,%edi
|
||
403052: e8 56 e6 ff ff call 4016ad <GenerateRandomNumber>
|
||
403057: 8b 45 f4 mov -0xc(%rbp),%eax
|
||
40305a: 48 63 d0 movslq %eax,%rdx
|
||
40305d: 48 8b 05 bc 57 00 00 mov 0x57bc(%rip),%rax # 408820 <rand_div>
|
||
403064: 48 39 c2 cmp %rax,%rdx
|
||
403067: 74 05 je 40306e <phase_3_5+0x6d>
|
||
403069: e8 88 2b 00 00 call 405bf6 <explode_bomb>
|
||
40306e: bf c8 00 00 00 mov $0xc8,%edi
|
||
403073: e8 35 e6 ff ff call 4016ad <GenerateRandomNumber>
|
||
403078: 8b 45 f4 mov -0xc(%rbp),%eax
|
||
40307b: 83 f8 07 cmp $0x7,%eax
|
||
40307e: 0f 87 eb 00 00 00 ja 40316f <phase_3_5+0x16e>
|
||
403084: 89 c0 mov %eax,%eax
|
||
403086: 48 8d 14 85 00 00 00 lea 0x0(,%rax,4),%rdx
|
||
40308d: 00
|
||
40308e: 48 8d 05 9f 36 00 00 lea 0x369f(%rip),%rax # 406734 <_IO_stdin_used+0x734>
|
||
403095: 8b 04 02 mov (%rdx,%rax,1),%eax
|
||
403098: 48 98 cltq
|
||
40309a: 48 8d 15 93 36 00 00 lea 0x3693(%rip),%rdx # 406734 <_IO_stdin_used+0x734>
|
||
4030a1: 48 01 d0 add %rdx,%rax
|
||
4030a4: 3e ff e0 notrack jmp *%rax
|
||
4030a7: 48 8b 05 72 57 00 00 mov 0x5772(%rip),%rax # 408820 <rand_div>
|
||
4030ae: 89 c2 mov %eax,%edx
|
||
4030b0: 8b 45 fc mov -0x4(%rbp),%eax
|
||
4030b3: 01 d0 add %edx,%eax
|
||
4030b5: 89 45 fc mov %eax,-0x4(%rbp)
|
||
4030b8: bf c8 00 00 00 mov $0xc8,%edi
|
||
4030bd: e8 eb e5 ff ff call 4016ad <GenerateRandomNumber>
|
||
...
|
||
403174: 8b 45 f0 mov -0x10(%rbp),%eax
|
||
403177: 39 45 fc cmp %eax,-0x4(%rbp) # 注意这里
|
||
40317a: 74 05 je 403181 <phase_3_5+0x180>
|
||
40317c: e8 75 2a 00 00 call 405bf6 <explode_bomb>
|
||
403181: 90 nop
|
||
403182: c9 leave
|
||
403183: c3 ret
|
||
|
||
```
|
||
看起来一大堆很吓人对不对?实际上确实很吓人。
|
||
|
||
但是发现其中玄机后其实简单的没边,最终答案就藏在`0x403177`里面,前提是确保这一步前炸弹不爆炸(意识到要爆炸了直接`run`一下重开qwq)。
|
||
|
||
---
|
||
|
||
### **动态调试**
|
||
|
||
阅读`Phase_3_5`发现这一关其实需要两个输入,并且第一个输入必须是`rand_div`,这里建议通过`si`单步执行监控好`rand_div`值变化,确定正确结果后使用`run`重开正确输入第一个密码后才能进行下一步求解:
|
||
```lldb
|
||
(lldb) si
|
||
Process 13376 stopped
|
||
* thread #1, name = 'bomb_linux', stop reason = instruction step into
|
||
frame #0: 0x000000000040317a bomb_linux`phase_3_5 + 377
|
||
bomb_linux`phase_3_5:
|
||
-> 0x40317a <+377>: je 0x403181 ; <+384>
|
||
0x40317c <+379>: callq 0x405bf6 ; explode_bomb
|
||
0x403181 <+384>: nop
|
||
0x403182 <+385>: leave
|
||
(lldb) x/wx $rbp-0x4
|
||
0x7fffffffdb0c: 0xffffffd7
|
||
```
|
||
例如这里我可以打印出第二个值结合第一个值得到第三关正确结果。
|
||
|
||
---
|
||
|
||
## **Phase_4**
|
||
|
||
### **静态分析**
|
||
|
||
本题依旧开局跳转,笔者的跳转方向是`phase_4_01`,如何跳转不再强调关注`rand_div`的值即可,下面请D指导解读一下`phase_4_01`的内容:
|
||
```assembly
|
||
0000000000404895 <phase_4_01>:
|
||
; 函数入口,初始化栈帧
|
||
404895: f3 0f 1e fa endbr64
|
||
404899: 55 push %rbp
|
||
40489a: 48 89 e5 mov %rsp,%rbp
|
||
40489d: 48 83 ec 70 sub $0x70,%rsp ; 分配栈空间
|
||
|
||
; 初始化斐波那契数组(F(10)~F(24)的十六进制值)
|
||
4048a1: 48 89 7d 98 mov %rdi,-0x68(%rbp) ; 保存输入字符串指针
|
||
4048a5: c7 45 b0 37 00 00 00 movl $0x37,-0x50(%rbp) ; F(10)=55
|
||
4048ac: c7 45 b4 59 00 00 00 movl $0x59,-0x4c(%rbp) ; F(11)=89
|
||
4048b3: c7 45 b8 90 00 00 00 movl $0x90,-0x48(%rbp) ; F(12)=144
|
||
4048ba: c7 45 bc e9 00 00 00 movl $0xe9,-0x44(%rbp) ; F(13)=233
|
||
4048c1: c7 45 c0 79 01 00 00 movl $0x179,-0x40(%rbp) ; F(14)=377
|
||
4048c8: c7 45 c4 62 02 00 00 movl $0x262,-0x3c(%rbp) ; F(15)=610
|
||
4048cf: c7 45 c8 db 03 00 00 movl $0x3db,-0x38(%rbp) ; F(16)=987
|
||
4048d6: c7 45 cc 3d 06 00 00 movl $0x63d,-0x34(%rbp) ; F(17)=1597
|
||
4048dd: c7 45 d0 18 0a 00 00 movl $0xa18,-0x30(%rbp) ; F(18)=2584
|
||
4048e4: c7 45 d4 55 10 00 00 movl $0x1055,-0x2c(%rbp) ; F(19)=4181
|
||
4048eb: c7 45 d8 6d 1a 00 00 movl $0x1a6d,-0x28(%rbp) ; F(20)=6765
|
||
4048f2: c7 45 dc c2 2a 00 00 movl $0x2ac2,-0x24(%rbp) ; F(21)=10946
|
||
4048f9: c7 45 e0 2f 45 00 00 movl $0x452f,-0x20(%rbp) ; F(22)=17711
|
||
404900: c7 45 e4 f1 6f 00 00 movl $0x6ff1,-0x1c(%rbp) ; F(23)=28657
|
||
404907: c7 45 e8 20 b5 00 00 movl $0xb520,-0x18(%rbp) ; F(24)=46368
|
||
|
||
; 读取输入到局部变量(格式为"%d")
|
||
40490e: 48 8d 55 ac lea -0x54(%rbp),%rdx ; 输入存储地址
|
||
404912: 48 8b 45 98 mov -0x68(%rbp),%rax ; 输入字符串
|
||
404916: 48 8d 0d 93 1f 00 00 lea 0x1f93(%rip),%rcx ; 格式字符串"%d"
|
||
40491d: 48 89 ce mov %rcx,%rsi
|
||
404920: 48 89 c7 mov %rax,%rdi
|
||
404923: b8 00 00 00 00 mov $0x0,%eax
|
||
404928: e8 63 c8 ff ff call 401190 <__isoc99_sscanf@plt>
|
||
|
||
; 验证输入有效性(必须为1个正数)
|
||
40492d: 89 45 fc mov %eax,-0x4(%rbp) ; sscanf返回值
|
||
404930: 83 7d fc 01 cmpl $0x1,-0x4(%rbp) ; 检查是否读取1个参数
|
||
404934: 75 07 jne 40493d <phase_4_01+0xa8> ; 失败则爆炸
|
||
404936: 8b 45 ac mov -0x54(%rbp),%eax ; 获取输入值N
|
||
404939: 85 c0 test %eax,%eax ; 检查N > 0
|
||
40493b: 7f 05 jg 404942 <phase_4_01+0xad>
|
||
40493d: e8 b4 12 00 00 call 405bf6 <explode_bomb>
|
||
|
||
; 检查输入值上限(必须 > 1999)
|
||
404942: 8b 45 ac mov -0x54(%rbp),%eax
|
||
404945: 3d cf 07 00 00 cmp $0x7cf,%eax ; 1999的十六进制
|
||
40494a: 7f 05 jg 404951 <phase_4_01+0xbc> ; N > 1999?
|
||
40494c: e8 a5 12 00 00 call 405bf6 <explode_bomb>
|
||
|
||
; 计算 N/2000(通过定点数乘法优化)
|
||
404951: 8b 45 ac mov -0x54(%rbp),%eax ; 输入值N
|
||
404954: 48 63 d0 movslq %eax,%rdx ; 符号扩展
|
||
404957: 48 69 d2 d3 4d 62 10 imul $0x10624dd3,%rdx,%rdx ; 乘以274877907(≈2^32/2000)
|
||
40495e: 48 c1 ea 20 shr $0x20,%rdx ; 取高32位
|
||
404962: c1 fa 07 sar $0x7,%edx ; 算术右移7位 → N/2000
|
||
404965: c1 f8 1f sar $0x1f,%eax ; 符号位扩展
|
||
404968: 89 c1 mov %eax,%ecx
|
||
40496a: 89 d0 mov %edx,%eax
|
||
40496c: 29 c8 sub %ecx,%eax ; 处理负数情况
|
||
40496e: 89 45 ac mov %eax,-0x54(%rbp) ; 保存k = N/2000
|
||
|
||
; 调用递归函数func4_0(k), 这个函数用于计算斐波那契数列
|
||
404971: 8b 45 ac mov -0x54(%rbp),%eax
|
||
404974: 89 c7 mov %eax,%edi ; 参数k
|
||
404976: e8 ce fd ff ff call 404749 <func4_0> ; 返回值eax=F(k+1)
|
||
40497b: 89 45 f8 mov %eax,-0x8(%rbp) ; 保存结果
|
||
|
||
; 生成随机索引并验证结果
|
||
40497e: bf 0f 00 00 00 mov $0xf,%edi ; 参数15
|
||
404983: e8 25 cd ff ff call 4016ad <GenerateRandomNumber> ; 生成0~14随机数
|
||
404988: 48 8b 05 91 3e 00 00 mov 0x3e91(%rip),%rax # 408820 <rand_div> ; 获取随机索引
|
||
40498f: 8b 44 85 b0 mov -0x50(%rbp,%rax,4),%eax ; 取数组[rand_div]的值
|
||
404993: 39 45 f8 cmp %eax,-0x8(%rbp) ; 比较func4_0(k) == 数组值?
|
||
404996: 74 05 je 40499d <phase_4_01+0x108>
|
||
404998: e8 59 12 00 00 call 405bf6 <explode_bomb>
|
||
```
|
||
所以相对还是很明了的,依旧是关注`rand_div`。
|
||
|
||
### **动态调试**
|
||
先找出`rand_div`在最后判断前的取值,比如我下面的0xa:
|
||
|
||
```lldb
|
||
(lldb) si
|
||
Process 27027 stopped
|
||
* thread #1, name = 'bomb_linux', stop reason = instruction step into
|
||
frame #0: 0x0000000000401719 bomb_linux`GenerateRandomNumber + 108
|
||
bomb_linux`GenerateRandomNumber:
|
||
-> 0x401719 <+108>: movq %rax, 0x7100(%rip) ; rand_div
|
||
0x401720 <+115>: jmp 0x401723 ; <+118>
|
||
0x401722 <+117>: nop
|
||
0x401723 <+118>: popq %rbp
|
||
(lldb) si
|
||
Process 27027 stopped
|
||
* thread #1, name = 'bomb_linux', stop reason = instruction step into
|
||
frame #0: 0x0000000000401720 bomb_linux`GenerateRandomNumber + 115
|
||
bomb_linux`GenerateRandomNumber:
|
||
-> 0x401720 <+115>: jmp 0x401723 ; <+118>
|
||
0x401722 <+117>: nop
|
||
0x401723 <+118>: popq %rbp
|
||
0x401724 <+119>: retq
|
||
(lldb) x/gx &rand_div
|
||
0x00408820: 0x000000000000000a
|
||
```
|
||
|
||
而当 `rand_div = 0xa`(即十进制 **10**)时,输入值 `N` 的计算步骤如下:
|
||
|
||
- 数组索引 **10** 的值是 **斐波那契数列第 20 项**(`F(20) = 6765`)。
|
||
|
||
- `func4_0(k)` 实际计算的是 **标准斐波那契数列的第 `k+1` 项**(例如,`func4_0(0) = 1 = F(2)`) 需要满足:
|
||
```c
|
||
func4_0(k) = F(k+1) = F(20)
|
||
```
|
||
解得:
|
||
k + 1 = 20 → k = 19
|
||
- `k = N / 2000` → `N = 2000 * k = 2000 * 19 = 38000`.
|
||
从而得解。
|
||

|
||
|
||
---
|
||
|
||
## **Phase_Impossible**
|
||
|
||
Impossible?
|
||
|
||
从这道题开始偷懒了,掏出ghidra直接看c代码了解一下大概流程再去objdump看汇编:
|
||
```c
|
||
void phase_impossible(char *param_1)
|
||
|
||
{
|
||
int iVar1;
|
||
size_t sVar2;
|
||
undefined local_118 [256];
|
||
long local_18;
|
||
long local_10;
|
||
|
||
local_10 = GetTickCount();
|
||
sVar2 = strlen(param_1);
|
||
if ((sVar2 < 10) || (sVar2 = strlen(param_1), 0x300 < sVar2)) {
|
||
explode_bomb();
|
||
}
|
||
memset(local_118,0,0x100);
|
||
tohex(local_118,param_1);
|
||
GenerateRandomNumber(0x400);
|
||
iVar1 = check_buf_valid(local_118,rand_div & 0xffffffff);
|
||
if (iVar1 == 0) {
|
||
puts(&DAT_00406518);
|
||
explode_bomb();
|
||
}
|
||
GenerateRandomNumber(3);
|
||
if (rand_div != 2) {
|
||
if (2 < rand_div) goto LAB_00401891;
|
||
if (rand_div == 0) {
|
||
goto_buf_0(local_118);
|
||
}
|
||
else if (rand_div != 1) goto LAB_00401891;
|
||
goto_buf_1(local_118);
|
||
}
|
||
goto_buf_2(local_118);
|
||
LAB_00401891:
|
||
explode_bomb();
|
||
GenerateRandomNumber(0x400);
|
||
if ((long)(int)result != rand_div) {
|
||
printf(&DAT_00406560,rand_div,(ulong)result);
|
||
explode_bomb();
|
||
}
|
||
local_18 = GetTickCount();
|
||
if (1000 < (ulong)(local_18 - local_10)) {
|
||
puts(&DAT_004065a8);
|
||
explode_bomb();
|
||
}
|
||
return;
|
||
}
|
||
```
|
||
最终任务还是很明确的,需要写一段机器码修改`result`的数值,但是注意要能通过`check_buf_valid`检测,并且最后指令必须是跳转到`0x401896`不然就会触发`phase_impossible`中`0x401891`处的`explode_bomb`函数,唯一的难点是跟踪`rand_div`的数值变化,建议使用`register write`来修改`check_buf_valid`的返回值使其强制通过然后监控`rand_div`每一次的数值变化(`x/gx &rand_div`),记录好`rand_div`的结果后开始指令设计,需要满足:
|
||
|
||
- 指令的异或和为`rand_div`第一次的数值末尾八位以通过检查;
|
||
- 修改`result`使其数值等于`rand_div`第三次数值;
|
||
- 跳转到`0x401896`避免炸弹;
|
||
|
||
如果前几问都完成了到这里应该是没有问题的。
|
||
|
||
---
|
||
|
||
## **Phase_Secret**
|
||
|
||
隐藏彩蛋,并非隐藏。汇编里写的非常清楚:
|
||
```assembly
|
||
0000000000401a8b <phase_secret>:
|
||
401a8b: f3 0f 1e fa endbr64
|
||
401a8f: 55 push %rbp
|
||
401a90: 48 89 e5 mov %rsp,%rbp
|
||
401a93: 48 83 ec 10 sub $0x10,%rsp
|
||
401a97: 48 89 7d f8 mov %rdi,-0x8(%rbp)
|
||
401a9b: 48 8d 05 26 4b 00 00 lea 0x4b26(%rip),%rax # 4065c8 <_IO_stdin_used+0x5c8>
|
||
401aa2: 48 89 c7 mov %rax,%rdi
|
||
401aa5: e8 76 f6 ff ff call 401120 <puts@plt>
|
||
401aaa: 90 nop
|
||
401aab: c9 leave
|
||
401aac: c3 ret
|
||
```
|
||
注意到这段指令在原程序中完全没有执行说明是需要用户自己跳转的,也非常简单只需要在`phase_5`中设计指令时加一个要求跳转到`0x401a8b`即可。
|
||
|
||
完结
|
||

|