---
title: 大同大學 惡意程式分析 W13 小考
tags:
- Malware Analysis
- writeup
---
# 大同大學 惡意程式分析 W13 小考
## 挑戰題
:::info
**題目:**
David 資料夾中是駭客執行 `Steal.exe` 後,所產生的加密檔案(`output.txt`),請協助解密,看看到底駭客偷了什麼?

:::
一開始就可以先玩玩看這支程式在幹嘛,會發現他跳出一個視窗叫你輸入密碼,如果錯誤就會跳出一個小視窗告訴你。

透過 pe-bear 可以看到這是 AMD64 的可執行檔,但總之可以跑在 x64 上所以不用太擔心。

一樣先丟到 x64dbg,進到 entry point 後看看字串跟引入的函式。從字串可以快速定位到輸入文字的 `fgets()` 還有比較字串的 `strcmp()`。仔細看會發現,在 `strcmp()` 被呼叫前的參數傳遞 `lea rdx,qword ptr ds:[7FF61EE73358]`,會發現字串 `NoPassword` 被傳入。所以可以合理推測密碼就是 `NoPassword`。

驗證的方式也很簡單,直接單獨執行程式去測試。再輸入完密碼 `NoPassword` 後,原本的錯誤提示沒有出現,反而出現了找不到檔案讀寫的錯誤訊息。

為了快速訂位到讀寫檔案的地方,我們可以回到跨模組呼叫的地方,看看有沒有 `CreateFile`、`ReadFile`、`WriteFile` 的 API 呼叫,並在那邊下斷點。

接著往下執行就會看到程式開啟並讀取同個目錄底下的 `target.txt`。

那就直接建一個檔案,看看程式還會有什麼行為。接著就直接順利地到 `ReadFile` 的呼叫了,可以透過 `rdx` 存的位置找到讀入資料的記憶體空間,並在資料視窗中跟隨。
> [!Note]
> ```c
> BOOL ReadFile(
> [in] HANDLE hFile,
> [out] LPVOID lpBuffer,
> [in] DWORD nNumberOfBytesToRead,
> [out, optional] LPDWORD lpNumberOfBytesRead,
> [in, out, optional] LPOVERLAPPED lpOverlapped
> );
> ```
> 若按照 x64 的 calling convention,`rcx`、`rdx`、`r8`、`r9` 去對照,我們便可以看到檔案讀取到的內容 `lpBuffer`。

關閉完 檔案的 HANDLE 後,可以看到有一個 loop 在算檔案內容的長度,`test eax, eax` 檢查如果是空檔案的就會跳出小視窗,告訴你檔案內容錯誤。這點可以透過單獨執行檔案驗證。

在檢查點加個斷點後,將檔案填充一點資料方便之後的除錯。重新往下執行後,會繼續看到一系列的檢查。先是 ` ` 看你的內容的結尾是不是 `\n`(`\x0A`),然後再看你的內容長度有沒有超過 `0x100`(`265`)。接著又有一個 loop 在比較內容是否吻合 `9527`。

到這裡我們先把我們檔案的內容換成 `9527\n` 然後重新單獨執行一次看看看現在能跑到哪了。
> [!Important]
> 換行格式在 CRLF 時,一般的換行會變成 `\r\n`,所以可以用 vs code 將格式改成 `LF` 避免換行是 `\r\n`。
> 
這次跳出的視窗,反倒是顯示了網路的錯誤。所以要提供這支程式有網路連線的環境。使用 Fakenet 或是 inetsim 模擬環境都可以,我是使用 REMnux + inetsim。

設定完網路環境後就再重新執行一次,就看到了成功加密資料並寫入檔案的提示。打開跳出來的 `ouput.txt` 後可以看到跟 David 的 `output.txt` 很相似的內容


重新用 x64dbg 繼續往下追蹤可以看到有一個 loop,這個 loop 會把檔案讀到的每一個字元加總,丟到 `srand()` 設定亂數,接者呼叫兩次 `rand()` 運算。

> 最後運算完的結果 `0x0000000002E46122` 會被放到 `rsi`。然後 `rsi` 的值到加密為止都沒有任何更動,當時在作答時就猜測是密鑰。不過到後面加密的邏輯就可以看到了。
接著繼續往下會看到網路連線的程式,可以看到程式會利用 `InternetOpenUrlA()` 嘗試與 `google.com` 建立連線,若建立失敗就會跳到一開始看到的網路錯誤的 `MessageBox`。
> [!Note]
> ```c
> HINTERNET InternetOpenUrlA(
> [in] HINTERNET hInternet,
> [in] LPCSTR lpszUrl,
> [in] LPCSTR lpszHeaders,
> [in] DWORD dwHeadersLength,
> [in] DWORD dwFlags,
> [in] DWORD_PTR dwContext
> );
> ```

接著程式會透過 `GetComputerNameA` 和 `GetAdapterNameA` 獲取主機的名稱和 IP。並透過格式化字串將電腦名稱和 IP 組合在一起,計算完資料長度後便開始進行加密。


進入加密的 loop 前,可以看到是用 xor 對字串進行加密的。可以在 `rsp + 0x48` 看到密鑰。就是剛剛 `rand` 計算完被放在 `rsi` 的值 `0x02E46122` 只不過是用 little endianness 存放的,所以密鑰會是 `0x2261E402`。在加密完主機資訊後,會把密文寫入 `output.txt`。啊後面就結束了。

所以在已知密鑰的情況下,解密就會變得很容易。當然自己寫腳本也是完全可以的,那我就用自己寫的腳本解密。
> [!Note]
> 腳本:[yuto0226/xor](https://github.com/yuto0226/xor)

所以被偷資料的 David 他的 IP 就是 `210.122.39.33`。
```
Computer Name: DAVID
IP Address: 210.122.39.33
```