--- tags: CS 2022 Fall, 程式安全 author: Ching367436 --- # [0x05] Reverse II slide: https://drive.google.com/drive/folders/1ZC6mdxIzcLsnGJ7j8S4emGsiY_LRNlKt?usp=sharing lecture: https://youtu.be/1EAV4XeQ8C4 <style> img { box-shadow: 0px 0px 15px #000; } </style> ### [LAB] AMessageBox ![](https://i.imgur.com/Wm4LeeO.png) 點開發現會輸入 flag 會跑出 `messageBox` #### 下斷點 來到 `x64dbg > Symbols > user32.dll` ![](https://i.imgur.com/lbhZvVR.png) 把跟 `messageBox` 有關的地方先放斷點 ![](https://i.imgur.com/DSgSMhz.png) 看到停在一個神奇的地方 繼續執行 撞到斷點 ![](https://i.imgur.com/BnoMRVF.png) 那是 `messageBoxA` #### `Call Stack` 來追 `Call Stack` ![](https://i.imgur.com/czea7WN.png) 來到 `amessagebox_904ac0c699abc2f6.00F3110B` #### `amessagebox_904ac0c699abc2f6.00F3110B` ![](https://i.imgur.com/GNOvr3O.png) 看到 `call AMessageBox` 的上面可以看到確認 `flag` 的比較 ![](https://i.imgur.com/J9xJr7m.png) 會把輸入的 `flag` 操作後跟 `flag_enc` 比較 所以只要把 `flag_enc` 拉出來 進行反操作就可以得到原本的 `flag` ![](https://i.imgur.com/pkpt1pE.png) #### `solve` ##### `AMessageBox/exp.py` ```python # xor 87 dump = bytearray([x ^ 0x87 for x in dump]) # rol 3 dump = bytearray([rotate_right(x, 3) for x in dump]) print(dump) # bytearray(b'FLAG{8699314d319802ef792b7babac9da58a}\xf0\xf0\xf0\xf0\xf0\xf0\xf0\xf0\xf0\xf0') ``` ### [LAB] IAT Hook #### `main` ![](https://i.imgur.com/MAADaRA.png) 先由 `:20` 知道 `flag` 長度可能是 $26$ 進入 `:17` #### `sub_7FF6EE5E1AC0` ![](https://i.imgur.com/Ir9HnQX.png) 看到 `:8` 對 `ModuleName` 做了一些事情 然後 `GetModuleHandleA(ModuleName)` `:8` 可能是對 `ModuleName` 解密 #### `:8` 修好可以發現真的是解密 ![](https://i.imgur.com/7nEYzwo.png) 這邊直接動態分析 ![](https://i.imgur.com/4c8oboO.png) <!-- ![](https://i.imgur.com/wgbyrg1.jpg) --> 發現 `ModuleName` 是 `kernel32.dll` 之後從 `x64dbg` 觀察 `:9` `GetProcAddres` 的第二個 `argument` 看到是 `GetProcAddres` ![](https://i.imgur.com/qgFRhwr.png) 從 `ida` 也可以看到一樣的事 ![](https://i.imgur.com/FVTfMhs.png) 所以 `:9` 的回傳值會是 `GetProcAddres` 的地址 ![](https://i.imgur.com/OAXK39j.png) `GetProcAddres_0` 之後也會繼續被呼叫 ![](https://i.imgur.com/UXM42FT.png) `:10` 是 `GetModuleHandleA` ![](https://i.imgur.com/NRRDEZz.png) ![](https://i.imgur.com/dUtjsHk.png) `:11` 是 `VirtualProtect` ![](https://i.imgur.com/jjac67c.png) `:12` 是 `user32.dll` ![](https://i.imgur.com/KDbldSh.png) 最後是 `MessageBoxA` 回到 `main` #### `main` <!-- ![](https://i.imgur.com/gHn5jyg.png) --> ![](https://i.imgur.com/khbgYMd.png) 然後進 `:25` #### `:25` ![](https://i.imgur.com/S8RKhac.png) 看到 `MessageBoxA` 被換成 `sub_7FF6DE9913A2` 了 更名為 `myMsgBx` 進去看看 #### `myMsgBx` ![](https://i.imgur.com/vB43RTX.png) 整理一下看到檢查 `flag` 的邏輯 只要把 `flag_enc` 多 `encrypt` 一次就會得到原本的 `flag` ##### `IAT Hook/solve.cpp` ```cpp int main () { char aWrong[10] = "Wrong\0"; int key_len = strlen(aWrong); encrypt(flag_enc, aWrong, 0x1Au, key_len); for (int j = 0; j < 26; ++j ) { cout << flag_enc[j]; } // output: FLAG{IAT_HoOk,MessageBoxA} } ``` ### [LAB] GetProcAddress #### `main` ![](https://i.imgur.com/xOILRwU.png) 看到 `:24` 猜測 `flag` 長度為 39 直接來動態分析 發現如果用 `ARM Windows` 跑會在 `:25` 出錯 所以換用 `x86_64` 發現可以正常跑 ![](https://i.imgur.com/DqljR0p.png) 把 `flag_enc` `key` 拉出啦解密看看 ##### `GetProcAddress/sol.cpp` ```cpp for (int j = 0; j < 39; ++j) { cout << (char)(key[j] ^ flag_enc[8 * j]); } // output: FLAG{Just_a_customized_GetProcAddress!} ``` ### [HW] ooxx 先試著用用看 覺得他應該是要我們下贏 ![](https://i.imgur.com/zGI43tc.png) 結果發現遊戲有 `bug` #### `WinMain` ![](https://i.imgur.com/LcJkfbd.png) `:10,13` 看起來像是畫線 https://learn.microsoft.com/en-us/windows/win32/gdiplus/-gdiplus-drawing-a-line-use 叫他 `drawLine` 到跑到 `:17` 的時候會出現一個視窗 先叫他 `showWindow` #### `showWindow` 看起來是 `Windows GDI` ![](https://i.imgur.com/ECWCea6.png) ![](https://i.imgur.com/BqCPUWp.png) 看到不斷地於 `:32,36` 徘徊 https://learn.microsoft.com/en-us/windows/win32/winmsg/using-messages-and-message-queues 回到 `WinMain` 觀察 `argument` 可以猜測出一些事情 經過猜測可以得到以下結果 ![](https://i.imgur.com/FsqLjR0.png) 下斷點於 `eventListener` 發現下期的時候會碰到斷點 所以是 `eventListener` 沒錯 ![](https://i.imgur.com/W8eO4li.png) #### `eventListener` ![](https://i.imgur.com/vSd8ij7.png) 進入 `:9` `dword_7FF62374D338` ![](https://i.imgur.com/r5hSeUs.png) 看到棋盤了 `2` 代表 `x` `1` 代表 `o` `0` 代表 空著 ![](https://i.imgur.com/0bMRfmS.png) 打開 `Hex View` 把棋盤第二行的第一個改成 `1 (o)` ![](https://i.imgur.com/KYeTPFL.png) 然後按下棋盤的第二排第三個 那樣就可以拿下第二行 ![](https://i.imgur.com/dMDGkTW.png) ![](https://i.imgur.com/j4ylImE.png) 贏了! ``` FLAG{Y0u_Won_A_gaM3_yoU_cOuldn0T_pO5s16ly_w1n} ``` ### [HW] trojan #### `WinMain` ![](https://i.imgur.com/cdKyUUV.png) 點進 `:8` `127.0.0.1` #### `127.0.0.1` 來到了 `.rdata` 看到了很像密碼的東西 ![](https://i.imgur.com/WqUoPQF.png) 進入很像密碼的東西的 `xrefs` #### `sub_140001560` ![](https://i.imgur.com/hb4HrHR.png) #### `:20` `:20` 進去修一修可以看出是 `encrypt` ![](https://i.imgur.com/2J2K2IM.png) 回去上一層 進入 `:13` #### `:13` ![](https://i.imgur.com/WbF0bHj.png) 繼續進去 ![](https://i.imgur.com/2S5lrdc.png) 進入 `:8` ![](https://i.imgur.com/yrXKquf.png) 看到是比較兩個參數 所以知道 `:13` 是 `check_not_equal` 回到 `:13` 的上一層 ![](https://i.imgur.com/gBES0wO.png) 先把這個 func 命名為 `send_and_recv_enc_msg` 決定先來看看 `log_65a0163d1ae2e798.pcapng` #### `log_65a0163d1ae2e798.pcapng` ![](https://i.imgur.com/htGWRNi.png) 看到了跟 `send_and_recv_enc_msg:12` 中一樣的字串 `send_and_recv_enc_msg:13,15` 的地方則是確認收到的訊息是否跟 `cDqr0hUUz1` 一樣 如果一樣會繼續執行下面的內容: 先把 `len (4 bytes)` 送給對方 這對應到了下圖畫起來的部分 ![](https://i.imgur.com/gbPPFNr.png) `0x00025980` 接著會先把 `msg` 加密然後送出 就試著把 `log_65a0163d1ae2e798.pcapng` 的東西解密看看吧 先檢查一下 dump 出來的資料 `size` ```sh Dump size: 153984 ``` 對應到了上面的 `len (0x00025980)` 所以正確 試著解密 因為是使用 `xor`  加密 所以在加密一次就是解密 ##### `trojan/sol.py` ```python with open("result.png", "wb") as f: f.write(encrypt(dump)) ``` #### `result.png` ![](https://i.imgur.com/R4DPgZW.png) ``` FLAG{r3v3R53_cPp_15_pAInfUl} ```