進(jìn)程注入是一種廣泛使用的躲避檢測(cè)的技術(shù),通常用于惡意軟件或者無(wú)文件技術(shù)。其需要在另一個(gè)進(jìn)程的地址空間內(nèi)運(yùn)行特制代碼,進(jìn)程注入改善了不可見(jiàn)性,同時(shí)一些技術(shù)也實(shí)現(xiàn)了持久性。盡管目前有許多進(jìn)程注入技術(shù),但在這篇文章中,我將會(huì)介紹十種在野發(fā)現(xiàn)的,在另一個(gè)程序的地址空間執(zhí)行惡意代碼的進(jìn)程注入技術(shù),并提供這些技術(shù)應(yīng)用的截圖,以便于逆向工程和惡意軟件分析,然后協(xié)助檢測(cè)并防御這些進(jìn)程注入技術(shù)。
一、通過(guò)CREATEREMOTETHREAD和LOADLIBRARY進(jìn)行經(jīng)典DLL注入
該技術(shù)是用于將惡意軟件代碼注入另一個(gè)進(jìn)程最常用技術(shù)之一,惡意軟件作者將惡意的動(dòng)態(tài)鏈接庫(kù)(DLL)的路徑寫(xiě)入另一個(gè)進(jìn)程的虛擬地址空間,并通過(guò)在目標(biāo)進(jìn)程中創(chuàng)建一個(gè)遠(yuǎn)程線程來(lái)確保目標(biāo)進(jìn)程加載它。
惡意軟件首先需要選擇被注入的目標(biāo)進(jìn)程(例如svchost.exe),這通常可以通過(guò)調(diào)用三個(gè)應(yīng)用編程接口(API)搜索進(jìn)程來(lái)完成:CreateToolhelp32Snapshot,Process32First和Process32Next。CreateToolhelp32Snapshot是用于枚舉指定進(jìn)程或所有進(jìn)程的堆或模塊狀態(tài)的API,其會(huì)返回一個(gè)快照。Process32First會(huì)檢索有關(guān)快照中第一個(gè)進(jìn)程的信息,然后通過(guò)循環(huán)Process32Next來(lái)迭代。找到目標(biāo)進(jìn)程后,惡意軟件通過(guò)調(diào)用OpenProcess獲取目標(biāo)進(jìn)程的句柄。
如圖一所示,惡意軟件調(diào)用VirtualAllocEx來(lái)獲得寫(xiě)入其DLL路徑的空間。然后惡意軟件調(diào)用WriteProcessMemory在已分配的內(nèi)存中寫(xiě)入路徑。最后,為了讓代碼在另一個(gè)進(jìn)程中執(zhí)行,惡意軟件作者會(huì)調(diào)用API,例如CreateRemoteThread,NtCreateThreadEx或RtlCreateUserThread。后兩個(gè)并未存在應(yīng)用記錄,但是一般的想法就是將LoadLibrary的地址傳遞給其中一個(gè)API,以便遠(yuǎn)程進(jìn)程不得不代表惡意軟件執(zhí)行DLL。
很多殺毒軟件都會(huì)追蹤和標(biāo)記CreateRemoteThread,此外,注入也需要磁盤(pán)上存在惡意DLL。但這是可以被檢測(cè)到的。考慮到攻擊者最常通過(guò)注入代碼以逃避檢測(cè),所以一些老練的攻擊者可能并不會(huì)使用這種方法。下面的截圖展示了一個(gè)叫Rebhip的惡意軟件應(yīng)用了此技術(shù)。
二、PORTABLE EXECUTABLE注入(PE注入)
這種技術(shù)斌沒(méi)有傳遞LoadLibrary的地址,而是將其惡意代碼復(fù)制到已存在的開(kāi)放進(jìn)程并執(zhí)行(通過(guò)shellcode或調(diào)用CreateRemoteThread)。PE注入相對(duì)于LoadLibrary注入的一個(gè)優(yōu)點(diǎn)是惡意軟件不必在磁盤(pán)上放一個(gè)惡意DLL。與第一種技術(shù)類(lèi)似,惡意軟件在宿主進(jìn)程中分配到內(nèi)存,其并沒(méi)有編寫(xiě)“DLL路徑”,而是通過(guò)調(diào)用WriteProcessMemory來(lái)編寫(xiě)其惡意代碼。然而,這種方法的一個(gè)缺陷是目標(biāo)基址的改變,當(dāng)惡意軟件將其PE注入到另一個(gè)進(jìn)程時(shí),其會(huì)有一個(gè)新的不可預(yù)測(cè)的基址,這就要求其動(dòng)態(tài)地重新計(jì)算PE的地址。為了解決這個(gè)問(wèn)題,惡意軟件需要在宿主進(jìn)程中找到其重定位表地址,并通過(guò)循環(huán)其重定位描述符來(lái)解析絕對(duì)地址。
此技術(shù)類(lèi)似于其他技術(shù),例如反射式DLL,因?yàn)樗鼈儾粫?huì)將任何文件放在磁盤(pán),但是,反射式DLL注入方法甚至?xí)与[蔽。它們不依賴(lài)于任何額外的Windows API(例如CreateRemoteThread或LoadLibrary),因?yàn)樗鼈冊(cè)趦?nèi)存中加載和執(zhí)行自己。反射式DLL注入通過(guò)創(chuàng)建一個(gè)DLL來(lái)實(shí)現(xiàn),該DLL在執(zhí)行時(shí)將自身映射到內(nèi)存,而不是依賴(lài)于Windows的loader。
在分析PE注入時(shí),調(diào)用CreateRemoteThread之前通常會(huì)看到循環(huán)(通常是兩個(gè)“for”循環(huán),一個(gè)嵌套在另一個(gè)中)這種技術(shù)在crypter(加密和混淆惡意軟件的軟件)中非常流行。在圖二中,樣本的單元測(cè)試中正在利用這種技術(shù)。代碼有兩個(gè)嵌套循環(huán)來(lái)調(diào)整其重定位表,可以在調(diào)用WriteProcessMemory和CreateRemoteThread之前看到它。“AND 0x0fff”指令是另一個(gè)好指示,表明前12位用于獲取包含重定位塊的虛擬地址的偏移量。既然惡意軟件已經(jīng)重新計(jì)算了所有必要的地址,那么它需要做的只是將其起始地址傳遞給CreateRemoteThread并讓它執(zhí)行。
三、PROCESS HOLLOWING技術(shù)(又名 PROCESS REPLACEMENT AND RUNPE)
惡意軟件可以不用將代碼注入宿主程序,而是利用Process Hollowing技術(shù)。當(dāng)惡意軟件從目標(biāo)進(jìn)程中取消映射,并使用惡意可執(zhí)行文件覆蓋目標(biāo)進(jìn)程的內(nèi)存空間時(shí),會(huì)發(fā)生Process Hollowing。
惡意軟件首先會(huì)創(chuàng)建一個(gè)新進(jìn)程,以掛起模式托管惡意代碼,如圖三所示,這是通過(guò)調(diào)用CreateProcess并將Process Creation Flag設(shè)置為CREATE_SUSPENDED(0×00000004)來(lái)完成的。新進(jìn)程的主線程是在掛起狀態(tài)下創(chuàng)建的,并且在調(diào)用ResumeThread函數(shù)之前不會(huì)執(zhí)行。接下來(lái),惡意軟件需要使用惡意載荷交換合法文件的內(nèi)容,這是通過(guò)調(diào)用ZwUnmapViewOfSection或NtUnmapViewOfSection來(lái)取消映射目標(biāo)進(jìn)程的內(nèi)存完成的。這兩個(gè)API基本上釋放了一個(gè)區(qū)的所有內(nèi)存。現(xiàn)在內(nèi)存處于未映射狀態(tài),loader執(zhí)行VirtualAllocEx為惡意軟件分配新內(nèi)存,并使用WriteProcessMemory將每個(gè)惡意軟件的部分寫(xiě)入目標(biāo)進(jìn)程空間。而惡意軟件通過(guò)調(diào)用SetThreadContext將入口點(diǎn)指向它已編寫(xiě)的新代碼段。最后,惡意軟件通過(guò)調(diào)用ResumeThread恢復(fù)掛起的線程,使進(jìn)程退出掛起狀態(tài)。
四、線程執(zhí)行劫持技術(shù)(或者說(shuō)SUSPEND, INJECT, AND RESUME (SIR))
該技術(shù)與先前討論的Process Hollowing技術(shù)有一些相似之處。在線程執(zhí)行劫持中,惡意軟件以進(jìn)程的現(xiàn)有線程為目標(biāo),并避免任何其他的進(jìn)程或線程創(chuàng)建操作。因此,在分析期間,你可能會(huì)看到對(duì)CreateToolhelp32Snapshot和Thread32First的調(diào)用,然后是OpenThread。
獲取目標(biāo)線程的句柄后,惡意軟件通過(guò)調(diào)用SuspandThread來(lái)掛起這個(gè)線程,然后調(diào)用VirtualAllocEx和WriteProcessMemory來(lái)分配內(nèi)存并執(zhí)行代碼注入。代碼可以包含shellcode,惡意DLL的路徑以及LoadLibrary的地址。
圖4展示了使用這種技術(shù)的通用木馬。為了劫持線程的執(zhí)行,惡意軟件通過(guò)調(diào)用SetThreadContext來(lái)修改目標(biāo)線程的EIP寄存器(包含下一條指令的地址的寄存器)。之后,惡意軟件恢復(fù)線程來(lái)執(zhí)行它已寫(xiě)入主機(jī)進(jìn)程的shellcode。從攻擊者的角度來(lái)看,SIR方法可能會(huì)出問(wèn)題,因?yàn)樵谙到y(tǒng)調(diào)用過(guò)程中掛起和恢復(fù)線程會(huì)導(dǎo)致系統(tǒng)崩潰。為了避免這種情況,如果EIP寄存器在NTDLL.dll范圍內(nèi),復(fù)雜一點(diǎn)的惡意軟件會(huì)稍后重新嘗試。
五、通過(guò)SETWINDOWSHOOKEX進(jìn)行HOOK注入
HOOK是一種攔截函數(shù)調(diào)用的技術(shù),惡意軟件可以利用HOOK的功能在特定線程中觸發(fā)事件時(shí)加載其惡意DLL。這通常通過(guò)調(diào)用SetWindowsHookEx將hook routine安裝到HOOK鏈中來(lái)完成。SetWindowsHookEx函數(shù)有四個(gè)參數(shù)。第一個(gè)參數(shù)是事件的類(lèi)型。事件反映了HOOK類(lèi)型的范圍,從鍵盤(pán)上的按鍵(WH_KEYBOARD)到鼠標(biāo)輸入(WH_MOUSE),CBT等等。第二個(gè)參數(shù)是指向惡意軟件想要在事件上調(diào)用的函數(shù)的指針。第三個(gè)參數(shù)是包含該函數(shù)的模塊。因此,在調(diào)用SetWindowsHookEx之前,通常會(huì)看到對(duì)LoadLibrary和GetProcAddress的調(diào)用。此函數(shù)的最后一個(gè)參數(shù)是與HOOK過(guò)程相關(guān)聯(lián)的線程。如果此值設(shè)置為零,則所有線程都會(huì)在觸發(fā)事件時(shí)執(zhí)行操作。但是,惡意軟件通常針對(duì)一個(gè)線程以降低噪聲,因此在SetWindowsHookEx之前也可以看到調(diào)用CreateToolhelp32Snapshot和Thread32Next來(lái)查找和定位單個(gè)線程。注入DLL后,惡意軟件代表其threadId傳遞給SetWindowsHookEx函數(shù)的進(jìn)程執(zhí)行其惡意代碼。在圖5中,Locky Ransomware實(shí)現(xiàn)了這種技術(shù)。六、通過(guò)修改注冊(cè)表實(shí)現(xiàn)注入和持久性
Appinit_DLL,AppCertDlls和IFEO(映像文件執(zhí)行選項(xiàng))都是惡意軟件用于注入和持久性的注冊(cè)表項(xiàng)。條目位于以下位置:
HKLM\Software\Microsoft\Windows NT\CurrentVersion\Windows\Appinit_Dlls
HKLM\Software\Wow6432Node\Microsoft\Windows NT\CurrentVersion\Windows\Appinit_Dlls
HKLM\System\CurrentControlSet\Control\Session Manager\AppCertDlls
HKLM\Software\Microsoft\Windows NT\currentversion\image file execution options
AppInit_DLLs
惡意軟件可以在Appinit_Dlls注冊(cè)表項(xiàng)下插入其惡意庫(kù)的位置,以使另一個(gè)進(jìn)程加載其庫(kù)。此注冊(cè)表項(xiàng)下的每個(gè)庫(kù)都會(huì)加載到每個(gè)加載User32.dll的進(jìn)程中。User32.dll是一個(gè)非常常見(jiàn)的庫(kù),用于存儲(chǔ)對(duì)話框等圖形元素。因此,當(dāng)惡意軟件修改此子鍵時(shí),大多數(shù)進(jìn)程將加載惡意庫(kù)。圖6展示了Ginwui依賴(lài)這種注入和持久性方法的木馬。它只是通過(guò)調(diào)用RegCreateKeyEx打開(kāi)Appinit_Dlls注冊(cè)表項(xiàng),并通過(guò)調(diào)用RegSetValueEx來(lái)修改其值。
AppCertDlls
此方法與AppInit_DLLs方法非常相似,只是此注冊(cè)表項(xiàng)下的DLL被加載到調(diào)用Win32 API函數(shù)CreateProcess,CreateProcessAsUser,CreateProcessWithLogonW,CreateProcessWithTokenW和WinExec的每個(gè)進(jìn)程中。
映像文件執(zhí)行選項(xiàng)(IFEO)
IFEO通常用于調(diào)試目的。開(kāi)發(fā)人員可以在此注冊(cè)表項(xiàng)下設(shè)置“調(diào)試器值”,以將程序附加到另一個(gè)可執(zhí)行文件以進(jìn)行調(diào)試。因此,每當(dāng)啟動(dòng)可執(zhí)行文件時(shí),會(huì)啟動(dòng)附加到它的程序。要使用此功能,你只需提供調(diào)試器的路徑,并將其附加到要分析的可執(zhí)行文件。惡意軟件可以修改此注冊(cè)表項(xiàng)以將其自身注入目標(biāo)可執(zhí)行文件。在圖7中,Diztakun木馬通過(guò)修改任務(wù)管理器的調(diào)試器值來(lái)實(shí)現(xiàn)此技術(shù)。
七、APC注入和ATOMBOMBING
惡意軟件可以利用異步過(guò)程調(diào)用(APC)通過(guò)將其附加到目標(biāo)線程的APC隊(duì)列來(lái)強(qiáng)制另一個(gè)線程執(zhí)行其特制代碼。每個(gè)線程都有一個(gè)APC隊(duì)列,它們等待目標(biāo)線程進(jìn)入可變狀態(tài)時(shí)執(zhí)行。如果線程調(diào)用SleepEx,SignalObjectAndWait,MsgWaitForMultipleObjectsEx,WaitForMultipleObjectsEx或WaitForSingleObjectEx函數(shù),則線程進(jìn)入可更改狀態(tài)。惡意軟件通常會(huì)查找處于可更改狀態(tài)的任何線程,然后調(diào)用OpenThread和QueueUserAPC將APC排入線程。 QueueUserAPC有三個(gè)參數(shù):
1)目標(biāo)線程的句柄;
2)指向惡意軟件想要運(yùn)行的功能的指針;
3)傳遞給函數(shù)指針的參數(shù)。
在圖8中,Amanahe惡意軟件首先調(diào)用OpenThread來(lái)獲取另一個(gè)線程的句柄,然后通過(guò)LoadLibraryA調(diào)用QueueUserAPC作為函數(shù)指針,將其惡意DLL注入另一個(gè)線程。
AtomBombing是一項(xiàng)由enSilo研究首次引入的技術(shù),然后用于Dridex V4。 正如我們?cè)谇耙黄恼轮性敿?xì)討論的那樣,該技術(shù)也依賴(lài)于APC注入。 但是,它使用原子表寫(xiě)入另一個(gè)進(jìn)程的內(nèi)存。
八、通過(guò)SETWINDOWLONG進(jìn)行附加窗口內(nèi)存注入(EWMI)
EWMI依賴(lài)于注入資源管理器托盤(pán)窗口的額外窗口內(nèi)存,并且已經(jīng)在Gapz和PowerLoader等惡意軟件系列中應(yīng)用過(guò)幾次。注冊(cè)窗口類(lèi)時(shí),應(yīng)用程序可以指定一些額外的內(nèi)存字節(jié),稱(chēng)為額外窗口內(nèi)存(EWM)。但是,EWM的空間不大。為了規(guī)避此限制,惡意軟件將代碼寫(xiě)入explorer.exe的共享部分,并使用SetWindowLong和SendNotifyMessage使用指向shellcode的函數(shù)指針,然后執(zhí)行它。
在寫(xiě)入共享部分時(shí),惡意軟件有兩種選擇。它既可以創(chuàng)建共享空間,也可以將其映射到自身和另一個(gè)進(jìn)程(例如explorer.exe),也可以只打開(kāi)已存在的共享空間。除了一些其他API調(diào)用之外,前者還有分配堆空間和調(diào)用NTMapViewOfSection的開(kāi)銷(xiāo),因此后一種方法更常用。在惡意軟件將其shellcode寫(xiě)入共享部分后,它使用GetWindowLong和SetWindowLong來(lái)訪問(wèn)和修改“Shell_TrayWnd”的額外窗口內(nèi)存。GetWindowLong是一個(gè)API,用于將指定偏移量的32位值檢索到窗口類(lèi)對(duì)象的額外窗口內(nèi)存中,SetWindowLong用于更改指定偏移量的值。這樣一來(lái),惡意軟件可以簡(jiǎn)單地更改窗口類(lèi)中的函數(shù)指針的偏移量,并將其指向?qū)懭牍蚕聿糠值膕hellcode。
與上面提到的大多數(shù)其他技術(shù)一樣,惡意軟件需要觸發(fā)它特制的代碼。在先前討論的技術(shù)中,惡意軟件通過(guò)調(diào)用諸如CreateRemoteThread,QueueUserAPC或SetThreadContext之類(lèi)的API來(lái)實(shí)現(xiàn)此目的。使用此方法,惡意軟件會(huì)通過(guò)調(diào)用SendNotifyMessage來(lái)觸發(fā)注入的代碼。執(zhí)行SendNotifyMessage后,Shell_TrayWnd接收控制并將控制轉(zhuǎn)移到之前由SetWindowLong設(shè)置的值指向的地址。在圖9中,名為PowerLoader的惡意軟件使用此技術(shù)。
九、SHIMS注入
Microsoft向開(kāi)發(fā)人員提供SHIMS主要是為了向后兼容。SHIMS允許開(kāi)發(fā)人員將修補(bǔ)程序應(yīng)用于他們的程序,而無(wú)需重寫(xiě)代碼。通過(guò)利用SHIMS,開(kāi)發(fā)人員可以告訴操作系統(tǒng)如何處理應(yīng)用程序。SHIMS本質(zhì)上是一種掛鉤API并定位特定可執(zhí)行文件的方法。惡意軟件可以利用SHIMS來(lái)定位持久性和注入的可執(zhí)行文件。Windows在加載二進(jìn)制文件時(shí)運(yùn)行Shim Engine以檢查SHIMS數(shù)據(jù)庫(kù)以應(yīng)用適當(dāng)?shù)男迯?fù)程序。
現(xiàn)在有許多方法應(yīng)用修復(fù)程序,但惡意軟件的最?lèi)?ài)是與安全相關(guān)的(例如,DisableNX,DisableSEH,InjectDLL等)。要安裝填充數(shù)據(jù)庫(kù),惡意軟件可以部署各種方法。例如,一種常見(jiàn)的方法是簡(jiǎn)單地執(zhí)行sdbinst.exe,并將其指向惡意sdb文件。在圖10中,廣告軟件“按導(dǎo)管搜索保護(hù)”使用墊片進(jìn)行持久性和注入。它在Google Chrome中執(zhí)行“InjectDLL”填充程序以加載vc32loader.dll。有一些用于分析sdb文件的現(xiàn)有工具,但是為了分析下面列出的sdb,我使用了python-sdb。
十、IAT HOOKING和INLINE HOOKING (或者叫應(yīng)用層ROOTKITS)
IAT hooking和inline hooking通常稱(chēng)為userland rootkit。IAT hooking是惡意軟件用于更改導(dǎo)入地址表的技術(shù)。當(dāng)合法應(yīng)用程序調(diào)用位于DLL中的API時(shí),其會(huì)執(zhí)行替換的函數(shù),而不是原始函數(shù)。相反,使用inline hooking,惡意軟件則會(huì)修改API函數(shù)本身。在圖11中,惡意軟件FinFisher通過(guò)修改CreateWindowEx指向的位置來(lái)執(zhí)行IAT hooking。
總結(jié)
在這篇文章中,我介紹了惡意軟件用于在另一個(gè)進(jìn)程中隱藏其活動(dòng)的十種不同技術(shù)。通常,惡意軟件會(huì)直接將其shellcode注入另一個(gè)進(jìn)程,或者強(qiáng)制另一個(gè)進(jìn)程加載其惡意庫(kù)。在表1中,我對(duì)各種技術(shù)進(jìn)行了分類(lèi),并提供了樣本作為閱讀本文所涵蓋的每種注入技術(shù)的參考。
|