**遠端執行緒注入** 是 Windows 進程間最經典的「越界」技術:在目標進程建立執行緒,載入指定 DLL,從而獲得該進程的完整存取權限。本文從 API 流程、記憶體佈局、實戰代碼到安全防禦全方位剖析,**僅供安全研究與防禦理解,嚴禁用於惡意用途。**
PROCESS_CREATE_THREAD | PROCESS_VM_OPERATION | PROCESS_VM_WRITELoadLibraryW 為起始位址、DLL 路徑為參數,在目標進程建立執行緒 → 觸發 DLL 載入
// 1. 取得目標進程 PID (如透過 ToolHelp32 遍歷或 FindWindow+GetWindowThreadProcessId)
DWORD dwPID = GetTargetPID(L"notepad.exe");
// 2. 開啟進程
HANDLE hProc = OpenProcess(PROCESS_CREATE_THREAD | PROCESS_VM_OPERATION | PROCESS_VM_WRITE, FALSE, dwPID);
if (!hProc) return ERROR_ACCESS_DENIED;
// 3. 計算 DLL 路徑寬字串長度並分配遠端記憶體
wchar_t dllPath[] = L"C:\\Inject\\MyHook.dll";
SIZE_T cb = (wcslen(dllPath) + 1) * sizeof(wchar_t);
LPVOID pRemotePath = VirtualAllocEx(hProc, NULL, cb, MEM_COMMIT, PAGE_READWRITE);
if (!pRemotePath) { CloseHandle(hProc); return ERROR_OUTOFMEMORY; }
// 4. 寫入路徑
if (!WriteProcessMemory(hProc, pRemotePath, dllPath, cb, NULL)) {
VirtualFreeEx(hProc, pRemotePath, 0, MEM_RELEASE);
CloseHandle(hProc); return ERROR_WRITE_FAULT;
}
// 5. 取得 LoadLibraryW 位址 (Kernel32 在所有進程基址相同,ASLR 前提下需額外處理)
FARPROC pLoadLib = GetProcAddress(GetModuleHandle(L"kernel32.dll"), "LoadLibraryW");
// 6. 建立遠端執行緒
HANDLE hThread = CreateRemoteThread(hProc, NULL, 0,
(LPTHREAD_START_ROUTINE)pLoadLib, pRemotePath, 0, NULL);
if (!hThread) {
VirtualFreeEx(hProc, pRemotePath, 0, MEM_RELEASE);
CloseHandle(hProc); return GetLastError();
}
// 7. 等待執行緒結束並清理
WaitForSingleObject(hThread, INFINITE);
DWORD exitCode; GetExitCodeThread(hThread, &exitCode); // exitCode 為 DLL 基址或 0
CloseHandle(hThread);
VirtualFreeEx(hProc, pRemotePath, 0, MEM_RELEASE);
CloseHandle(hProc);
| 環節 | 陷阱 | 對策 |
|---|---|---|
| 權限 | 目標進程以較高完整性等級運行 (如系統服務、管理員提權) | 注入端需同等或更高權限,或利用 Token 竊取/提權漏洞 |
| ASLR | Kernel32 基址隨機化導致 LoadLibraryW 位址不固定 | x64 下通常共用基址;若不固定需先注入 Shellcode 解析匯出表 |
| 位數不匹配 | 32 位注入器注入 64 位進程 (或反向) | 注入器與目標**位數必須一致** (WoW64 除外) |
| DLL 依賴 | 注入 DLL 依賴其他 DLL 且路徑不在目標進程搜尋順序 | 使用完整路徑、延遲載入、或預先將依賴放入系統目錄 |
| 防毒/EDR 攔截 | CreateRemoteThread 是高危行為特徵 | 合法軟體應簽名、走驅動層回調、或改用 Hook/AppInit_DLLs 等替代方案 |
BOOL APIENTRY DllMain(HMODULE hMod, DWORD reason, LPVOID) {
if (reason == DLL_PROCESS_ATTACH) {
wchar_t msg[64]; swprintf(msg, 64, L"Injected! PID=%u", GetCurrentProcessId());
MessageBox(NULL, msg, L"RemoteDLL", MB_OK);
}
return TRUE;
}
注入後彈窗顯示目標 PID,Process Explorer 可見 DLL 已載入目標模組列表。
PsSetCreateThreadNotifyRoutine / PsSetLoadImageNotifyRoutine,監控異常 CreateRemoteThread 與非預期 DLL 載入CreateRemoteThread、WriteProcessMemory,記錄呼叫堆疊與參數CreateRemoteThread 注入是 Windows 進程架構開放性的必然產物。**理解其機制,不是為了攻擊,而是為了建立更堅固的防線**。現代 Windows (10/11) 配合 VBS/HVCI、CET、ACG 等硬體輔助防護,已大幅提升注入門檻。作為開發者,應優先選擇 **文檔化的擴充點** (如 COM 擴充、驅動回調、ETW Provider) 而非灰色地帶技術;作為防禦者,持續更新威脅情報、部署行為分析、啟用核心隔離,才是正道。