32位进程注入64位进程
远程线程注入的做法是通过API:CreateRemoteThread在目标进程创建远程线程,让这个线程实现LoadLibrary去加载动态库。LoadLibrary函数通过kernel32导出,在32位和64位下的地址是不同的,所以一般来说32位是无法注入64位的。
在github上有一个开源项目rewolf-wow64ext,该项目的目的是让运行在Wow64下的32位程序可以调用x64下的API。
具体方法是通过该库的函数导出LdrLoadDll,RtlCreateUserThread,RtlExitUserThread三个API,RtlCreateUserThread创建远程线程,LdrLoadDll加载动态库,RtlExitUserThread退出远程线程。代码如下:
// Wow64Injectx64.cpp : 定义控制台应用程序的入口点。 // #include "stdafx.h" #include <Windows.h> #include <iostream> #include <string> #include "shlwapi.h" #include "wow64ext.h" #pragma comment(lib,"shlwapi.lib") #pragma comment(lib,"wow64ext.lib") using namespace std; // unsigned char ShellCode[] = { 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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov r9,0 //PVOID* BaseAddr opt 0x49, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov r8,0 //PUNICODE_STRING Name 0x48, 0xba, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov rdx,0 0x48, 0xb9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov rcx,0 0x48, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov rax,0 0xff, 0xd0, // call rax LdrLoadDll 0x48, 0xb9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov rcx,0 0x48, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov rax,0 0xff, 0xd0 // call rax }; BOOL Wow64Injectx64(DWORD ProcessID, const TCHAR* FilePath); int main() { cout << "Input ProcessID" << endl; ULONG_PTR ProcessID = 0; cin >> ProcessID; WCHAR FilePath[] = L"C:\\Users\\ChangSungsin\\Desktop\\测试\\Injectx64\\Injectx64\\Dll.dll"; if (Wow64Injectx64(ProcessID, FilePath)) { cout << "Inject Success" << endl; } else { cout << "Failed to Inject" << endl; } return 0; } BOOL Wow64Injectx64(DWORD ProcessID, const TCHAR* FilePath) { if (!PathFileExists(FilePath)) { return FALSE; } HANDLE hTarget = OpenProcess(PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ, FALSE, ProcessID); if (INVALID_HANDLE_VALUE == hTarget) { return FALSE; } SIZE_T FilePathLength = (SIZE_T)::_tcslen(FilePath); SIZE_T ParamemterSize = (FilePathLength + 1)*sizeof(TCHAR) + sizeof(_UNICODE_STRING_T<DWORD64>) + sizeof(DWORD64); DWORD64 ParamemterMemAddr = (DWORD64)VirtualAllocEx64(hTarget, NULL, ParamemterSize, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); DWORD64 ShellCodeAddr = (DWORD64)VirtualAllocEx64(hTarget, NULL, sizeof(ShellCode), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); if ((!ParamemterMemAddr) || (!ShellCodeAddr)) { return FALSE; } char* ParamemterMemLocal = new char[ParamemterSize]; memset(ParamemterMemLocal, 0, ParamemterSize); _UNICODE_STRING_T<DWORD64>* UnicodeString = (_UNICODE_STRING_T<DWORD64>*)(ParamemterMemLocal + sizeof(DWORD64)); UnicodeString->Length = FilePathLength * sizeof(wchar_t); UnicodeString->MaximumLength = (FilePathLength +1)* 2; wcscpy((WCHAR*)(UnicodeString + 1), FilePath); UnicodeString->Buffer = ParamemterMemAddr + sizeof(DWORD64) + sizeof(_UNICODE_STRING_T<DWORD64>); DWORD64 Ntdll64 = GetModuleHandle64(L"ntdll.dll"); DWORD64 NtdllLdrLoadDll = GetProcAddress64(Ntdll64, "LdrLoadDll"); DWORD64 NtdllRtlCreateUserThread = GetProcAddress64(Ntdll64, "RtlCreateUserThread"); DWORD64 NtdllRtlExitThread = GetProcAddress64(Ntdll64, "RtlExitUserThread"); if (NtdllLdrLoadDll == NULL || NtdllRtlCreateUserThread == NULL || NtdllRtlExitThread == NULL) { return FALSE; } // DWORD转char union { DWORD64 from; unsigned char to[8]; }Convert; // 写入r9寄存器 Convert.from = ParamemterMemAddr; memcpy(ShellCode + 32, Convert.to, sizeof(Convert.to)); // 写入r8寄存器 Convert.from = ParamemterMemAddr + sizeof(DWORD64); memcpy(ShellCode + 42, Convert.to, sizeof(Convert.to)); // 写入LdrLoadDll地址 Convert.from = NtdllLdrLoadDll; memcpy(ShellCode + 72, Convert.to, sizeof(Convert.to)); // 写入NtdllRtlExitThread地址 Convert.from = NtdllRtlExitThread; memcpy(ShellCode + 94, Convert.to, sizeof(Convert.to)); SIZE_T WriteSize = 0; if (!WriteProcessMemory64(hTarget, ParamemterMemAddr, ParamemterMemLocal, ParamemterSize, NULL) || !WriteProcessMemory64(hTarget, ShellCodeAddr, ShellCode, sizeof(ShellCode), NULL)) { return FALSE; } DWORD64 hRemoteThread = 0; struct { DWORD64 UniqueProcess; DWORD64 UniqueThread; }ClientID; int nRet = X64Call(NtdllRtlCreateUserThread, 10, (DWORD64)hTarget, // ProcessHandle (DWORD64)NULL, // SecurityDescriptor (DWORD64)FALSE, // CreateSuspended (DWORD64)0, // StackZeroBits (DWORD64)NULL, // StackReserved (DWORD64)NULL, // StackCommit ShellCodeAddr, // StartAddress (DWORD64)NULL, // StartParameter (DWORD64)&hRemoteThread, // ThreadHandle (DWORD64)&ClientID); // ClientID) if (hRemoteThread != 0) { CloseHandle((HANDLE)hRemoteThread); return TRUE; } return TRUE; }