RunPE是指惡意程式先執行一個正常的process,然後將該process本來要執行的PE模組替換成惡意的模組,導致該process執行惡意程式指定的PE而非本來該process的PE,達到披著羊皮的狼的目的,逃過防毒軟體的偵測。
一個process可以掛載多個PE(ex. DLL),也就是一個process的address space中可以映射進很多個PE,而當一個新的process要開始執行時,要如何知道執行哪一個PE的內容才對呢,答案就在PEB(Process Environment Block)中,PEB中的ImageBaseAddress會儲存要執行的程式映像基址,假設一個PE模組被映射到address space中的0xA00000,還有另一個PE模組被映射到0x400000,而如果PEB->ImageBaseAddress是0xA00000,就代表該PE是這支process將要執行的模組。
當Main Thread執行到NtDLL!LdrpInitializeProcess函數(此為「執行程式裝載器」,負責修正導入導出表及重定向等工作)時,會識別出主要執行模組為位在0xA00000的那個模組,便會以該模組進行修正工作,並在執行完後把執行權交棒給該PE模組的入口(嘿對就是該PE的AddressOfEntryPoint),然後該PE的內容就會被執行。
這樣RunPE的思路就比較清晰了,假設本來有個process,其中有個A模組應該要被執行,但如果我可以在執行程式裝載器執行前,把一個B模組映射進該process的address space,而且把該process的PEB->ImageBaseAddress修改成B模組映射到的image基址,再把應該被交棒的入口改成B模組的AddressOfEntryPoint,那就可以劫持本來的流程,把B模組跑起來了。
CreateProcessA在建立新process時可以將其Suspend,此時Main Thread尚未執行到執行程式裝載器,且此時Main Thread的Context中,EIP會指向NtDLL!RtlUserThreadStart函數,該函數第一個參數會放在EAX,儲存著完成初始化後應該要被交棒的執行地址,第二個參數放在EBX,儲存的就是PEB的地址,而EBX+8這個地址存的就是PEB中的ImageBaseAddress。
以下程式runPE.exe會先檢查當前的模組名稱是不是garena.exe,是的話就彈一個窗口。如果不是的話,代表當前模組是runPE.exe,它會用CreateProcessA開啟garena.exe,這時候新的process模組名稱就會是garena.exe了,然後再把新process的模組替換成當前模組(runPE.exe),這時候新process的模組名稱是garena.exe,但是實際執行的模組被替換了,所以當新的process執行時,會執行runPE.exe的內容,而runPE.exe會先檢查當前模組名稱是不是garena.exe,檢查是garena.exe,最後彈出一個窗口。
1 |
|
參考連結
https://github.com/aaaddress1/Windows-APT-Warfare/blob/main/source/chapter%2302/RunPE/RunPE.cpp
https://github.com/Zer0Mem0ry/RunPE/blob/master/RunPE.cpp