# Bomb lab 紀錄
contributed by < `justapig9020` >
###### tags: `CSAPP`
## Link
[bomb lab](http://csapp.cs.cmu.edu/3e/labs.html)
## Lab 說明
題目給予一支已編譯好的 binary 檔案 `bomb` ,`bomb` 總共有 6 個關卡,每個階段會從 stdin 讀取一個字串,若輸入的字串正確,則成功解除該關卡,否則炸彈引爆。
## Lab 實做
### 工具
在實做 lab 時,使用到的工具有:
- objdump: 用以反組譯 `bomb`
- gdb: 用以觀察 `bomb` 的行為,以及阻止其爆炸
- [peda](https://github.com/longld/peda): 更棒的 gdb 使用者體驗
- [pwntools](https://docs.pwntools.com/en/stable/): 用以實做腳本,執行 `bomb` 並餵入字串
===============防雷頁===============
===============防雷頁===============
===============防雷頁===============
===============防雷頁===============
===============防雷頁===============
===============防雷頁===============
===============防雷頁===============
===============防雷頁===============
### 解答
#### text
```
Border relations with Canada have never been better.
1 2 4 8 16 32
1 311
7 0
IONEFG
4 3 2 1 6 5
```
#### pwntools
```python3
from pwn import *
p = process("./bomb")
sol = open("./psol.txt", "w+")
def recv_msg():
msg = p.recv().decode("ascii")
print(msg)
def str_to_bytes(s):
return bytes(s, "ascii")
def phase_1():
# phase_1_cmp_addr = 0x402400
payload = "Border relations with Canada have never been better."
p.sendline(str_to_bytes(payload))
sol.write(payload)
sol.write('\n')
def phase_2():
args = []
val = 1
for i in range(6):
args.append(val)
val *= 2
payload = ' '.join(str(n) for n in args)
p.sendline(str_to_bytes(payload))
sol.write(payload)
sol.write('\n')
def phase_3():
"""
0x402470: 0x0000000000400f7c 0x0000000000400fb9
0x402480: 0x0000000000400f83 0x0000000000400f8a
0x402490: 0x0000000000400f91 0x0000000000400f98
0x4024a0: 0x0000000000400f9f 0x0000000000400fa6
"""
a = 1
b = 0x137
payload = str(a) + ' ' + str(b)
p.sendline(str_to_bytes(payload))
sol.write(payload)
sol.write('\n')
def phase_4():
a = 7
b = 0
payload = str(a) + ' ' + str(b)
p.sendline(str_to_bytes(payload))
sol.write(payload)
sol.write('\n')
def phase_5():
"""
6d616475696572736e666f747662796c
"""
data = "maduiersnfotvbyl"
key = "flyers"
args = []
for i in key:
n = data.find(i)
args.append(n)
payload = ''.join(chr(n + ord('@')) for n in args)
print(payload)
p.sendline(str_to_bytes(payload))
sol.write(payload)
sol.write('\n')
def phase_6():
"""
0x6032d0 <node1>: 0x000000010000014c 0x00000000006032e0
0x6032e0 <node2>: 0x00000002000000a8 0x00000000006032f0
0x6032f0 <node3>: 0x000000030000039c 0x0000000000603300
0x603300 <node4>: 0x00000004000002b3 0x0000000000603310
0x603310 <node5>: 0x00000005000001dd 0x0000000000603320
"""
values = [0x0000014c, 0x000000a8, 0x0000039c, 0x000002b3, 0x000001dd, 0x000001bb]
tuples = []
for i in range(len(values)):
tuples.append((i + 1, values[i]))
tuples.sort(key = lambda tup: tup[1])
args = []
for tup in tuples:
args.append(7 - tup[0])
args.reverse()
payload = ' '.join(str(n) for n in args)
p.sendline(str_to_bytes(payload))
sol.write(payload)
sol.write('\n')
recv_msg()
phase_1()
recv_msg()
phase_2()
recv_msg()
phase_3()
recv_msg()
phase_4()
recv_msg()
phase_5()
recv_msg()
phase_6()
recv_msg()
sol.close()
```
### 炸彈引爆
```shell
$ ./bomb
Welcome to my fiendish little bomb. You have 6 phases with
which to blow yourself up. Have a nice day!
a
BOOM!!!
The bomb has blown up.
```
當輸入錯誤字串時,炸彈便會被引爆。在實際課程中,每當炸彈引爆,都會被扣分。因此,首先要避免在答錯時引爆炸彈。
在 `bomb` 中,炸彈引爆的函數為:
```asm
000000000040143a <explode_bomb>:
40143a: 48 83 ec 08 sub rsp,0x8
40143e: bf a3 25 40 00 mov edi,0x4025a3
401443: e8 c8 f6 ff ff call 400b10 <puts@plt>
401448: bf ac 25 40 00 mov edi,0x4025ac
40144d: e8 be f6 ff ff call 400b10 <puts@plt>
401452: bf 08 00 00 00 mov edi,0x8
401457: e8 c4 f7 ff ff call 400c20 <exit@plt>
```
因此,在開始執行前,透過 gdb 在 `explode_bomb` 下中斷點即可防止炸彈引爆。一旦進入 `explode_bomb` 並出發中斷點,馬上透過 kill 指令中止 process 即可。
使用 gdb 的方法為:
1. 執行 `bomb` 後透過 `ps -a` 指令來獲得其 pid
```shell
$ ps -a
PID TTY TIME CMD
14815 pts/1 00:00:00 bomb
14819 pts/0 00:00:00 ps
```
2. 在 gdb 中使用 attach $pid 指令 attach 上 bomb 的 process
```gdb
gdb-peda$ attach 14815
Attaching to process 14815
```
### phase_1
```asm
0000000000400ee0 <phase_1>:
400ee0: 48 83 ec 08 sub rsp,0x8
400ee4: be 00 24 40 00 mov esi,0x402400
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 rsp,0x8
400efb: c3 ret
```
觀察組合語言可以輕易的發現, `phase_1` 是將輸入的字串與位在 0x402400 的字串比對。
透過 gdb 可以找出該位址的字串為:
```gdb
gdb-peda$ x/s 0x402400
0x402400: "Border relations with Canada have never been better."
```
因此只要輸入該字串即可通過 `phase_1`
phase_1 完整的邏輯如下:
```c=
void phase_1(char *input) {
const char *password = "Border relations with Canada have never been better.";
if (strings_not_equal(input, password))
explode_bomb();
}
```
### phase_2
```asm
0000000000400efc <phase_2>:
400efc: 55 push rbp
400efd: 53 push rbx
400efe: 48 83 ec 28 sub rsp,0x28
400f02: 48 89 e6 mov rsi,rsp
400f05: e8 52 05 00 00 call 40145c <read_six_numbers>
400f0a: 83 3c 24 01 cmp DWORD PTR [rsp],0x1
400f0e: 74 20 je 400f30 <phase_2+0x34>
400f10: e8 25 05 00 00 call 40143a <explode_bomb>
400f15: eb 19 jmp 400f30 <phase_2+0x34>
400f17: 8b 43 fc mov eax,DWORD PTR [rbx-0x4]
400f1a: 01 c0 add eax,eax
400f1c: 39 03 cmp DWORD PTR [rbx],eax
400f1e: 74 05 je 400f25 <phase_2+0x29>
400f20: e8 15 05 00 00 call 40143a <explode_bomb>
400f25: 48 83 c3 04 add rbx,0x4
400f29: 48 39 eb cmp rbx,rbp
400f2c: 75 e9 jne 400f17 <phase_2+0x1b>
400f2e: eb 0c jmp 400f3c <phase_2+0x40>
400f30: 48 8d 5c 24 04 lea rbx,[rsp+0x4]
400f35: 48 8d 6c 24 18 lea rbp,[rsp+0x18]
400f3a: eb db jmp 400f17 <phase_2+0x1b>
400f3c: 48 83 c4 28 add rsp,0x28
400f40: 5b pop rbx
400f41: 5d pop rbp
400f42: c3 ret
```
#### 有註解的版本
```asm
// rdi => read_line
0000000000400efc <phase_2>:
400efc: 55 push rbp
400efd: 53 push rbx
400efe: 48 83 ec 28 sub rsp,0x28
400f02: 48 89 e6 mov rsi,rsp # void *buf = rsp
// Read 6 integers into rsp[0 - 5], rsp as a integer buffer.
400f05: e8 52 05 00 00 call 40145c <read_six_numbers>
400f0a: 83 3c 24 01 cmp DWORD PTR [rsp],0x1 // rsp[0] == 1
400f0e: 74 20 je 400f30 <phase_2+0x34>
400f10: e8 25 05 00 00 call 40143a <explode_bomb>
400f15: eb 19 jmp 400f30 <phase_2+0x34>
// A loop start
/*
rbx = &buf[1]
rbp = &buf[6]
while (rbx != rbp):
if rbx[0] != (rbx[-1] * 2):
explode_bomb()
rbx += 1
*/
400f17: 8b 43 fc mov eax,DWORD PTR [rbx-0x4] // eax = rbx[-1]
400f1a: 01 c0 add eax,eax // eax *= 2
400f1c: 39 03 cmp DWORD PTR [rbx],eax // rbx[0] == rbx[-1] * 2
/*
* if rbx[0] != (rbx[-1] * 2):
* explode_bomb()
*/
400f1e: 74 05 je 400f25 <phase_2+0x29>
400f20: e8 15 05 00 00 call 40143a <explode_bomb>
400f25: 48 83 c3 04 add rbx,0x4 // rbx += 1
400f29: 48 39 eb cmp rbx,rbp
// if rbx != rbp, keep looping
400f2c: 75 e9 jne 400f17 <phase_2+0x1b>
// Exit loop, defuse phase_2
400f2e: eb 0c jmp 400f3c <phase_2+0x40>
400f30: 48 8d 5c 24 04 lea rbx,[rsp+0x4] // rbx = &rsp[1]
400f35: 48 8d 6c 24 18 lea rbp,[rsp+0x18] // rbp = &rsp[6](another variable outside the buffer)
// Goto a loop
400f3a: eb db jmp 400f17 <phase_2+0x1b>
400f3c: 48 83 c4 28 add rsp,0x28
400f40: 5b pop rbx
400f41: 5d pop rbp
400f42: c3 ret
```
在 phase_2 中,首先會將輸入字串解析成六個數字,並依序存放在 rsp[0] ~ rsp[5] 中。
解析完後的邏輯如下:
```c=
if (rsp[0] != 1)
explode_bomb();
for (int i=1; i<6; i++) {
if ((rsp[i-1] * 2) != rsp[i])
explode_bomb();
```
因此只要輸入的第一個數字為 1 ,且之後每個數字皆為前一位的兩倍即可。
答案為:
`1 2 4 8 16 32`
phase_2 完整的邏輯如下:
```c=
void phase_2(char *input) {
int buf[6];
read_six_numbers(input, buf);
if (1 != buf[0])
explode_bomb();
for (int i=1; i<6; i++)
if ((buf[i-1] * 2) != buf[i])
explode_bomb();
}
```
### phase_3
```asm
0000000000400f43 <phase_3>:
400f43: 48 83 ec 18 sub rsp,0x18
400f47: 48 8d 4c 24 0c lea rcx,[rsp+0xc]
400f4c: 48 8d 54 24 08 lea rdx,[rsp+0x8]
400f51: be cf 25 40 00 mov esi,0x4025cf
400f56: b8 00 00 00 00 mov eax,0x0
400f5b: e8 90 fc ff ff call 400bf0 <__isoc99_sscanf@plt>
400f60: 83 f8 01 cmp eax,0x1
400f63: 7f 05 jg 400f6a <phase_3+0x27>
400f65: e8 d0 04 00 00 call 40143a <explode_bomb>
400f6a: 83 7c 24 08 07 cmp DWORD PTR [rsp+0x8],0x7
400f6f: 77 3c ja 400fad <phase_3+0x6a>
400f71: 8b 44 24 08 mov eax,DWORD PTR [rsp+0x8]
400f75: ff 24 c5 70 24 40 00 jmp QWORD PTR [rax*8+0x402470]
400f7c: b8 cf 00 00 00 mov eax,0xcf
400f81: eb 3b jmp 400fbe <phase_3+0x7b>
400f83: b8 c3 02 00 00 mov eax,0x2c3
400f88: eb 34 jmp 400fbe <phase_3+0x7b>
400f8a: b8 00 01 00 00 mov eax,0x100
400f8f: eb 2d jmp 400fbe <phase_3+0x7b>
400f91: b8 85 01 00 00 mov eax,0x185
400f96: eb 26 jmp 400fbe <phase_3+0x7b>
400f98: b8 ce 00 00 00 mov eax,0xce
400f9d: eb 1f jmp 400fbe <phase_3+0x7b>
400f9f: b8 aa 02 00 00 mov eax,0x2aa
400fa4: eb 18 jmp 400fbe <phase_3+0x7b>
400fa6: b8 47 01 00 00 mov eax,0x147
400fab: eb 11 jmp 400fbe <phase_3+0x7b>
400fad: e8 88 04 00 00 call 40143a <explode_bomb>
400fb2: b8 00 00 00 00 mov eax,0x0
400fb7: eb 05 jmp 400fbe <phase_3+0x7b>
400fb9: b8 37 01 00 00 mov eax,0x137
400fbe: 3b 44 24 0c cmp eax,DWORD PTR [rsp+0xc]
400fc2: 74 05 je 400fc9 <phase_3+0x86>
400fc4: e8 71 04 00 00 call 40143a <explode_bomb>
400fc9: 48 83 c4 18 add rsp,0x18
400fcd: c3 ret
```
#### 有註解的版本
```asm
0000000000400f43 <phase_3>:
400f43: 48 83 ec 18 sub rsp,0x18
400f47: 48 8d 4c 24 0c lea rcx,[rsp+0xc]
400f4c: 48 8d 54 24 08 lea rdx,[rsp+0x8]
400f51: be cf 25 40 00 mov esi,0x4025cf // %d %d
400f56: b8 00 00 00 00 mov eax,0x0
// int a @ rsp + 0x8
// int b @ rsp + 0xc
// sscanf(str, "%d %d", &a, &b)
400f5b: e8 90 fc ff ff call 400bf0 <__isoc99_sscanf@plt>
400f60: 83 f8 01 cmp eax,0x1
400f63: 7f 05 jg 400f6a <phase_3+0x27>
400f65: e8 d0 04 00 00 call 40143a <explode_bomb>
// if a > 7:
// explode_bomb()
400f6a: 83 7c 24 08 07 cmp DWORD PTR [rsp+0x8],0x7
400f6f: 77 3c ja 400fad <phase_3+0x6a>
400f71: 8b 44 24 08 mov eax,DWORD PTR [rsp+0x8] // eax = a
400f75: ff 24 c5 70 24 40 00 jmp QWORD PTR [rax*8+0x402470]
400f7c: b8 cf 00 00 00 mov eax,0xcf
400f81: eb 3b jmp 400fbe <phase_3+0x7b>
400f83: b8 c3 02 00 00 mov eax,0x2c3
400f88: eb 34 jmp 400fbe <phase_3+0x7b>
400f8a: b8 00 01 00 00 mov eax,0x100
400f8f: eb 2d jmp 400fbe <phase_3+0x7b>
400f91: b8 85 01 00 00 mov eax,0x185
400f96: eb 26 jmp 400fbe <phase_3+0x7b>
400f98: b8 ce 00 00 00 mov eax,0xce
400f9d: eb 1f jmp 400fbe <phase_3+0x7b>
400f9f: b8 aa 02 00 00 mov eax,0x2aa
400fa4: eb 18 jmp 400fbe <phase_3+0x7b>
400fa6: b8 47 01 00 00 mov eax,0x147
400fab: eb 11 jmp 400fbe <phase_3+0x7b>
400fad: e8 88 04 00 00 call 40143a <explode_bomb>
400fb2: b8 00 00 00 00 mov eax,0x0
400fb7: eb 05 jmp 400fbe <phase_3+0x7b>
400fb9: b8 37 01 00 00 mov eax,0x137 // 1
// if eax != b:
// explode_bomb()
400fbe: 3b 44 24 0c cmp eax,DWORD PTR [rsp+0xc] // eax == b
400fc2: 74 05 je 400fc9 <phase_3+0x86>
400fc4: e8 71 04 00 00 call 40143a <explode_bomb>
400fc9: 48 83 c4 18 add rsp,0x18
400fcd: c3 ret
```
首先,透過 sscanf 將輸入字串解析成兩個 int ,分別存放至 rsp + 0x8 , rsp + 0xc 。分別令兩 int 為 `a` , `b` 。
接著,檢查 `a` 是否大於 7 ,若大於則引爆炸彈。這邊需要注意的是 `ga` 這個指令比較時是將兩數視為 `unsigned` ,因此,比較後 $0\le$ `a` $\le 7$ 。
接著在 0x400f71 , 0x400f75 的指令,首先將 `a` 載入至 `eax` ,並將 `eax` 作為位址的 offset 來執行 `jmp` 。
透過 gdb 檢視 jump table 的 base address `0x402470` 。
```gdb
gdb-peda$ x/8gx 0x402470
0x402470: 0x0000000000400f7c 0x0000000000400fb9
0x402480: 0x0000000000400f83 0x0000000000400f8a
0x402490: 0x0000000000400f91 0x0000000000400f98
0x4024a0: 0x0000000000400f9f 0x0000000000400fa6
```
可以發現與 `phase_2` 中的這段指令位址具有對應關係
```asm
400f7c: b8 cf 00 00 00 mov eax,0xcf
400f81: eb 3b jmp 400fbe <phase_3+0x7b>
400f83: b8 c3 02 00 00 mov eax,0x2c3
400f88: eb 34 jmp 400fbe <phase_3+0x7b>
400f8a: b8 00 01 00 00 mov eax,0x100
400f8f: eb 2d jmp 400fbe <phase_3+0x7b>
400f91: b8 85 01 00 00 mov eax,0x185
400f96: eb 26 jmp 400fbe <phase_3+0x7b>
400f98: b8 ce 00 00 00 mov eax,0xce
400f9d: eb 1f jmp 400fbe <phase_3+0x7b>
400f9f: b8 aa 02 00 00 mov eax,0x2aa
400fa4: eb 18 jmp 400fbe <phase_3+0x7b>
400fa6: b8 47 01 00 00 mov eax,0x147
400fab: eb 11 jmp 400fbe <phase_3+0x7b>
400fad: e8 88 04 00 00 call 40143a <explode_bomb>
400fb2: b8 00 00 00 00 mov eax,0x0
400fb7: eb 05 jmp 400fbe <phase_3+0x7b>
400fb9: b8 37 01 00 00 mov eax,0x137
```
因此,實際上邏輯為(為省空間以及有助閱讀, switch 中省略 `break`):
```c=
int eax = a;
switch(eax) {
case 0:
eax = 0xcf;
case 1:
eax = 0x137;
case 2:
eax = 0x2c3;
case 3:
eax = 0x100;
case 4:
eax = 0x185;
case 5:
eax = 0xce;
case 6:
eax = 0x2aa;
case 7:
eax = 0x147;
default:
explode_bomb()
}
```
接著,比較 eax 與 `b` ,若不相等則引爆炸彈。
因此,只須任意選定 `a` ,並輸入對應的 `b` 即可。
參考答案:
`1 311`
phase_3 完整的邏輯如下:
```c=
void phase_3(char *input) {
int a, b;
sprintf(input, "%d %d", &a, &b);
int eax = a;
switch(eax) {
case 0:
eax = 0xcf;
break;
case 1:
eax = 0x137;
break;
case 2:
eax = 0x2c3;
break;
case 3:
eax = 0x100;
break;
case 4:
eax = 0x185;
break;
case 5:
eax = 0xce;
break;
case 6:
eax = 0x2aa;
break;
case 7:
eax = 0x147;
break;
default:
explode_bomb();
}
if (eax != b)
explode_bomb();
}
```
### phase_4
```asm
0000000000400fce <func4>:
400fce: 48 83 ec 08 sub rsp,0x8
400fd2: 89 d0 mov eax,edx
400fd4: 29 f0 sub eax,esi
400fd6: 89 c1 mov ecx,eax
400fd8: c1 e9 1f shr ecx,0x1f
400fdb: 01 c8 add eax,ecx
400fdd: d1 f8 sar eax,1
400fdf: 8d 0c 30 lea ecx,[rax+rsi*1]
400fe2: 39 f9 cmp ecx,edi
400fe4: 7e 0c jle 400ff2 <func4+0x24>
400fe6: 8d 51 ff lea edx,[rcx-0x1]
400fe9: e8 e0 ff ff ff call 400fce <func4>
400fee: 01 c0 add eax,eax
400ff0: eb 15 jmp 401007 <func4+0x39>
400ff2: b8 00 00 00 00 mov eax,0x0
400ff7: 39 f9 cmp ecx,edi
400ff9: 7d 0c jge 401007 <func4+0x39>
400ffb: 8d 71 01 lea esi,[rcx+0x1]
400ffe: e8 cb ff ff ff call 400fce <func4>
401003: 8d 44 00 01 lea eax,[rax+rax*1+0x1]
401007: 48 83 c4 08 add rsp,0x8
40100b: c3 ret
000000000040100c <phase_4>:
40100c: 48 83 ec 18 sub rsp,0x18
401010: 48 8d 4c 24 0c lea rcx,[rsp+0xc]
401015: 48 8d 54 24 08 lea rdx,[rsp+0x8]
40101a: be cf 25 40 00 mov esi,0x4025cf
40101f: b8 00 00 00 00 mov eax,0x0
401024: e8 c7 fb ff ff call 400bf0 <__isoc99_sscanf@plt>
401029: 83 f8 02 cmp eax,0x2
40102c: 75 07 jne 401035 <phase_4+0x29>
40102e: 83 7c 24 08 0e cmp DWORD PTR [rsp+0x8],0xe
401033: 76 05 jbe 40103a <phase_4+0x2e>
401035: e8 00 04 00 00 call 40143a <explode_bomb>
40103a: ba 0e 00 00 00 mov edx,0xe
40103f: be 00 00 00 00 mov esi,0x0
401044: 8b 7c 24 08 mov edi,DWORD PTR [rsp+0x8]
401048: e8 81 ff ff ff call 400fce <func4>
40104d: 85 c0 test eax,eax
40104f: 75 07 jne 401058 <phase_4+0x4c>
401051: 83 7c 24 0c 00 cmp DWORD PTR [rsp+0xc],0x0
401056: 74 05 je 40105d <phase_4+0x51>
401058: e8 dd 03 00 00 call 40143a <explode_bomb>
40105d: 48 83 c4 18 add rsp,0x18
401061: c3 ret
```
#### 有註解的版本
```asm
0000000000400fce <func4>:
/*
func4(a, rsi, rdx):
buf = edx - esi // e
tmp = a >>> 0x1f // 16 + 15 = 31
buf += tmp // e + 0 = e
buf >>= 1 // e >> 1 = 7
n = buf + rsi // buf + 0 = 7
// n == a -> return 0
if n <= a :
if n >= a:
return 0
ret = func(a, n + 1, rdx);
ret = ret * 2 + 1
else:
ret = func4(a, rsi, n - 1)
ret *= 2
return ret
*/
400fce: 48 83 ec 08 sub rsp,0x8
400fd2: 89 d0 mov eax,edx // eax = edx
400fd4: 29 f0 sub eax,esi // eax -= esi
400fd6: 89 c1 mov ecx,eax // ecx = eax
400fd8: c1 e9 1f shr ecx,0x1f // ecx >>>= 0x1f
400fdb: 01 c8 add eax,ecx // eax += ecx
400fdd: d1 f8 sar eax,1 // eax >>= 1
400fdf: 8d 0c 30 lea ecx,[rax+rsi*1]
400fe2: 39 f9 cmp ecx,edi
400fe4: 7e 0c jle 400ff2 <func4+0x24>
400fe6: 8d 51 ff lea edx,[rcx-0x1]
400fe9: e8 e0 ff ff ff call 400fce <func4>
400fee: 01 c0 add eax,eax
400ff0: eb 15 jmp 401007 <func4+0x39> // end func
400ff2: b8 00 00 00 00 mov eax,0x0
400ff7: 39 f9 cmp ecx,edi
400ff9: 7d 0c jge 401007 <func4+0x39> // end func
400ffb: 8d 71 01 lea esi,[rcx+0x1]
400ffe: e8 cb ff ff ff call 400fce <func4>
401003: 8d 44 00 01 lea eax,[rax+rax*1+0x1]
401007: 48 83 c4 08 add rsp,0x8
40100b: c3 ret
000000000040100c <phase_4>:
40100c: 48 83 ec 18 sub rsp,0x18
401010: 48 8d 4c 24 0c lea rcx,[rsp+0xc]
401015: 48 8d 54 24 08 lea rdx,[rsp+0x8]
40101a: be cf 25 40 00 mov esi,0x4025cf // %d %d
40101f: b8 00 00 00 00 mov eax,0x0
// int a @ rsp + 0x8
// int b @ rsp + 0xc
// if sscanf(str, "%d %d", &a, &b) != 2:
// explode_bomb()
401024: e8 c7 fb ff ff call 400bf0 <__isoc99_sscanf@plt>
401029: 83 f8 02 cmp eax,0x2
40102c: 75 07 jne 401035 <phase_4+0x29>
40102e: 83 7c 24 08 0e cmp DWORD PTR [rsp+0x8],0xe
401033: 76 05 jbe 40103a <phase_4+0x2e>
401035: e8 00 04 00 00 call 40143a <explode_bomb>
40103a: ba 0e 00 00 00 mov edx,0xe
40103f: be 00 00 00 00 mov esi,0x0
401044: 8b 7c 24 08 mov edi,DWORD PTR [rsp+0x8] // a
// if a > 0xe:
// explode_bomb()
// ret = func4(a, 0, 0xe); // return 0 if a == 7
// if ret != 0:
// explode_bomb()
// if b != 0:
// explode_bomb()
401048: e8 81 ff ff ff call 400fce <func4>
40104d: 85 c0 test eax,eax
40104f: 75 07 jne 401058 <phase_4+0x4c>
401051: 83 7c 24 0c 00 cmp DWORD PTR [rsp+0xc],0x0
401056: 74 05 je 40105d <phase_4+0x51>
401058: e8 dd 03 00 00 call 40143a <explode_bomb>
40105d: 48 83 c4 18 add rsp,0x18
401061: c3 ret
```
首先,輸入的字串透過 sscanf 解析成兩個 int 。令他們分別為 `a` , `b` 。
接著,執行 `func4(a, 0, 0xe)` ,若返回值不為 0 則爆炸。此外若 `b` 不為 0 也會爆炸。
`func4` 的邏輯如下:
```python=
def func4(a, rsi, rdx):
buf = edx - esi # e
tmp = a >>> 0x1f # logic right shift, 16 + 15 = 31
buf += tmp # e + 0 = e
buf >>= 1 # e >> 1 = 7
n = buf + rsi # buf + 0 = 7
# n == a -> return 0
if n <= a :
if n >= a:
return 0
ret = func(a, n + 1, rdx);
ret = ret * 2 + 1
else:
ret = func4(a, rsi, n - 1)
ret *= 2
return ret
```
可以發現只要在開始時使 `a` = 7 即可避免遞迴,並直接返回 0 。
因此 phase_4 的解答為:
`7 0`
phase_4 的完整邏輯為:
```c=
int func4(int a, int rsi, int rdx) {
int buf = rdx - rsi;
int tmp = ((unsigned int)a) >> 0x1f; // logical shift
buf += tmp;
buf >>= 1;
int n = buf + rsi;
if (n <= a) {
if (n >= a)
return 0;
int ret = func4(a, n + 1, rdx);
return ret * 2 + 1;
} else {
int ret = func4(a, rsi, n - 1);
return ret * 2;
}
}
void phase_4(char *input) {
int a, b;
int n = sscanf(input, "%d %d", &a, &b);
if (n != 2)
explode_bomb();
if (func4(a, 0, 0xe) != 0)
explode_bomb();
if (b != 0)
explode_bomb();
}
```
### phase_5
```asm
0000000000401062 <phase_5>:
401062: 53 push rbx
401063: 48 83 ec 20 sub rsp,0x20
401067: 48 89 fb mov rbx,rdi
40106a: 64 48 8b 04 25 28 00 mov rax,QWORD PTR fs:0x28
401071: 00 00
401073: 48 89 44 24 18 mov QWORD PTR [rsp+0x18],rax
401078: 31 c0 xor eax,eax
40107a: e8 9c 02 00 00 call 40131b <string_length>
40107f: 83 f8 06 cmp eax,0x6
401082: 74 4e je 4010d2 <phase_5+0x70>
401084: e8 b1 03 00 00 call 40143a <explode_bomb>
401089: eb 47 jmp 4010d2 <phase_5+0x70>
40108b: 0f b6 0c 03 movzx ecx,BYTE PTR [rbx+rax*1]
40108f: 88 0c 24 mov BYTE PTR [rsp],cl
401092: 48 8b 14 24 mov rdx,QWORD PTR [rsp]
401096: 83 e2 0f and edx,0xf
401099: 0f b6 92 b0 24 40 00 movzx edx,BYTE PTR [rdx+0x4024b0]
4010a0: 88 54 04 10 mov BYTE PTR [rsp+rax*1+0x10],dl
4010a4: 48 83 c0 01 add rax,0x1
4010a8: 48 83 f8 06 cmp rax,0x6
4010ac: 75 dd jne 40108b <phase_5+0x29>
4010ae: c6 44 24 16 00 mov BYTE PTR [rsp+0x16],0x0
4010b3: be 5e 24 40 00 mov esi,0x40245e
4010b8: 48 8d 7c 24 10 lea rdi,[rsp+0x10]
4010bd: e8 76 02 00 00 call 401338 <strings_not_equal>
4010c2: 85 c0 test eax,eax
4010c4: 74 13 je 4010d9 <phase_5+0x77>
4010c6: e8 6f 03 00 00 call 40143a <explode_bomb>
4010cb: 0f 1f 44 00 00 nop DWORD PTR [rax+rax*1+0x0]
4010d0: eb 07 jmp 4010d9 <phase_5+0x77>
4010d2: b8 00 00 00 00 mov eax,0x0
4010d7: eb b2 jmp 40108b <phase_5+0x29>
4010d9: 48 8b 44 24 18 mov rax,QWORD PTR [rsp+0x18]
4010de: 64 48 33 04 25 28 00 xor rax,QWORD PTR fs:0x28
4010e5: 00 00
4010e7: 74 05 je 4010ee <phase_5+0x8c>
4010e9: e8 42 fa ff ff call 400b30 <__stack_chk_fail@plt>
4010ee: 48 83 c4 20 add rsp,0x20
4010f2: 5b pop rbx
4010f3: c3 ret
```
#### 有註解的版本
```asm
0000000000401062 <phase_5>:
401062: 53 push rbx
401063: 48 83 ec 20 sub rsp,0x20
401067: 48 89 fb mov rbx,rdi // rbx = str
40106a: 64 48 8b 04 25 28 00 mov rax,QWORD PTR fs:0x28
401071: 00 00
401073: 48 89 44 24 18 mov QWORD PTR [rsp+0x18],rax // canary
401078: 31 c0 xor eax,eax
// len = string_length(str)
// if len != 6:
// explode_bomb()
40107a: e8 9c 02 00 00 call 40131b <string_length>
40107f: 83 f8 06 cmp eax,0x6
401082: 74 4e je 4010d2 <phase_5+0x70>
401084: e8 b1 03 00 00 call 40143a <explode_bomb>
401089: eb 47 jmp 4010d2 <phase_5+0x70>
// loop start
// for (i = 0; i != 6; i ++):
// int rdx = str[i]
// rdx &= 0xf
// edx = data[rdx] // data = "
// buf[i] = edx
40108b: 0f b6 0c 03 movzx ecx,BYTE PTR [rbx+rax*1] // move with zero extend
40108f: 88 0c 24 mov BYTE PTR [rsp],cl
401092: 48 8b 14 24 mov rdx,QWORD PTR [rsp]
401096: 83 e2 0f and edx,0xf
401099: 0f b6 92 b0 24 40 00 movzx edx,BYTE PTR [rdx+0x4024b0]
4010a0: 88 54 04 10 mov BYTE PTR [rsp+rax*1+0x10],dl
4010a4: 48 83 c0 01 add rax,0x1
4010a8: 48 83 f8 06 cmp rax,0x6
4010ac: 75 dd jne 40108b <phase_5+0x29>
4010ae: c6 44 24 16 00 mov BYTE PTR [rsp+0x16],0x0
4010b3: be 5e 24 40 00 mov esi,0x40245e
4010b8: 48 8d 7c 24 10 lea rdi,[rsp+0x10]
4010bd: e8 76 02 00 00 call 401338 <strings_not_equal>
4010c2: 85 c0 test eax,eax
4010c4: 74 13 je 4010d9 <phase_5+0x77>
4010c6: e8 6f 03 00 00 call 40143a <explode_bomb>
4010cb: 0f 1f 44 00 00 nop DWORD PTR [rax+rax*1+0x0]
4010d0: eb 07 jmp 4010d9 <phase_5+0x77>
4010d2: b8 00 00 00 00 mov eax,0x0
4010d7: eb b2 jmp 40108b <phase_5+0x29>
// canary check
4010d9: 48 8b 44 24 18 mov rax,QWORD PTR [rsp+0x18]
4010de: 64 48 33 04 25 28 00 xor rax,QWORD PTR fs:0x28
4010e5: 00 00
4010e7: 74 05 je 4010ee <phase_5+0x8c>
4010e9: e8 42 fa ff ff call 400b30 <__stack_chk_fail@plt>
4010ee: 48 83 c4 20 add rsp,0x20
4010f2: 5b pop rbx
4010f3: c3 ret
```
首先判斷輸入字串的長度是否為 6 。
接著 0x401089 ~ 0x4010ac 為一迴圈,迴圈歷遍輸入字串,並且取當前字元的低 4 bits 作為 offset 。接著從位於 0x4024b0 的陣列中,取出對應 offset 的字元,存入另一字串 `key` 中。
最後比對 `key` 與目標字串(位於 0x40245e )是否相同。若不相同則引爆炸彈。
首先利用 gdb 便可找出 0x4024b0 與目標字串分別為:
- 0x4024b0
```gdb
gdb-peda$ x/s 0x4024b0
0x4024b0 <array.3449>: "maduiersnfotvbyl(後略)"
```
- 0x40245e
```gdb
gdb-peda$ x/s 0x40245e
0x40245e: "flyers"
```
接著只要透過簡單的腳本,從 0x4024b0 字串中找出對應 "flyers" 的字元的 offset 即可。
這邊需要注意的是,由於是取每一字元的低 4 bits 。因此在轉成可視字元時,只要找到一個低 4 bits 為 0x0 的基底即可。(我這邊使用的是 '@' 其 ascii code 為 0x40)。
對應的腳本為
```python=
data = "maduiersnfotvbyl"
password = "flyers"
args = []
for i in password:
n = data.find(i)
args.append(n)
payload = ''.join(chr(n + ord('@')) for n in args)
```
參考解答為:
`IONEFG`
phase_5 的邏輯如下:
```c=
void phase_5(char *input) {
if (string_length(input) != 6)
explode_bomb()
static const char *words = "maduiersnfotvbyl";
char key[6];
for (int i=0; i<6; i++) {
unsigned int offset = input[i] & 0xf;
key[i] = words[offset];
}
static const char *password = "flyers";
if (string_not_equal(key, password))
explode_bomb();
}
```
### phase_6
```asm
00000000004010f4 <phase_6>:
4010f4: 41 56 push r14
4010f6: 41 55 push r13
4010f8: 41 54 push r12
4010fa: 55 push rbp
4010fb: 53 push rbx
4010fc: 48 83 ec 50 sub rsp,0x50
401100: 49 89 e5 mov r13,rsp
401103: 48 89 e6 mov rsi,rsp
401106: e8 51 03 00 00 call 40145c <read_six_numbers>
40110b: 49 89 e6 mov r14,rsp
40110e: 41 bc 00 00 00 00 mov r12d,0x0
401114: 4c 89 ed mov rbp,r13
401117: 41 8b 45 00 mov eax,DWORD PTR [r13+0x0]
40111b: 83 e8 01 sub eax,0x1
40111e: 83 f8 05 cmp eax,0x5
401121: 76 05 jbe 401128 <phase_6+0x34>
401123: e8 12 03 00 00 call 40143a <explode_bomb>
401128: 41 83 c4 01 add r12d,0x1
40112c: 41 83 fc 06 cmp r12d,0x6
401130: 74 21 je 401153 <phase_6+0x5f>
401132: 44 89 e3 mov ebx,r12d
401135: 48 63 c3 movsxd rax,ebx
401138: 8b 04 84 mov eax,DWORD PTR [rsp+rax*4]
40113b: 39 45 00 cmp DWORD PTR [rbp+0x0],eax
40113e: 75 05 jne 401145 <phase_6+0x51>
401140: e8 f5 02 00 00 call 40143a <explode_bomb>
401145: 83 c3 01 add ebx,0x1
401148: 83 fb 05 cmp ebx,0x5
40114b: 7e e8 jle 401135 <phase_6+0x41>
40114d: 49 83 c5 04 add r13,0x4
401151: eb c1 jmp 401114 <phase_6+0x20>
401153: 48 8d 74 24 18 lea rsi,[rsp+0x18]
401158: 4c 89 f0 mov rax,r14
40115b: b9 07 00 00 00 mov ecx,0x7
401160: 89 ca mov edx,ecx
401162: 2b 10 sub edx,DWORD PTR [rax]
401164: 89 10 mov DWORD PTR [rax],edx
401166: 48 83 c0 04 add rax,0x4
40116a: 48 39 f0 cmp rax,rsi
40116d: 75 f1 jne 401160 <phase_6+0x6c>
40116f: be 00 00 00 00 mov esi,0x0
401174: eb 21 jmp 401197 <phase_6+0xa3>
401176: 48 8b 52 08 mov rdx,QWORD PTR [rdx+0x8]
40117a: 83 c0 01 add eax,0x1
40117d: 39 c8 cmp eax,ecx
40117f: 75 f5 jne 401176 <phase_6+0x82>
401181: eb 05 jmp 401188 <phase_6+0x94>
401183: ba d0 32 60 00 mov edx,0x6032d0
401188: 48 89 54 74 20 mov QWORD PTR [rsp+rsi*2+0x20],rdx
40118d: 48 83 c6 04 add rsi,0x4
401191: 48 83 fe 18 cmp rsi,0x18
401195: 74 14 je 4011ab <phase_6+0xb7>
401197: 8b 0c 34 mov ecx,DWORD PTR [rsp+rsi*1]
40119a: 83 f9 01 cmp ecx,0x1
40119d: 7e e4 jle 401183 <phase_6+0x8f>
40119f: b8 01 00 00 00 mov eax,0x1
4011a4: ba d0 32 60 00 mov edx,0x6032d0
4011a9: eb cb jmp 401176 <phase_6+0x82>
4011ab: 48 8b 5c 24 20 mov rbx,QWORD PTR [rsp+0x20]
4011b0: 48 8d 44 24 28 lea rax,[rsp+0x28]
4011b5: 48 8d 74 24 50 lea rsi,[rsp+0x50]
4011ba: 48 89 d9 mov rcx,rbx
4011bd: 48 8b 10 mov rdx,QWORD PTR [rax]
4011c0: 48 89 51 08 mov QWORD PTR [rcx+0x8],rdx
4011c4: 48 83 c0 08 add rax,0x8
4011c8: 48 39 f0 cmp rax,rsi
4011cb: 74 05 je 4011d2 <phase_6+0xde>
4011cd: 48 89 d1 mov rcx,rdx
4011d0: eb eb jmp 4011bd <phase_6+0xc9>
4011d2: 48 c7 42 08 00 00 00 mov QWORD PTR [rdx+0x8],0x0
4011d9: 00
4011da: bd 05 00 00 00 mov ebp,0x5
4011df: 48 8b 43 08 mov rax,QWORD PTR [rbx+0x8]
4011e3: 8b 00 mov eax,DWORD PTR [rax]
4011e5: 39 03 cmp DWORD PTR [rbx],eax
4011e7: 7d 05 jge 4011ee <phase_6+0xfa>
4011e9: e8 4c 02 00 00 call 40143a <explode_bomb>
4011ee: 48 8b 5b 08 mov rbx,QWORD PTR [rbx+0x8]
4011f2: 83 ed 01 sub ebp,0x1
4011f5: 75 e8 jne 4011df <phase_6+0xeb>
4011f7: 48 83 c4 50 add rsp,0x50
4011fb: 5b pop rbx
4011fc: 5d pop rbp
4011fd: 41 5c pop r12
4011ff: 41 5d pop r13
401201: 41 5e pop r14
401203: c3 ret
```
#### 有註解的版本
```asm
00000000004010f4 <phase_6>:
4010f4: 41 56 push r14
4010f6: 41 55 push r13
4010f8: 41 54 push r12
4010fa: 55 push rbp
4010fb: 53 push rbx
4010fc: 48 83 ec 50 sub rsp,0x50
401100: 49 89 e5 mov r13,rsp // r13 = rsp
401103: 48 89 e6 mov rsi,rsp
401106: e8 51 03 00 00 call 40145c <read_six_numbers>
40110b: 49 89 e6 mov r14,rsp // void *r14 = rsp
40110e: 41 bc 00 00 00 00 mov r12d,0x0 // r12d = 0 (r12d = r12 lower 32 bits)
/*
// 1. arg[i] - 1 <= 5, arg[i] <= 6, unsigned cmp
// 2. arg[i] != arg[j] for all i != j
r13 = buf
rsi = buf
read_six_numbers(str, buf)
r14 = buf
i = 0
int *ptr = buf // r13
do {
if (ptr[0] - 1) > 5: // ptr[0] = arg[i], unsigned
explode_bomb
i += 1
if i == 6:
break outer
ebx = i
do {
long rax = ebx // sign extend
eax = buf[rax]
if eax == ptr[0]:
explode_bomb
ebx += 1
} while ebx <= 5
ptr += 1
}
*/
401114: 4c 89 ed mov rbp,r13 // rbp = r13
401117: 41 8b 45 00 mov eax,DWORD PTR [r13+0x0] // eax = rsp[0]
40111b: 83 e8 01 sub eax,0x1 // eax - 1
40111e: 83 f8 05 cmp eax,0x5
401121: 76 05 jbe 401128 <phase_6+0x34>
401123: e8 12 03 00 00 call 40143a <explode_bomb>
401128: 41 83 c4 01 add r12d,0x1
40112c: 41 83 fc 06 cmp r12d,0x6
401130: 74 21 je 401153 <phase_6+0x5f>
401132: 44 89 e3 mov ebx,r12d
401135: 48 63 c3 movsxd rax,ebx
401138: 8b 04 84 mov eax,DWORD PTR [rsp+rax*4]
40113b: 39 45 00 cmp DWORD PTR [rbp+0x0],eax
40113e: 75 05 jne 401145 <phase_6+0x51>
401140: e8 f5 02 00 00 call 40143a <explode_bomb>
401145: 83 c3 01 add ebx,0x1
401148: 83 fb 05 cmp ebx,0x5
40114b: 7e e8 jle 401135 <phase_6+0x41>
40114d: 49 83 c5 04 add r13,0x4
401151: eb c1 jmp 401114 <phase_6+0x20>
// End
/*
// n = 7 - i
// i = 7 - n
// buf = buf.map(i -> 7-i)
int *bound = rsp + 0x18 // &rsp[6] = &buf[0]
int *ptr = &buf[0]
ecx = 7
do {
*ptr = 7 - *ptr
ptr += 1
} while ptr != bound
*/
401153: 48 8d 74 24 18 lea rsi,[rsp+0x18]
401158: 4c 89 f0 mov rax,r14 // r14 = rsp
40115b: b9 07 00 00 00 mov ecx,0x7
// loop start
401160: 89 ca mov edx,ecx
401162: 2b 10 sub edx,DWORD PTR [rax] // edx = edx - *rax
401164: 89 10 mov DWORD PTR [rax],edx
401166: 48 83 c0 04 add rax,0x4
40116a: 48 39 f0 cmp rax,rsi
40116d: 75 f1 jne 401160 <phase_6+0x6c>
// loop end
/*
// long *nodes = rsp + 0x20
// n = buf[i]
// nodes[i] = node[n], if n > 1
// node[1], if n <= 1
i = 0 // i = esi
do {
n = buf[i]
if n <= 1:
tmp = node1 // 0x6032d0
else:
eax = 1
tmp = node1 // 0x6032d0
do
tmp = tmp.next // tmp.next @ tmp[1]
eax += 1
while eax != n
// long *nodes = rsp + 0x20
nodes[i] = tmp
i += 1
} while i != 6
*/
40116f: be 00 00 00 00 mov esi,0x0
401174: eb 21 jmp 401197 <phase_6+0xa3>
401176: 48 8b 52 08 mov rdx,QWORD PTR [rdx+0x8]
40117a: 83 c0 01 add eax,0x1
40117d: 39 c8 cmp eax,ecx
40117f: 75 f5 jne 401176 <phase_6+0x82>
401181: eb 05 jmp 401188 <phase_6+0x94>
401183: ba d0 32 60 00 mov edx,0x6032d0
401188: 48 89 54 74 20 mov QWORD PTR [rsp+rsi*2+0x20],rdx
40118d: 48 83 c6 04 add rsi,0x4
401191: 48 83 fe 18 cmp rsi,0x18
401195: 74 14 je 4011ab <phase_6+0xb7> // break
401197: 8b 0c 34 mov ecx,DWORD PTR [rsp+rsi*1]
40119a: 83 f9 01 cmp ecx,0x1
40119d: 7e e4 jle 401183 <phase_6+0x8f> // backward
40119f: b8 01 00 00 00 mov eax,0x1
4011a4: ba d0 32 60 00 mov edx,0x6032d0
4011a9: eb cb jmp 401176 <phase_6+0x82>
// end
// rsp + 0x20 is nodes
/*
// nodes[0] -> nodes[1] ....
// nodes[i] -> nodes[i + 1]
struct node *rbx = nodes[0]
struct node **ptr = &nodes[1]
struct node **bound = &nodes[6]
struct node *prev = rbx
loop {
struct node *curr = *ptr
prev.next = curr
ptr += 1
if ptr == bound:
break
prev = curr
}
curr.next = NULL
*/
4011ab: 48 8b 5c 24 20 mov rbx,QWORD PTR [rsp+0x20] // rbx = nodes[0]
4011b0: 48 8d 44 24 28 lea rax,[rsp+0x28] // rax = &buf[1]
4011b5: 48 8d 74 24 50 lea rsi,[rsp+0x50] // rsi = &buf[6]
4011ba: 48 89 d9 mov rcx,rbx // rcx = nodes[0]
4011bd: 48 8b 10 mov rdx,QWORD PTR [rax]
4011c0: 48 89 51 08 mov QWORD PTR [rcx+0x8],rdx
4011c4: 48 83 c0 08 add rax,0x8
4011c8: 48 39 f0 cmp rax,rsi
4011cb: 74 05 je 4011d2 <phase_6+0xde> // break
4011cd: 48 89 d1 mov rcx,rdx
4011d0: eb eb jmp 4011bd <phase_6+0xc9> // loop
4011d2: 48 c7 42 08 00 00 00 mov QWORD PTR [rdx+0x8],0x0
// end
4011d9: 00
// rbx = nodes[0] // A pointer to first node
/*
// Check whether the list is sorted in decreasing order or not.
i = 5 // i = ebp
curr = nodes[0]
do {
next = curr.next
if curr.value < next.value:
explode_bomb
curr = curr.next
i -= 1
} while i >= 0
*/
4011da: bd 05 00 00 00 mov ebp,0x5 // ebp = 5
4011df: 48 8b 43 08 mov rax,QWORD PTR [rbx+0x8] // rax = node[1]
4011e3: 8b 00 mov eax,DWORD PTR [rax] // eax = rax.value
4011e5: 39 03 cmp DWORD PTR [rbx],eax
4011e7: 7d 05 jge 4011ee <phase_6+0xfa>
4011e9: e8 4c 02 00 00 call 40143a <explode_bomb>
4011ee: 48 8b 5b 08 mov rbx,QWORD PTR [rbx+0x8]
4011f2: 83 ed 01 sub ebp,0x1
4011f5: 75 e8 jne 4011df <phase_6+0xeb>
// End
4011f7: 48 83 c4 50 add rsp,0x50
4011fb: 5b pop rbx
4011fc: 5d pop rbp
4011fd: 41 5c pop r12
4011ff: 41 5d pop r13
401201: 41 5e pop r14
401203: c3 ret
```
首先呼叫 `read_six_numbers` 將 input 解析成 6 個 int 並放於 buf 中。
接著對 buf 內的數字做檢查。規則如下:
1. $1 \le buf \le 6$
2. buf[i] $\ne$ buf[j], $\forall i \ne j$
接著將 buf 中的每一數字變為其 mod 7 的加法反元素。
為了解析接下來的程式,必須先定義一個 struct `node`
```c=
struct node {
int value;
int index;
struct node *next;
};
```
可以發現此 struct 構成 linked list 節點。
接下來的程式將會圍繞著一個 struct node 陣列 `node_arr` 展開。該陣列中具有 6 的元素,並且位於 0x6032d0 。
首先透過 gdb 觀察該陣列:
```gdb
gdb-peda$ x/12gx 0x6032d0
0x6032d0 <node1>: 0x000000010000014c 0x00000000006032e0
0x6032e0 <node2>: 0x00000002000000a8 0x00000000006032f0
0x6032f0 <node3>: 0x000000030000039c 0x0000000000603300
0x603300 <node4>: 0x00000004000002b3 0x0000000000603310
0x603310 <node5>: 0x00000005000001dd 0x0000000000603320
0x603320 <node6>: 0x00000006000001bb 0x0000000000000000
```
在初始狀態 linked list 的狀態為:
node1 -> node2 -> node3 -> node4 -> node5 -> node6 -> NULL
接下來,為了方便解釋,會先將接下來的程式翻譯成 c 語言來解釋。
```c=
struct node *nodes[6];
// nodes[i] = node_arr[buf[i]];
for (int i=0; i<6; i++) {
struct node *tmp = &node_arr[1];
n = buf[i];
if (n > 1) {
for (int j=0; j<n; j++) {
tmp = tmp->next;
}
}
nodes[i] = tmp;
}
// link the list by the order of "nodes"
struct node *prev = nodes[0];
struct node *curr;
for (int i=1; i<6; i++) {
curr = nodes[i];
prev->next = curr;
prev = curr;
}
curr->next = NULL;
// Check wheither the linked list is in non-increasing order
curr = nodes[0];
struct node *next;
for (int i=5; i>=0; i++) {
next = curr->next;
if (curr->value < next->value)
explode_bomb();
curr = curr->next;
}
```
首先,將 nodes[i] 指向 linked list 的第 buf[i] 個節點。接著將 nodes[i] 的節點的 next 指向 nodes[i+1] 。也就是在執行結束後, linked list 會是:
nodes[0] -> nodes[1] -> nodes[2] ->nodes[3] ->nodes[4] ->nodes[5] -> NULL 。
最後在檢查整個 linked list 中的值是否按照非遞增排列。
了解邏輯後,便知道我們需要按照需求找出節點間非遞增排列的順序,並依序輸入他們的 mod 7 的加法反元素。
```python=
values = [0x0000014c, 0x000000a8, 0x0000039c, 0x000002b3, 0x000001dd, 0x000001bb]
tuples = []
for i in range(len(values)):
tuples.append((i + 1, values[i]))
tuples.sort(key = lambda tup: tup[1])
args = []
for tup in tuples:
args.append(7 - tup[0])
args.reverse()
payload = ' '.join(str(n) for n in args)
```
透過一個簡單的腳本我們可以得出答案為:
`4 3 2 1 6 5`
而執行後 linked list 的狀態為:
```gdb
gdb-peda$ x/12gx 0x6032d0
0x6032d0 <node1>: 0x000000010000014c 0x00000000006032e0
0x6032e0 <node2>: 0x00000002000000a8 0x0000000000000000
0x6032f0 <node3>: 0x000000030000039c 0x0000000000603300
0x603300 <node4>: 0x00000004000002b3 0x0000000000603310
0x603310 <node5>: 0x00000005000001dd 0x0000000000603320
0x603320 <node6>: 0x00000006000001bb 0x00000000006032d0
```
邏輯上的順序為:
node3 -> node4 -> node5 -> node6 -> node1 -> node2 -> NULL
phase_6 的邏輯如下:
```c=
void phase_6(char *input) {
int buf[6];
read_six_numbers(input, buf);
for (int i=0; i<6; i++) {
if (!(buf[i] >= 1 && buf[i] <=6))
explode_bomb();
for (int j=i+1; j<6; j++) {
if (buf[i] == buf[j])
explode_bomb();
}
}
for (int i=0; i<6; i++) {
buf[i] = 7 - buf[i];
}
static struct node_arr[] = {
// init omit
};
struct node *nodes[6];
// nodes[i] = node_arr[buf[i]];
for (int i=0; i<6; i++) {
struct node *tmp = &node_arr[1];
n = buf[i];
if (n > 1) {
for (int j=0; j<n; j++) {
tmp = tmp->next;
}
}
nodes[i] = tmp;
}
// link the list by the order of "nodes"
struct node *prev = nodes[0];
struct node *curr;
for (int i=1; i<6; i++) {
curr = nodes[i];
prev->next = curr;
prev = curr;
}
curr->next = NULL;
// Check wheither the linked list is in non-increasing order
curr = nodes[0];
struct node *next;
for (int i=5; i>=0; i++) {
next = curr->next;
if (curr->value < next->value)
explode_bomb();
curr = curr->next;
}
}
```
## TODO
- [ ] secret_phase