# T5Camp 2025 惡意程式分析 ###### tags: `malware`, `資安` ###### author: `ywc` [toc] ## 答題整理 (TLDR) ### 答題重點 - 分析相關樣本 - 詳見樣本分析部分 - 受害者觸發惡意程式的方式 - 透過 decoy file,使受害者誤執行一個偽裝成資料夾的 `Draft_PSC_planning_MARCH_quarterly_planning.exe` - `Draft_PSC_planning_MARCH_quarterly_planning.exe` 將其資料區段內容進行 xor 解密,並作為檔案內容寫入 `adobe_wf.exe`, `libcef.dll`, `IntelCPHS.docx`, `IntelGFXCoin.docx` 檔案中,最後使用 ShellExecuteA API 呼叫 explorer 執行 `adobe_wf.exe` 程式 - `adobe_wf.exe` 程式利用 DLL sideloading 帶起同目錄下惡意的 `libcef.dll`,並執行其 `cef_api_hash` 函式 - `libcef.dll` 將 `IntelCPHS.docx` 和 `IntelGFXCoin.docx` 內容進行 xor 解密,寫入 `WinDbg.exe` 和 `coreclr.dll` 檔案中,並使用 schedule task 排程每兩分鐘嘗試執行 `WinDbg.exe` 程式 - `WinDbg.exe` 程式利用 DLL sideloading 帶起同目錄下惡意的 `coreclr.dll`,並執行其 `GetCLRRuntimeHost` 函式 - `coreclr.dll` 檢查並使用 exception handling 機制跳轉到 handler 函式中,將資料區段中的 shellcode 用 xor 解密後放入 VirtualAllocEx 創建的 RWX 空間中,並呼叫執行 shellcode - 惡意程式族群 - `TONEDROP` + `TONESHELL` varient b - 樣本編譯時間 + 推測攻擊時間 - `Draft_PSC_planning_MARCH_quarterly_planning.exe`: 2020/01/10 - `adobe_wf.exe` (benign): 2021/11/29 - `libcef.dll`: 2023/02/13 - `Windbg.exe` (benign): 2018/10/24 - `coreclr.dll`: 2022/09/21 - 根據 decoy file、相關樣本等,推測攻擊時間在 2023/02/13 ~ 2023/03/07 之間 - Decoy 檔案 - `Draft_PSC_planning_MARCH.pdf` - 使用 icon 偽裝成資料夾的 `Draft_PSC_planning_MARCH_quarterly_planning.exe` - C2 - `212.114.52.210:443` - 常駐方式 - 在 `libcef.dll` 中,使用 schedule task 設定每兩分鐘嘗試執行一次 `Windbg.exe` - 相關 traffic - ping send ![](https://hackmd.io/_uploads/S1ay9vhMkx.png) - ping response ![](https://hackmd.io/_uploads/B1zZcDnz1e.png =400x) - 一般通訊 ![](https://hackmd.io/_uploads/HJiB9Pnzyx.png =400x) - 當 create TOnePipeShell 發生錯誤時的回傳訊息 ![](https://hackmd.io/_uploads/B1WO5P3Mkl.png) - 其他你認為重要或者覺得有用的資訊 - 相關混淆工具: [Tai7sy/vs-obfuscation](https://github.com/Tai7sy/vs-obfuscation/blob/master/obfuscation.h) - 相似惡意程式檢測資料: [Sha256: ... - LevelBlue - Open Threat Exchange](https://otx.alienvault.com/indicator/file/7cc2a21bcb3d58c2c82cee3e6b97c34aff1892d52658ecb5d10659c266c53b16) - 疑似 malware 開發者的姓氏 ![image](https://hackmd.io/_uploads/HyeneBSWJg.png =400x) ### 分析受害/攻擊者身分 - 受害國家 - `歐盟` - 攻擊族群 - `Earth Preta` (`MUSTANG PANDA`) ### 加分題 - Payload decoding/decryption algorithm - 基本上都是使用 xor 進行加解密,除了 `coreclr.dll` 解密 shellcode 的方式是 xor 加解密的變體,如下所示 ```python for i in range(0x6000): dec_shellcode += bytes([enc_shellcode[i] ^ key[k_i]]) if (k_i == 0x20 - 1): k_i = 0 k_i += 1 ``` - Malware obfuscation techniques - 在 `libcef.dll`, `coreclr.dll` 部分,部分字串會先進行 xor 加密後,再使用相同的 xor key 進行解密 - 在 `coreclr.dll` 部分,使用 exception handling 進行控制流轉移 - 在 shellcode 部分,使用自訂的 hash function 進行 module 和函式名稱的查詢 - Config offset + decoding method - 不清楚這是指什麼,但相關 payload offset 請詳見樣本分析部分 - Capability - 詳見樣本分析部分 - 其他視情況/細節給分 - 詳見樣本分析部分 ## 樣本分析 此樣本有兩個檔案,分別是 `Draft_PSC_planning_MARCH.pdf` 和 `Draft_PSC_planning_MARCH_quarterly_planning.exe`,以下會將這兩個檔案和延伸的部分嘗試進行完整的分析 ### Draft_PSC_planning_MARCH.pdf > Filetype: `pdf` > Hash (MD5): `6a33fc4b0428b8fd420790a895f2294a` > Date Modified: `2023/03/07` 該檔案是一個 decoy file,檔案內容如下 ![image](https://hackmd.io/_uploads/SJXwdPig1l.png) 可以看到這是一個類似內部行事曆的內容,行事曆的月份是 2023 年的 3 月,在行事曆中可以看到與一個叫做 PSC 的組織有關,且內容可以看到有烏俄戰爭、歐盟議會等等 透過基本的搜尋,可以找到一個叫做 [Political and Security Committee (PSC)](https://www.consilium.europa.eu/en/council-eu/preparatory-bodies/political-security-committee/) 的歐盟組織,推測為該樣本的攻擊目標 ### Draft_PSC_planning_MARCH_quarterly_planning.exe > Filetype: `PE 32bit` > Hash (MD5): `6cc47b9fc19c67b4c61aa2173f4c8b47` > Date Modified: `2023/03/07` ![image](https://hackmd.io/_uploads/B1uY2Psxyg.png) 該檔案是一個使用資料夾 icon 的一個 PE 32bit exe 檔案,推測觸發該執行檔的方式為誤導受害者以為它是 decoy file 的附件,雙擊開啟後觸發執行 以下是使用 Detect It Easy (DIE) 工具偵測出的開發工具環境,推測攻擊者使用 Visual Studio 進行惡意程式的開發及編譯 ![image](https://hackmd.io/_uploads/H1zwRDolye.png =500x) 在 PE 的 IMAGE_FILE_HEADER 中可以看到 TimeDateStamp 記載著執行檔的編譯時間為 `2020/01/10 19:14:33` ![image](https://hackmd.io/_uploads/r1EQWdjl1l.png =500x) 以上部分為檔案的基本資訊,接下來會使用 IDA 反編譯工具進行更詳細的分析 --- 在 main 函式中,可看到一開始該程式會嘗試建立 `C:\Programdata\LuaJIT` 的資料夾,不過後續沒有使用該資料夾,推測是用來偵測是否曾被感染過避免二次感染主機 (類似 mutex 的功能) ![image](https://hackmd.io/_uploads/rkZ1Hdsxyg.png =500x) 而透過搜尋該資料夾名稱,可以找到 [Behind the Scenes: Unveiling the Hidden Workings of Earth Preta](https://www.trendmicro.com/en_us/research/23/f/behind-the-scenes-unveiling-the-hidden-workings-of-earth-preta.html) 這篇報告,提及 TONEDROP family 會使用該名稱資料夾作為是否感染過的判斷,因此可以初步推斷該惡意程式可能是 TONEDROP 類型 (而後續的一些分析可以更加確定這一點) --- 在建立資料夾的下一步,該惡意程式會做一些 anti-debugging 的行為,首先會檢查 process list 中是否含有一些已知的分析程式如 cheatengine、IDA、x64dbg、procmon 等存在 (`sub_401000`,下二圖),假如前項通過後還會使用 FindWindowW API 再檢查是否有一些 debugger 常見的視窗名稱存在 (下一圖),避免分析人員修改分析工具執行檔名稱繞過第一項檢查 ![image](https://hackmd.io/_uploads/B1-_tOolyx.png =400x) ![image](https://hackmd.io/_uploads/Sko5KusgJg.png =400x) --- 下一步,該惡意程式會將 data section 中的四個位置分別做 xor 解密,並將解密的 payload 寫入到 `C:\users\public\` 資料夾下的各檔案中,解密金鑰為 `b7eb9f9e922473a27010e42da25be9d14f9e0df8e9aebddb3f9f50863a249ee47ff0cbf01ca65d9458ac7bd35cb202b3e54b7172cac6c2aa90a9a967cb182fdc` (註: 非 16 進位資料,純文字進行解密),被加密 payload 的位置、大小、寫入檔案資訊整理如下 | offset (dynamic VA) | size | filename | |:-------------------:|:-------:|:-----------------:| | 0x585538 | 0x636D8 | adobe_wf.exe | | 0x4D2D38 | 0xB2800 | libcef.dll | | 0x454738 | 0x7E600 | IntelCPHS.docx | | 0x41A8B0 | 0x39E88 | IntelGFXCoin.docx | ![image](https://hackmd.io/_uploads/rkly3djgJx.png) ![image](https://hackmd.io/_uploads/H1XNhuslyg.png =500x) 一個簡單的解密腳本如下 ```python= metadata = [ {"offset": 0x585538, "length": 0x636D8, "name": "adobe_wf.exe"}, {"offset": 0x4D2D38, "length": 0xB2800, "name": "libcef.dll"}, {"offset": 0x454738, "length": 0x7E600, "name": "IntelCPHS.docx"}, {"offset": 0x41A8B0, "length": 0x39E88, "name": "IntelGFXCoin.docx"}, ] data_dynamic_va = 0x41a000 data_static_va = 0x18e00 enckey = b"..." # Ignore size too long. See report. with open("Draft_PSC_planning_MARCH_quarterly_planning.exe", "rb") as fh: for meta in metadata: fh.seek(meta["offset"] - data_dynamic_va + data_static_va) data = fh.read(meta["length"]) decrypted = bytes([d ^ enckey[i % 128] for i,d in enumerate(data)]) with open(meta["name"], "wb") as ofh: ofh.write(decrypted) ``` --- 在此惡意程式的最後一步,他會呼叫 `sub_4011B0` 函式,該函式會使用 kernel32 的 LoadLibraryW API 載入 User32 和 Shell32,並使用 Shell32 的 ShellExecuteA API 呼叫 explorer 執行 `adobe_wf.exe` 程式 ![image](https://hackmd.io/_uploads/SkPCgYjxJg.png) ### adobe_wf.exe > Filetype: `PE 32bit` > Hash (MD5): `c751af3a2b5e5085e0cf4a66a09480d9` 此程式是由前項惡意程式解密並寫入檔案系統後,自動帶起的一個程式 以下是使用 DIE 工具偵測出的開發工具環境,可以看到該程式也是由 Visual Studio 所開發,另外也可發現該程式帶有簽章 ![image](https://hackmd.io/_uploads/r1JaOTslkl.png =500x) 在 IMAGE_FILE_HEADER 中的 TimeDateStamp 可以看到該執行檔的編譯時間為 `2021/11/29 22:04:25` ![image](https://hackmd.io/_uploads/H1LaFToxyg.png =500x) 在簽章內容中可看出是由 `Adobe Inc.` 所簽發,且簽章合法,代表它是一個正常的執行檔 ![image](https://hackmd.io/_uploads/ryArYTsxyg.png =500x) ![image](https://hackmd.io/_uploads/By-OY6sxkg.png =500x) 而由於它是一個正常的執行檔,照理說不會有惡意行為,不過由於前項惡意程式在該執行檔的相同目錄中同樣也產生了一個 `libcef.dll` 檔案,因此可以假定此執行檔執行時有載入 `libcef.dll` 的行為,但因為 DLL sideloading 的關係載入的不是系統中的 `libcef.dll` 而是同目錄下的 `libcef.dll`,真正的惡意攻擊行為是藏在該 DLL 中 --- 為了驗證前項假設,可以嘗試用 IDA 分析工具嘗試進行分析 首先在執行檔中的 Import Address Table (IAT) 中可看到該程式確實會進行 `libcef.dll` 的載入 ![image](https://hackmd.io/_uploads/Bkig06oxJl.png =500x) 在觸發 `libcef.dll` 惡意攻擊行為的部分,在 `WinMain` 函式中會呼叫 `sub_405ED0` 函式,該函式會再呼叫 `libcef.dll` 中的 `cef_api_hash` 函式,執行惡意 DLL 中唯一 export 出來 (扣除 `DLLEntryPoint`) 的 `cef_api_hash` 函式 ![image](https://hackmd.io/_uploads/r1uSJ0jx1g.png) ![image](https://hackmd.io/_uploads/SJSOJColkl.png) ![image](https://hackmd.io/_uploads/SJep1AogJg.png =400x) > btw 這個執行檔的 pdb 資訊中可以看出 adobe 內部有使用 jenkins CI/CD 工具 :) > ![image](https://hackmd.io/_uploads/H19inBHgJx.png) ### libcef.dll > Filetype: `PE 32bit DLL` > Hash (MD5): `731826d52e6f3527786fe5cff48ef171` 首先一樣嘗試使用 DIE 工具分析該 DLL 的開發工具環境,不過沒有發現比較有用的資訊 ![image](https://hackmd.io/_uploads/ByQH80ol1l.png =500x) 在 IMAGE_FILE_HEADER 中的 TimeDateStamp 可以看到該 DLL 的編譯時間為 `2023/02/13 13:51:25` ![image](https://hackmd.io/_uploads/ry6K8Aox1x.png =500x) 以上部分為檔案的基本資訊,接下來會使用 IDA 工具進行更詳細的分析 --- 首先是 pdb 的部分如下,基本上看不出什麼有用的資訊,只知道是使用 debug mode 去編譯的 ![image](https://hackmd.io/_uploads/r1RlaHHeyg.png =400x) --- 如同 `adobe_wf.exe` 所述,該 DLL 除了有 `DLLEntryPoint` 之外,還有 export `cef_api_hash` 函式做為惡意行為的進入點,因此以下將以 `cef_api_hash` 作為起始進行分析 在該函式的一開始,除了一些基本的 `memset` 做資料初始化之外,最主要可以看到有一個 `kernel32.dll` 的字串的每個 byte 都進行 xor,而後在 79 行時又會對該字串再做一次 xor 運算,不過可以看出他的運算式是 (0x9ef2 + i) $\oplus$ (-0x610e + i),而 -0x610e 的二進位補數恰巧是 0x9ef2,因此該運算基本上等同於 xor 0,也就是該字串在運算完後的值就跟原本一樣,這是它的字串混淆方法,而除了 `kernel32.dll` 字串之外,在其他字串的部分也可以看到類似的混淆方法 ![image](https://hackmd.io/_uploads/SknUfkpeJg.png =500x) ![image](https://hackmd.io/_uploads/HJHdMJ6l1x.png) --- 忽略掉字串混淆的部分,該函式的第一個行為是使用 `kernel32.dll` 中的 `CreateEventA` 創建一個 `iygyjtfurt` 的 event,不過後續沒有到該 event,推測目的應該與先前分析的`Draft_PSC_planning_MARCH_quarterly_planning.exe` 的 `LuaJIT` 資料夾一樣是用來避免重複執行惡意行為 ![image](https://hackmd.io/_uploads/ry5CwBTxyl.png) ![image](https://hackmd.io/_uploads/SyqJur6e1x.png =500x) 另外在該部分取得 CreateEventA API 的地方使用 `sub_10007E50` 函式,而追蹤從 `sub_10007E50` -> `sub_10007F90` -> `sub_10007FF0` -> `sub_10007FF0` 最終可以看到一些字串訊息如 `DefWindowProcW1222_test`、`Find function HeapAlloc` 等 ![image](https://hackmd.io/_uploads/BkaatBpx1g.png =400x) ![image](https://hackmd.io/_uploads/B1zJ5STgyg.png =400x) ![image](https://hackmd.io/_uploads/rkVb5Hpg1g.png =500x) 透過搜尋引擎搜索這些字串,可以找到 [Tai7sy/vs-obfuscation](https://github.com/Tai7sy/vs-obfuscation/blob/master/obfuscation.h) 和 [Sha256: ... - LevelBlue - Open Threat Exchange](https://otx.alienvault.com/indicator/file/7cc2a21bcb3d58c2c82cee3e6b97c34aff1892d52658ecb5d10659c266c53b16) 這兩個連結,前者是一個混淆工具的 GitHub repo,且比對程式碼之後推測此惡意 DLL 有使用該工具進行字串混淆等行為。而在後者的部分,是一個有出現這些字串但是是其他惡意程式的檢測結果,該程式在 VirusTotal 上被偵測為 toneshell family,而這也更進一步支持目前分析樣本是 toneshell 相關 family 的一個判斷依據 ![image](https://hackmd.io/_uploads/B1_hnHTgkl.png =400x) --- 在建立 event 的下一步,該惡意 DLL 將 data 區段上的資料做 xor 解密,xor key 是 0x7d,資料位置及解密後的字串整理如下 | Address (dynamic VA) | Decrypted String | |:--------------------:|:-----------------------------------------:| | 0x100AD208 | C:\\Users\\Public\\Documents\\WinDbg.exe | | 0x100AD30C | C:\\Users\\Public\\Documents\\coreclr.dll | | 0x100AD000 | IntelGFXCoin.docx | | 0x100AD104 | IntelCPHS.docx | ![image](https://hackmd.io/_uploads/S1qiyL6ekx.png) ![image](https://hackmd.io/_uploads/Sk_3yITg1e.png) 可以看到,解密出來的資料似乎是檔案名稱,而可以看到在解密完的 `IntelGFXCoin.docx` 和 `IntelCPHS.docx` 字串中還會再透過 command line argument 中取得的當前執行目錄組合這兩個檔案名稱,將它們轉換成絕對路徑 --- 在下個階段,該惡意 DLL 透過 `wstrcat` 組合一串設定 schedule task 的指令,並在最後使用 CreateProcessW API 做執行 ![image](https://hackmd.io/_uploads/SkvzGL6gJe.png) ![image](https://hackmd.io/_uploads/HJjQz86gJg.png) ![image](https://hackmd.io/_uploads/B1aNG8Tgye.png) ![image](https://hackmd.io/_uploads/B1E8zLpxJx.png) ![image](https://hackmd.io/_uploads/HyvZm8Teyl.png) 該 schedule task 的完整指令為 `schtasks /create /sc minute /mo 2 /tn \"Windowstore\" /tr \"C:\\Users\\Public\\Documents\\WinDbg.exe\" /f`,用途是設定一個叫做 `Windowstore` 的工作,每兩分鐘會嘗試執行 `WinDbg.exe`,而下個階段可以看到該檔案是用於下一階段的惡意行為執行,因此此部分是用於程式常駐使用 另外,在此階段時 schedule task 指令不是一次寫完而要使用字串串接方式進行,推測有部分原因是要規避防毒軟體偵測,不過我認為最大的原因是方便攻擊族群直接抽換關鍵偵測字串如 task name、執行檔名稱等,在針對該惡意行為的偵測規則被生成出來之後可以方便的替換掉,使規則失效 --- 在下個階段,該 DLL 呼叫了 `decryptAndCopyfile_100013E0` 函式進行解密檔案和複製的行為 ![image](https://hackmd.io/_uploads/S1f3qUaxkx.png) 在該函式中,第一步會使用 CreateFileW API 以讀取模式開啟檔案 ![image](https://hackmd.io/_uploads/rkz1iIpe1x.png) 第二步會使用 GetFileSize API 讀取原始檔案的大小,分配適當的空間 ![image](https://hackmd.io/_uploads/SyIgs8peJx.png) 第三步會用 ReadFile API 做檔案資料讀取 ![image](https://hackmd.io/_uploads/S1S-iU6xJx.png) 而第四步會將讀取的資料做 xor 解密,而解密金鑰是由傳入的第三個參數決定是 0x36 或 0x2d,在此例中 `IntelGFXCoin_docx` 會使用 0x36 而 `IntelCPHS_docx` 則使用 0x2d ![image](https://hackmd.io/_uploads/r1fMj8Tlye.png =500x) ![image](https://hackmd.io/_uploads/SkFQsLagJg.png =500x) ![image](https://hackmd.io/_uploads/ByINjI6eye.png =500x) 最後一步,創建新的檔案,並將解密後的資料進行寫入 ![image](https://hackmd.io/_uploads/HyVua86eke.png) 以下是一個簡單的解密腳本 ```python metadata = [ {"xorkey": 0x36, "srcname": "IntelGFXCoin.docx", "dstname": "Windbg.exe"}, {"xorkey": 0x2d, "srcname": "IntelCPHS.docx", "dstname": "coreclr.dll"}, ] for meta in metadata: with open(meta["srcname"], "rb") as fh: data = fh.read() decrypted = bytes([d ^ meta["xorkey"] for d in data]) with open(meta["dstname"], "wb") as ofh: ofh.write(decrypted) ``` --- 在最後的階段,該 DLL 會先使用 GetCurrentProcess API 取得當前的 process handle,並使用 TerminateProcess 結束程式執行 ![image](https://hackmd.io/_uploads/SkIEOUpgyg.png) ### Windbg.exe > Filetype: `PE 32bit` > Hash (MD5): `17e40315660830aa625483bbf608730c` 此程式是由前項惡意 DLL 程式解密後,透過 schedule task 帶起的一個程式 以下是使用 DIE 工具偵測出的開發工具環境,可以看到該程式也是由 `Visual Studio` 所開發,另外與 `adobe_wf.exe` 相同,可發現該程式帶有簽章 ![image](https://hackmd.io/_uploads/H1N2OtReyl.png =500x) 在 IMAGE_FILE_HEADER 中的 TimeDateStamp 可以看到該執行檔的編譯時間為 `2018/10/24 10:23:21` ![image](https://hackmd.io/_uploads/HJObYY0e1g.png =500x) 在簽章內容中可看出是由 `Mircosoft Corporation` 所簽發,且簽章合法,代表它是一個正常的執行檔 ![image](https://hackmd.io/_uploads/SyZlOF0lyx.png =500x) ![image](https://hackmd.io/_uploads/BJ4muFAxkl.png =500x) 與 `adobe_wf.exe` 類似,既然它是一個正常的執行檔就應該不會有惡意行為,而在前面的 DLL 惡意行為中有在該執行檔的同目錄下寫入一個 `coreclr.dll`,因此推測應該也是利用 DLL sideloading 技巧載入該 DLL 後才觸發惡意行為,惡意攻擊行為藏在該 DLL 中 --- 為了驗證前項假設,可以嘗試用 IDA 分析工具嘗試進行分析 與 `adobe_wf.exe` 不同,該執行檔的 IAT 中並沒有看到 `coreclr.dll` 的載入 不過,從 `WinMain` -> `sub_406780` -> `sub_409510` -> `sub_40B690` 的 function call chain 中,可以發現在 `sub_40B690` 中使用了 LoadLibraryW API 進行 `coreclr.dll` 的載入,並呼叫 `GetCLRRuntimeHost` 函式 ![image](https://hackmd.io/_uploads/BkH-hgk-1g.png =400x) ![image](https://hackmd.io/_uploads/SysH2lkWkx.png =500x) ![image](https://hackmd.io/_uploads/rJyF3e1Z1l.png =300x) ![image](https://hackmd.io/_uploads/HJFjhlJbkx.png) 而在 `coreclr.dll` 的 export table 中確實存在該函式,推測應該是惡意行為的進入點 ![image](https://hackmd.io/_uploads/HJev6e1-yg.png =400x) ### coreclr.dll > Filetype: `PE 32bit DLL` > Hash (MD5): `984b7abf11cf6a13ccd3b99e8f437397` 首先一樣嘗試使用 DIE 工具分析該 DLL 的開發工具環境,不過與惡意的 `libcef.dll` 一樣沒有發現比較有用的資訊 ![image](https://hackmd.io/_uploads/H1jkjt0g1l.png =500x) 在 IMAGE_FILE_HEADER 中的 TimeDateStamp 可以看到該 DLL 的編譯時間為 `2022/09/21 14:21:58` ![image](https://hackmd.io/_uploads/HkLAqYAgkx.png =500x) 以上部分為檔案的基本資訊,接下來會使用 IDA 工具進行更詳細的分析 --- 如同 `Windbg.exe` 所推測,該 DLL 的惡意行為進入點為 `GetCLRRuntimeHost`,因此以下將以該函式作為起始點進行分析 首先,在 `GetCLRRuntimeHost` 中,會直接呼叫 `sub_10002D00` 函式 ![image](https://hackmd.io/_uploads/SJZ0UtMZJg.png =400x) 在 `sub_10002D00` 中,最一開始會看到有出現類似 `libcef.dll` 中的字串混淆方式 ![image](https://hackmd.io/_uploads/BJ81AXSWke.png) 忽略掉字串混淆的部分,該函式的第一步是使用 CreateEventA API 建立一個名為 `ydgffsrbtyt5ster` 的 event,推測應該也是用於確保不要重複感染系統 ![image](https://hackmd.io/_uploads/SyOVJVHWkg.png) ![image](https://hackmd.io/_uploads/rynJgESbJe.png =400x) --- 下一步,會先使用 GetModuleFileNameA API 取得當前執行檔的位置,並與一個 xor 解密後的字串做比較,相同的話會進入下方區塊,否則進入上方區塊 ![image](https://hackmd.io/_uploads/r1j-WVS-Jx.png) xor 解密的金鑰為 0x7e,解密後的字串為 `C:\\Users\\Public\\Documents\\WinDbg`,可以看到解密後的字串與 `libcef.dll` 段落描述的寫檔路徑相同,而一般來說對於惡意程式動態分析而言,通常會將程式置於沙箱中,因此程式路徑會有所改變,可推測此處檢查是為了避免沙盒動態分析 --- 在上一步中,程式分成兩條路線,不過二者都呼叫了 `sub_1000B410` 只是所帶的參數不同 而在 `sub_1000B410` 函式中,雖然中間部分看起來很複雜,但是基本上看起來是觸發 exception handling 的部分 ![image](https://hackmd.io/_uploads/BkMXdErZkl.png =400x) 而觀察二者帶入的參數,可透過第二個參數推測出正確的 exception handler 位置 在路徑比對不一致的區塊中 (上方區塊),第二個參數帶入 `0x10049464`,因此透過下方的 reference 關係得出 handler 位置為 `0x10004770` ![image](https://hackmd.io/_uploads/B1Tr9ErW1e.png =500x) ![image](https://hackmd.io/_uploads/S1qdqEBZ1g.png =500x) 而路徑比對一致的區塊中 (下方區塊),第二個參數帶入 `0x100494A4`,因此透過下方的 reference 關係得出 handler 位置為 `0x10005470` ![image](https://hackmd.io/_uploads/r1jZjVB-Jg.png =500x) ![image](https://hackmd.io/_uploads/ByBQsESbye.png =500x) --- 由於已知程式會進行路徑的檢查並分成兩條路線,因此此處將著重在路徑比對一致的 exception handler 函式分析 在此函式中,首先會先使用 GetCurrentProcess API 取得當前的 process handler,並結合 VirtualAllocEx API 在該 process 中創建一個 0x6000 大小的記憶體空間,權限為可讀、寫和執行 ![image](https://hackmd.io/_uploads/rJsv72wM1x.png =500x) ![image](https://hackmd.io/_uploads/HyYBNhPGkl.png) 當創建記憶體空間後,會先將 `0x1004b000` 位置的資料用 `0x7e` 做 xor 解密,並將解密後的字串作為 xor key 並再與 `0x1004B021` 位置 0x6000 bytes 大小的資料做 xor 解密,解密後的資料會複製進 VirtualAllocEx API 創建的記憶體空間中,並進行執行 因此,我們可知 `0x1004b000` 位置的資料是加密後的 xor key,該 xor key 的解密金鑰為 `0x7e`,而 `0x1004B021` 則很可能是加密後的 shellcode 值得一提的是,進行 shellcode 解密的函式並非一般的 xor 解密函式,函式內容如下,在他的循環條件中可看到 `v4` 變數從一開始 0 ~ `str2_len - 1`,之後會先設定成 0 並馬上執行 `++v4` 的行為,因此接下來的循環中的 `v4` 變數會是 1 ~ `str2_len - 1` 的循環,並非從 0 開始 ![image](https://hackmd.io/_uploads/H1jdUnPf1e.png =500x) 以下是一個解密並提取 shellcode 的腳本,執行後可提取 shellcode 並進入下一步分析 ```python data_dynamic_va = 0x1004b000 data_static_va = 0x49200 enc_shellcode_addr = 0x1004B021 enc_key_addr = 0x1004B000 def xor(data, key): return bytes([d ^ key[i % len(key)] for i,d in enumerate(data)]) def shellcode_xor(enc_shellcode, key): dec_shellcode = b"" k_i = 0 for i in range(0x6000): dec_shellcode += bytes([enc_shellcode[i] ^ key[k_i]]) if (k_i == 0x20 - 1): k_i = 0 k_i += 1 return dec_shellcode with open("coreclr.dll", "rb") as fh: fh.seek(enc_shellcode_addr - data_dynamic_va + data_static_va) enc_shellcode = fh.read(0x6000) fh.seek(enc_key_addr - data_dynamic_va + data_static_va) enc_key = fh.read(32) key = xor(enc_key, b"\x7e") # shellcode = xor(enc_shellcode, key) shellcode = shellcode_xor(enc_shellcode, key) with open("coreclr_shellcode.bin", "wb") as ofh: ofh.write(shellcode) ``` --- 除了上面的執行流程之外,在此 DLL 中還可以發現一些類似中文姓氏的字串,推測可能為此惡意 DLL 開發者的署名 ![image](https://hackmd.io/_uploads/HyeneBSWJg.png =400x) ### shellcode 取得 shellcode 後,以下使用 [shcode2exe](https://github.com/accidentalrebel/shcode2exe) 工具將 shellcode 先轉換成 exe 的形式,以方便後續分析 在入口點的地方,會直接呼叫 `main_401090` 函式 ![image](https://hackmd.io/_uploads/ByxHhG2zkx.png) 在 `main_401090` 函式的初始化區塊中,可以看到有像是 IP 和 port 列表的資訊,推測應該是存放惡意程式的 C2 ![image](https://hackmd.io/_uploads/SJAWpz3z1l.png) 該函式的第一步會嘗試使用 `get_module_from_peb_401770` 函式從 PEB 資訊塊中找出一個特定的 module,帶入資料是一個自定義的 hash,他會將 PEB 中每個 module 的名稱做 hash 之後進行資料比對已找出特定的 module ![image](https://hackmd.io/_uploads/HymPH7hzkl.png) ![image](https://hackmd.io/_uploads/B1-GQQ2fyx.png =500x) hash 函式的內容如下 ![image](https://hackmd.io/_uploads/ByXHXQ3fJl.png =400x) 為了找出具體是要使用哪個 module,可以嘗試先取得載入的 module 資訊,並列舉計算 hash 並比對,可以發現他會取得 `kernel32.dll` module ![image](https://hackmd.io/_uploads/B1KGBQnzJe.png) 當取得 `kernel32.dll` 後,該函式會再透過列舉導出函式表的方式尋找特定的模組,並且也使用比對 hash 的方式進行查詢,而在此時它會先找出 GetProcAddress 和 LoadLibraryA API 的位置 ![image](https://hackmd.io/_uploads/rJjIxEhz1e.png) 而在 `loadFunctions_401900` 函式中,會透過先前找出的 LoadLibraryA 和 GetProcAddress 載入並取得更多 shellcode 所需的 API,他使用類似 function table 的結構進行儲存 ![image](https://hackmd.io/_uploads/H1kFQVnz1l.png) 當載入完函式後,該 shellcode 會建立並初始化一個自定義的結構,在此簡稱為 commblock,該結構的主要目的是方便管理通訊和訊息資訊 ![image](https://hackmd.io/_uploads/r1BGVN2GJl.png) 另外值得一提的是,在 `createCommblock_4026c0` -> `getCryptoContext_402930` 函式中會嘗試建立一個 `MyKeyContainer` crypto context,以用於後續亂數產生器的使用 ![image](https://hackmd.io/_uploads/HJugSN3Mkx.png) 在建立完 commblock 後,會進入到主要的 `doWork_4031E0` 函式 --- 在 `doWork_4031E0` 函式中,首先他會執行 `getComputerRandomNumber_402C10` 函式取得一個類似裝置序號的資訊,基本上是拿裝置電腦名稱、使用者名稱、硬碟序號資訊計算而成 ![image](https://hackmd.io/_uploads/HJhZUE2G1g.png) ![image](https://hackmd.io/_uploads/SyG5UE2Gyl.png =500x) 在取得裝置序號後,會執行一個 while true 無窮迴圈,而在迴圈中會嘗試遍歷 C2 IP list 和 port list,先將 IP 部分的 hostname 轉換成 IPv4 形式,並將轉換後的 IP 和 port 嘗試建立 socket ![image](https://hackmd.io/_uploads/HymVDVnGJx.png =500x) 在建立 socket 後,會嘗試進行一次 pingpong 通訊以確認受害者與 C2 間網路通訊正常,確認正常後會呼叫 `communicate_402B10` 函式做後續的溝通行為 `pingPong_402DB0` 函式的內容如下 ![image](https://hackmd.io/_uploads/SJyfqE3Mye.png =500x) ![image](https://hackmd.io/_uploads/r1xDqV2MJl.png =500x) ![image](https://hackmd.io/_uploads/r1rdqV3f1x.png =400x) 從反組譯程式碼中,可以看出相關的封包結構,首先受害者電腦端會送出以下的封包,可以看到傳送了訊息類別 0x2 的資料 ![](https://hackmd.io/_uploads/BkgPgS2zkg.png) 而 C2 預期會回傳以下封包,可以看到收到了訊息類別 0x1 的資料 ![](https://hackmd.io/_uploads/r1zSZrnzJg.png) --- 在 `communicate_402B10` 函式中,首先可以看到 shellcode 會先用 CreateThread 生成一個新的 thread,而後會不斷的嘗試從一個類似 linked list 的 PIPE 結構中取得要傳送的 message,嘗試進行傳送並取得回應 ![image](https://hackmd.io/_uploads/B1KHornz1x.png =500x) 在 `sendMsgAndRecv_4035E0` 函式中,會呼叫 `sendAndRecv_404350` 進行資料的接收,並會根據回傳的訊息類別進行 buffer 大小的檢查,當 buffer 大小符合預期,會將訊息塞入另一個接收用的 PIPE ![image](https://hackmd.io/_uploads/HkbHXL2G1x.png) `sendAndRecv_404350` 函式的內容如下,基本上與 pingpong 的程式碼相似,不過可以看到多了 `prepare_sendbuf_404230` 和 `recv_and_decode_4044E0` 函式 ![image](https://hackmd.io/_uploads/HkmBNLnzke.png) 在 `prepare_sendbuf_404230` 和 `recv_and_decode_4044E0` 函式的程式碼中可以觀察到,在前面 pingpong 時傳送封包中空白的部分是一些隨機產生的資料,主要用途是作為封包資料的 xor key ![image](https://hackmd.io/_uploads/B1L1BLnzkx.png =400x) ![image](https://hackmd.io/_uploads/SJ3-rUhzJx.png =400x) 因此,綜合以上觀察,可以發現一般通訊下伺服器回傳的封包格式如下 ![](https://hackmd.io/_uploads/rymCv8nMkg.png =500x) 而根據相關資料,可以推測該 shellcode 應該是 toneshell varient b 的形式 --- 而回顧 `communicate_402B10` 函式,他會生成另一個 thread,thread handler 如下所示 ![image](https://hackmd.io/_uploads/Hymm9Uhfkx.png =400x) 可以看到,它會不斷的嘗試從接收的 PIPE 取得訊息,當有訊息時會執行 `doCommand_404700` 函式 --- 在 `doCommand_404700` 函式中,可以看到它會根據接收的訊息類別進行相對應的行為,對應的行為可以從其錯誤訊息字串中觀察到 ![image](https://hackmd.io/_uploads/HJ8bsI3Gke.png) ![image](https://hackmd.io/_uploads/r1EfoU2G1x.png) 以下是整理出的訊息類別和對應的行為 | type | behavior | ret code | |:----:|:--------------------------------------:|:--------:| | 0x3 | create TOnePipeShell | | | 0x9 | cleanup TOnePipeShell | | | 0xa | cleanup TOnePipeShell | | | 0xb | stop execution | | | 0x4 | upload file begin (create file) | 0x6 | | 0x5 | upload file write (write file) | 0x7 | | 0x6 | upload file end (write and close file) | 0x8 | | 0x7 | upload file cancel (delete file) | | 此外在 Upload file 相關訊息類別部分,可以觀察到會將執行狀態回傳給 C2 伺服器,正常執行狀態碼資訊列於上表中,如遇到異常狀態,則回應狀態碼 0xa 並將錯誤訊息置於資料欄位中 最後是 create TOnePipeShell 發生錯誤的情況,則會傳輸以下封包內容,資料區段為錯誤訊息部分 ![](https://hackmd.io/_uploads/SJBnFP2f1e.png)