天天看點

程序注入原理——提權會用到本質上就是在程序的記憶體位址上做一些hack改動

0x00 前言

程序注入是一種廣泛應用于惡意軟體和無檔案攻擊中的逃避技術,這意味着可以将自定義代碼運作在另一個程序的位址空間内。程序注入提高了隐蔽性,也實作了持久化。盡管有非常多的程序注入技術,但是本文我隻列舉了10種常見的技術。我還提供了這些技術的相關截圖以便逆向和惡意軟體的分析,并幫助防禦這些技術。

0x01 通過CreateRemoteThread和LoadLibrary的DLL注入

這是程序注入最常見的技術。惡意軟體将惡意的動态連結庫的路徑寫入另一個程序的虛拟位址空間内,通過在目标程序中建立遠端線程來確定遠端程序加載它。

程式注入原理——提權會用到本質上就是在程式的記憶體位址上做一些hack改動

惡意軟體首先需要選擇目标程序(例如svchost.exe)。通常使用API:CreateToolhelp32Snapshot, Process32First, 和 Process32Next來完成。CreateToolhelp32Snapshot是個用于枚舉指定程序或所有程序的堆或子產品的狀态,并且它傳回一個快照。Process32First得到快照中的第一個程序的資訊,然後Process32Next來周遊所有的程序。在找到目标程序後,惡意軟體調用OpenProcess得到目标程序的句柄。

如上圖所示,惡意軟體調用VirtualAllocEx得到寫入路徑的記憶體空間。然後調用WriteProcessMemory在配置設定的記憶體中寫入路徑(動态連結庫)。最後,調用API(如CreateRemoteThread、NtCreateThreadEx、RtlCreateUserThread)使得另一個程序執行代碼。後兩個API是未文檔化的。然而,通常想法是将LoadLibrary的位址傳入這些API中的一個,以便遠端程序執行DLL。

CreateRemoteThread被許多安全産品跟蹤并标記。而且,它在磁盤上面留下了一個惡意的DLL可供檢測。考慮到攻擊者注入代碼最常見的目的是逃避防禦,高明的攻擊者不會使用這種方式。下面是名為Rebhip(Sha256: 07b8f25e7b536f5b6f686c12d04edc37e11347c8acd5c53f98a174723078c365)的惡意軟體使用了這種技術。

程式注入原理——提權會用到本質上就是在程式的記憶體位址上做一些hack改動

0x02 可執行檔案注入(PE注入)

惡意軟體并不傳入LoadLibrary的位址,而是拷貝惡意代碼到打開的程序中并執行(通過小段shellcode或者調用CreateRemoteThread)。與LoadLibrary相比,PE注入的優勢是惡意軟體不需要在磁盤中釋放一個惡意的DLL。與上個技術類似,惡意軟體在目标程序中配置設定記憶體,調用WriteProcessMemory将惡意代碼而不是DLL路徑寫入記憶體。然而,這種方式的缺陷是被複制的映像的基址的改變。當一個惡意軟體注入PE到另一個程序,它的新基址是不可預料的,需要動态重新計算PE的位址。為了完成這個,惡意軟體需要找到目标程序的重定位表,并根據它的重定位描述解析被複制映像的絕對位址。

程式注入原理——提權會用到本質上就是在程式的記憶體位址上做一些hack改動

這種技術和其他技術很類似,如反射DLL注入和記憶體子產品加載,因為他們都不釋放任何檔案到磁盤。但是,記憶體子產品和反射DLL注入更加隐蔽。他們不依賴Windows API(如CreateRemoteThread或LoadLibrary),因為他們在記憶體中加載并執行自身。反射DLL注入通過在記憶體中建立一個DLL映射執行,而不依賴Windows的加載器。記憶體子產品加載和反射DLL注入類似,其不同之處隻是在于記憶體子產品加載的注入器或加載器負責映射目标DLL到記憶體中而不是DLL自身映射。在之前的博文中,讨論過這兩種技術。

當分析PE注入時,在調用CreateRemoteThread之前通常能看見循環(通常是兩個for循環,一個嵌套在另一個中)。這種技術在crypter(加密和混淆軟體)中非常流行。下圖中的樣本(Sha256: ce8d7590182db2e51372a4a04d6a0927a65b2640739f9ec01cfd6c143b1110da)充分利用了這種技術。在調用WriteProcessMemory和CreateRemoteThread之前有兩層循環來處理重定位。“and 0x0fff”指令也是一個比較好的表征,它标明了頭12位用于得到包含重定位塊的虛拟位址的偏移量。現在惡意軟體重新計算了所有需要的位址了,隻需要将起始位址傳入CreateRemoteThread并執行就行了。

程式注入原理——提權會用到本質上就是在程式的記憶體位址上做一些hack改動

0x03 程序hollow(又名程序替換和RunPE)

惡意軟體有一種技術叫程序hollow,而不是注入代碼到程式中(如DLL注入)。程序hollow發生在惡意軟體unmap目标程序的合法記憶體代碼,并使用惡意的代碼覆寫目标程序的記憶體(如svchost.exe)的時候。

程式注入原理——提權會用到本質上就是在程式的記憶體位址上做一些hack改動

惡意軟體首先以挂起模式建立一個新程序來容納惡意代碼。如下圖(Sha256: eae72d803bf67df22526f50fc7ab84d838efb2865c27aef1a61592b1c520d144),以CREATE_SUSPENDED (0x00000004)為參數調用CreateProcess。新程序的主線程建立後就處于挂起狀态,直到調用ResumeThread才會繼續執行。接下來,惡意軟體需要使用惡意的payload來填充合法檔案的内容。調用ZwUnmapViewOfSection或者NtUnmapViewOfSection來unmap目标程序的記憶體。這兩個API将釋放section指向的所有記憶體。記憶體unmap之後,使用WriteProcessMemory将惡意軟體的節寫入目标程序。調用SetThreadContext将入口點指向它已寫入的新的代碼節。最後,調用ResumeThread恢複挂起程序的執行。

程式注入原理——提權會用到本質上就是在程式的記憶體位址上做一些hack改動

0x04 線程執行劫持(又名挂起、注入并恢複)

這種技術類似于程序hollow。線上程執行劫持中,惡意軟體的目标是程序中已存在的線程,而且沒有建立任何程序或線程。是以,在分析期間你可能看見CreateToolhelp32Snapshot和Thread32First、OpenThread。

程式注入原理——提權會用到本質上就是在程式的記憶體位址上做一些hack改動

在得到目标線程的句柄後,惡意軟體調用SuspendThread将線程挂起。調用VirtualAllocEx和WriteProcessMemory來配置設定記憶體并執行代碼注入。代碼包含shellcode,惡意DLL的路徑和LoadLibrary的位址。

下圖(Sha256: 787cbc8a6d1bc58ea169e51e1ad029a637f22560660cc129ab8a099a745bd50e)描述了一個普通木馬是如何使用這種技術的。為了劫持線程的執行,惡意軟體調用SetThreadContext修改目标線程的EIP寄存器(包含下條執行指令的位址的寄存器)。随後,惡意軟體恢複線程繼續執行它已寫入到宿主程序的shellcode。從攻擊者的角度看,這種方式是有問題的,因為在系統調用的中途挂起并恢複線程可能引起系統崩潰。為了避免這種情況的發生,更複雜的利用技術是,一旦EIP寄存器在NTDLL.dll中就恢複并重試。

程式注入原理——提權會用到本質上就是在程式的記憶體位址上做一些hack改動

0x05 通過SetWindowsHookEx鈎子注入

鈎子是用于攔截函數調用的一種技術。惡意軟體能利用指定線程中事件觸發來加載他們的惡意DLL。通常使用SetWindowsHookEx來安裝消息鈎子。SetWindowsHookEx有4個參數。第一個參數是事件的類型。事件有很多的類型,有鍵盤按鍵(WH_KEYBOARD)和滑鼠輸入(WH_MOUSE)等。第二個參數是個函數指針,指向惡意軟體想要處理事件的函數。第3個參數是包含函數的子產品。是以,通常可以看見LoadLibrary、GetProcAddress、SetWindowsHookEx。最後一個參數是消息鈎子關聯的線程。如果值為0,則針對所有線程。然而,隻針對某個線程的目标會小很多,是以也可能看見CreateToolhelp32Snapshot和Thread32Next。一旦DLL被注入後,惡意軟體将執行惡意代碼。下圖中,勒索軟體Locky(Sha256: 5d6ddb8458ee5ab99f3e7d9a21490ff4e5bc9808e18b9e20b6dc2c5b27927ba1)就使用了這種技術。

0x06 通過系統資料庫修改(如AppInit_DLLs,AppCertDlls,IFEO)

Appinit_DLL, AppCertDlls, IFEO(映像劫持)可以用于注入和持久化。完整的路徑如下:

程式注入原理——提權會用到本質上就是在程式的記憶體位址上做一些hack改動

AppInit_DLLs

惡意軟體能在AppInit_DLLs鍵下插入惡意的DLL的路徑,以便其他程序加載。該鍵下每個DLL會被加載到所有的加載User32.dll的程序中。User32.dll是常見的Windows基礎庫。是以,當惡意軟體修改這個子鍵時,大量程序将加載惡意的DLL。下圖中,木馬Ginwui(Sha256: 9f10ec2786a10971eddc919a5e87a927c652e1655ddbbae72d376856d30fa27c)依賴了這種技術。它通過調用RegCreateKeyEx打開AppInit_DLLs鍵,并調用RegSetValueEx修改它。

程式注入原理——提權會用到本質上就是在程式的記憶體位址上做一些hack改動

AppCertDlls

這種方式類似與AppInit_DLLs,除了該鍵下的DLL會加載到調用Win32 API CreateProcess, CreateProcessAsUser, CreateProcessWithLogonW, CreateProcessWithTokenW, WinExec的程序中。

IFEO

IFEO通常用于調試。開發者能在該鍵下設定調試器,來附加調試。是以,當可執行檔案啟動時,附加到它的程式也會啟動。為了使用這功能,你能簡單的設定調試器的路徑,并附加到你想分析的可執行檔案上。下圖,木馬Diztakun(Sha256: f0089056fc6a314713077273c5910f878813fa750f801dfca4ae7e9d7578a148)使用了這種技術,它修改了任務管理器的調試器的值。

程式注入原理——提權會用到本質上就是在程式的記憶體位址上做一些hack改動

0x07 APC注入和AtomBombing

惡意軟體利用異步過程調用(APC)來強制另一個線程執行附加到APC隊列的自定義代碼。每個線程都有一個APC隊列,當線程進入可變狀态(編輯注: 這裡疑為英文原文的拼寫錯誤,有兩處使用了alterable state一詞,而一處使用了alertable state,疑應為alterable state)時,可以被執行。當調用SleepEx, SignalObjectAndWait, MsgWaitForMultipleObjectsEx, WaitForMultipleObjectsEx,  WaitForSingleObjectEx時進入可變狀态。惡意軟體通常查詢線程是否處于可變狀态,然後調用OpenThread和QueueUserAPC來向線程插入APC。QueueUserAPC有3個參數:1. 目标線程的句柄 2. 惡意軟體想要執行的函數指針 3. 傳給函數的參數。下圖,惡意軟體Amanahe(Sha256: f74399cc0be275376dad23151e3d0c2e2a1c966e6db6a695a05ec1a30551c0ad)首先調用了OpenThread來得到另一個線程的句柄,然後調用QueueUserAPC,以LoadLibrary作為函數指針注入惡意DLL。

AtomBombing由enSilo首次提出,然後在Dridex V4中使用。正如之前博文中讨論的,這種技術也依賴APC注入。然而它使用atom表來寫入到另一個程序的記憶體。

0x08 通過SetWindowLong的視窗記憶體注入(EWMI)

EWMI依賴注入到資料總管托盤視窗記憶體中,并在惡意軟體家族Gapz和PowerLoader中使用多次。當注冊一個視窗類時,應用程式能指定額外的記憶體位元組,稱為額外的視窗記憶體(EWM)。然而,在EWM中沒有太多的空間。為了規避這個限制,惡意軟體将代碼寫入explorer.exe的共享段中,并使用SetWindowLong和SendNotifyMessage得到一個指向shellcode的函數指針,然後執行它。

當寫入共享段時,惡意軟體有兩個選項。它能建立一個共享段自己映射到另一個程序(如explorer)中,或者打開一個已存在的共享段。前者有配置設定堆記憶體的開銷,而且還要調用NtMapViewOfSection等API,是以後者更常用。在惡意軟體将shellcode寫入共享段後,使用GetWindowLong和SetWindowLong來通路并修改Shell_TrayWnd的額外的視窗記憶體。GetWindowLong是用于通過32位值作為偏移得到視窗類對象中額外視窗記憶體,同時使用SetWindowLong能改變指定偏移的值。通過完成這個,惡意軟體能改變視窗類中的函數指針,将它指向共享段的shellcode。

和上述的技術一樣,惡意軟體需要觸發寫入的代碼。之前說,它是通過調用類似CreateRemoteThread,SetThreadContext,QueueUserAPC這些API來實作的。與之前不同的是,這種技術是通過使用SendNotifyMessage來觸發代碼執行的。

一旦執行SendNotifyMessage,Shell_TrayWnd将接收到并将控制移交給SetWindowLong設定的位址。下圖,名為PowerLoader(Sha256: 5e56a3c4d4c304ee6278df0b32afb62bd0dd01e2a9894ad007f4cc5f873ab5cf)的惡意軟體使用了這種技術。

程式注入原理——提權會用到本質上就是在程式的記憶體位址上做一些hack改動
程式注入原理——提權會用到本質上就是在程式的記憶體位址上做一些hack改動

0x09 使用Shims注入

微軟提供了Shims給開發者,這主要是為了向後相容。Shims允許開發者不必重寫代碼就能修複程式。通過利用shims,開發者告訴作業系統如何處理他們的應用程式。Shims本質是Hook API的方式。惡意軟體能利用shims實作注入和持久化。當加載二進制時,Windows運作Shim引擎以檢查shim資料庫,以便使用合适的修複。

有很多修複可以利用,但是惡意軟體最喜歡的是一些安全相關的(如DisableNX, DisableSEH, InjectDLL等)。為了安裝一個shim資料庫,惡意軟體部署了多種方式。例如,常見的一種方式是執行sdbinst.exe,并将它指向惡意的sdb檔案。如下圖,一個廣告軟體“Search Protect by Conduit”(Sha256: 6d5048baf2c3bba85adc9ac5ffd96b21c9a27d76003c4aa657157978d7437a20),使用shim來實作了持久化和注入。它執行一個“InjectDLL”shim到谷歌chrome中加載vc32loader.dll。有一些現成的工具可以分析sdb檔案,下面是我使用python-sdb分析的結果。

程式注入原理——提權會用到本質上就是在程式的記憶體位址上做一些hack改動

0x0A IAT hook和Inline hook(應用層rootkit)

IAT hook和inline hook通常也叫應用層rootkit。IAT hook使用用于改變導入位址表的技術。當合法的程式調用位于DLL中API時,将會執行被替換的API。相反,在inline hook中,惡意程式修改API函數本身。如下圖,惡意軟體FinFisher(Sha256: f827c92fbe832db3f09f47fe0dcaafd89b40c7064ab90833a1f418f2d1e75e8e),IAT就hook了CreateWindowEx。

程式注入原理——提權會用到本質上就是在程式的記憶體位址上做一些hack改動

0x0B 總結

本文中,我描述了惡意軟體用于隐藏自身行為的10種不同的技術。通常,惡意軟體直接注入shellcode到另一個程序中或者強制其他程序加載惡意DLL。如下表,我已經将不同的技術進行了分類,并提供了樣本,用于檢視在本文提到的每個注入技術。這可以幫助研究者用于在逆向時識别各種技術。

程式注入原理——提權會用到本質上就是在程式的記憶體位址上做一些hack改動

攻擊者和研究員一直在研究新的注入和隐蔽的技術。本文介紹了10種常見的技術,但是還有其他的,如COM劫持。防禦者任重道遠。

繼續閱讀