---
# System prepended metadata

title: HW 0x02 Write Up
tags: [Course, CS, NCTU, SecureProgramming]

---

###### tags: `NCTU` `CS` `Course` `SecureProgramming`

HW 0x02 Write Up
==
yysung

## [Lab 2-1] Add
flag: flag{y0u_added_thr33_nums!}

使用反編譯程式後，可以發現該程式會讀取三個數字，並將其加總

將加總的數字當作參數呼叫 gen 函式得到一個字串

而且只有在加總為 1337 時，才會印出 flag{字串}

輸入 `0 0 1337` 後就可以得到 flag

## [Lab 2-2] Guess
flag: flag{aaA_tOucH_0f_luccK_47ca4e}

使用反編譯程式後，可以發現該程式會先隨機產生一個數字
接下來讀入數字並與隨機數字比較，如果不同則回傳 Hi 或 Lo，只能猜測 22 次

猜測成功後就可以輸出 flag

將比較數字的機器碼 `0x400b93~0x400b94` 都 patch 成 `nop`，就不會比較數字，而且會直接跳到印 flag 的程式碼，就可以得到 flag

## [Lab 2-3] Forest
flag: flag{you_could_see_the_forest_for_the_trees_ckyljfxyfmsw}

該程式會從 argv 讀入兩個字串，第二個字串是題目給定的字串。只要第一個字串是 flag 就會輸出 `You did it! Put the input in the flag{}.`

使用反編譯程式後，可以發現該程式會先用內建於程式裡的字串生出一個樹狀結構，並照著 argv 的第二個字串走訪樹

+ D 代表的是將該節點的值和argv 的第一個字串比對並回到樹根
+ L 代表的是往當前節點的左節點走
+ R 代表的是往當前節點的右節點走

只要用一樣的方法生出一個樹狀結構，並用題目給定的字串走訪，在 D 時印出該節點的值，就可以得到 flag

`lab2-3.cpp` 即為上述程式

## [HW 0x02] simplebox
flag: flag{wow0oW_Y0U_brEak_Th3_$IMP1e8oX}

該程式會從 argv 讀入題目給定的檔案的 filename ，接下來會讀入 36 個字元，隨便輸入後回傳 `Try hard!`

先用 `strings` 指令發現該程式有用 upx 加殼，所以先脱殼

使用 `strings` 後發現無法找到 `Try hard!` 字串

使用反編譯程式後，發現該程式是靜態編譯而且 symbol 有被拔掉，無法直接看出 main 函式的位置

尋找後發現 main 函式在 `0x401B1C` 的位置，接下來會將 filename  fopen 並以 fread 讀入至 `0x4AFB60`，計算 `0x4AFB60` 字串的長度，並將該字串和長度作為 `0x401E9E` 函式的參數

題目給定的檔案內容最後有一個=，所以猜測是 base64 編碼過的字串，使用 `gdb` 執行後發現 `0x401E9E` 函式會將字串做 base64 解碼

被 base64 解碼的字串會被當作 `0x4016FD` 函式的參數，回傳值再被當作 `0x401978` 函式的參數

`0x4016FD` 函式是一個 switch case，有 8 個 cases，每個 cases 分別是把 1~8 以 2 bytes 大小放入 `0x4A7340` 並且每次跳 4 bytes，使用 gdb 看 `0x4A7340` 後會得到

```
0x4a7340:       0x0000000100000003      0x000b000700000006
0x4a7350:       0x0000000300000001      0x0000000300000001
0x4a7360:       0x0000000200000002      0x0003000800000004
0x4a7370:       0x0000000100000001      0x0000000200150007
```
只看 `0x4016FD` 操作的記憶體就是
```
3167131322481172
```
和題目給定的檔案 base64 解碼後的字串比較
```
mBOFBmBmaabxBBFa
```

可以看出以下對應
```
B:1, a:2, m:3, b:4, O:6, F:7, x:8
```

剩下的 o 對應的是 5

`0x401978` 將上面做的轉換作為輸入，而且也是一個有 8 個 cases 的 switch case

+ 1 將 [rbp+var_8] 加 1
+ 2 將 [rbp+var_8] 減 1
+ 3 將 rbp+2*[rbp+var_8]+var_20010 指到的記憶體值加 1
+ 4 將 rbp+2*[rbp+var_8]+var_20010 指到的記憶體值減 1
+ 5 將 rbp+2*[rbp+var_8]+var_20010 指到的記憶體值當作參數呼叫 `0x40A200`
+ 6 將 `0x40BCD0` 函式的回傳值寫入 rbp+2*[rbp+var_8]+var_20010 指到的記憶體位址
+ 7 比對 [rbp+var_8] 是否為 0，是則跳躍
+ 8 比對 [rbp+var_8] 是否為 0，否則跳躍

`0x40A200` 為 write 一個字元， `0x40BCD0` 為 read 一個字元

以上的行為和 brainfuck 語言極為相似，所以將base64 解碼後的字串用以上規則轉換後用 brainfuck 直譯器執行，發現程式會先讀入一個字元，再建構出比較的字元，也就是 flag，再進行比較，全部字元
完全相同的會就會印 `You got the flag!`

所以就將建構比較字元的程式碼複製出來執行，就可以得到 flag

`sol.b` 即為可以印出 flag 的 brainfuck 程式碼