Wow64(32位程序)注入DLL到64位程序
http://blog.poxiao.me/p/wow64-process-inject-dll-into-x64-process/#Wow64環境下32位程序注入64位程序
DLL注入
向其他程序注入DLL通常的做法是通過呼叫CreateRemoteThread
這個API在目標程序內建立一個遠端執行緒,用這個執行緒來呼叫LoadLibraryA
或LoadLibraryW
(下文統稱LoadLibrary)以實現讓目標程序載入指定的DLL檔案。使用CreateRemoteThread建立一個遠端執行緒需要傳入一個執行緒過程函式的地址,並且這個函式地址是需要在目標程序中有效的。由於LoadLibrary是kernel32.dll的匯出函式,所以對於執行在同一個系統上的同為32位的程序或同為64位的程序可以假定彼此程序內的LoadLibrary函式的地址是相同的。並且CreateRemoteThread的執行緒過程函式和LoadLibrary的引數個數相同,且引數都是指標,因此通常都是直接將LoadLibrary作為CreateRemoteThread的過程函式。然後使用VirtualAllocEx
WriteProcessMemory
往這塊記憶體中寫入DLL檔案路徑,將這塊記憶體的地址作為執行緒過程函式(LoadLibrary)的引數。
在64位的Windows作業系統上32位程序中的LoadLibrary函式地址與64位程序的函式地址不同,因此如果想對64位程序注入DLL,簡單的做法就是使用64位程序來執行注入工作。但是如果能讓32位程序注入DLL到64位程序顯然更好。
在一番Google之後找到了這篇文章。這篇文章的作者研究出來一種在Wow64程序中執行x64程式碼的方法,並且將其封裝成了這個庫。
本文就是介紹如何使用這個庫實現Wow64環境下32位程序向64位程序注入DLL。
Wow64環境下32位程序注入64位程序
32位程序難以注入DLL進64位程序是由於兩個程序內LoadLibrary的地址不同,32位程序無法知道64位程序的LoadLibrary函式地址。使用wow64ext這個庫在Wow64環境下可以讓32位程序獲取到64位的ntdll.dll的匯出函式(得到的地址與64程序的地址是一樣的)。
本文使用ntdll中的這3個未文件的函式來注入DLL。
1 |
NTSTATUS |
使用RtlCreateUserThread
建立遠端執行緒,在遠端執行緒中呼叫LdrLoadDll
載入要注入的DLL檔案,最後在遠端執行緒中呼叫RtlExitUserThread
退出執行緒。
為了在遠端執行緒中呼叫兩個函式(LdrLoadDll、RtlExitUserThread),需要將要執行的x64程式碼寫入目標程序,然後讓遠端執行緒執行這段程式碼,在這之前需要了解一些預備知識。可以看MSDN中的這篇文章。通過這個篇文章我們知道了。
- 在呼叫約定上Windows在x64進行了統一,也就是說不管你有沒有顯式指定呼叫約定,指定了何種呼叫約定,最終編譯後都使用
__fastcall
這一種呼叫約定。 - 在引數傳遞上對於Integer型別(含指標)前4個引數通過
RCX
、RDX
、R8
、R9
暫存器傳遞,其他引數通過棧傳遞。
LdrLoadDll有4個引數都是指標,RtlExitUserThread只有1個引數是Integer型別。為這兩個函式傳遞引數只通過暫存器就足夠了。
當然我們不需要自己去寫彙編程式碼再將彙編程式碼轉成機器碼,首先先寫下面這樣一段程式碼。
1 |
typedef unsigned long long DWORD64; |
然後使用VC編譯器將其編譯成x64的程式碼,再反彙編它。
跟據記憶體地址,容易得到下面的機器碼與彙編程式碼的對應關係。
1 |
0x48 0x89 0x4c 0x24 0x08 mov qword ptr [rsp+8],rcx 0x57 push rdi 0x48 0x83 0xec 0x20 sub rsp,20h 0x48 0x8b 0xfc mov rdi,rsp 0xb9 0x08 0x00 0x00 0x00 mov ecx,8 0xb8 0xcc 0xcc 0xcc 0xcc mov eac,0CCCCCCCCh 0xf3 0xab rep stos dword ptr [rdi] 0x48 0x8b 0x4c 0x24 0x30 mov rcx,qword ptr [__formal] 0x49 0xb9 0x44 0x44 0x44 0x44 0x44 0x44 0x44 0x44 mov r9,4444444444444444h 0x49 0xb8 0x33 0x33 0x33 0x33 0x33 0x33 0x33 0x33 mov r8,3333333333333333h 0x48 0xba 0x22 0x22 0x22 0x22 0x22 0x22 0x22 0x22 mov rdx,2222222222222222h 0x48 0xb9 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 mov rcx,1111111111111111h 0x48 0xb8 0x56 0x34 0x12 0x90 0x78 0x56 0x34 0x12 mov rax,1234567890123456h 0xff 0xd0 call rax 0x48 0xb9 0x55 0x55 0x55 0x55 0x55 0x55 0x55 0x55 mov rcx,5555555555555555h 0x48 0xb8 0x21 0x43 0x65 0x87 0x09 0x21 0x43 0x65 mov rax,6543210987654321h 0xff 0xd0 call rax |
只要在執行的時候根據獲取到的函式地址和引數地址替換對應機器碼然後將機器碼寫入目標程序,建立執行緒執行這段程式碼就能夠實現Wow64程序注入DLL到64位程序了。
完整的實現程式碼如下(VS2012編譯通過,Windows 8 x64測試注入成功)。
1 |
#include <memory> |
這段程式碼在建立遠端執行緒成功即認為注入成功,為了更加準確的判斷是否注入成功可以在注入的機器碼增加額外的程式碼來判斷是否注入成功。