BOOL InitializeW64oWoW64() { void * lvpNtdll = GetModuleBase64( L"ntdll.dll" ); UNICODE_STRING64 sUnicodeString; __int8 * lvpKernelBaseBase; __int8 * lvpKernel32Base; PLDR_DATA_TABLE_ENTRY64 lpsKernel32Ldr; PLDR_DATA_TABLE_ENTRY64 lpsKernelBaseLdr; sFunctions.LdrGetKnownDllSectionHandle = GetProcAddress64( lvpNtdll, "LdrGetKnownDllSectionHandle" ); sFunctions.NtFreeVirtualMemory = GetProcAddress64( lvpNtdll, "NtFreeVirtualMemory" ); sFunctions.NtMapViewOfSection = GetProcAddress64( lvpNtdll, "NtMapViewOfSection" ); sFunctions.NtUnmapViewOfSection = GetProcAddress64( lvpNtdll, "NtUnmapViewOfSection" ); if( FreeKnownDllPage( L"kernel32.dll" ) == FALSE) return FALSE; if( FreeKnownDllPage( L"user32.dll" ) == FALSE ) return FALSE; sUnicodeString.Length = 0x18; sUnicodeString.MaximumLength = 0x1a; sUnicodeString.Buffer = (DWORD64)L"kernel32.dll"; if( X64Call( GetProcAddress64( lvpNtdll, "LdrLoadDll" ), 4, (DWORD64)0, (DWORD64)0, (DWORD64)&sUnicodeString, (DWORD64)&lvpKernel32Base ) != NULL ) { PrintLastError(); return FALSE; } lvpKernelBaseBase = (__int8 *)GetModuleBase64( L"KERNELBASE.dll"); X64Call( ( lvpKernelBaseBase + (int)GetModule64EntryRVA( lvpKernelBaseBase ) ), 3, (DWORD64)lvpKernelBaseBase, (DWORD64)DLL_PROCESS_ATTACH, (DWORD64)0 ); X64Call( ( lvpKernel32Base + (int)GetModule64EntryRVA( lvpKernel32Base ) ), 3, (DWORD64)lvpKernel32Base, (DWORD64)DLL_PROCESS_ATTACH, (DWORD64)0 ); lpsKernel32Ldr = GetModule64LdrTable( L"kernel32.dll" ); lpsKernel32Ldr->LoadCount = 0xffff; lpsKernel32Ldr->Flags += LDRP_ENTRY_PROCESSED | LDRP_PROCESS_ATTACH_CALLED; lpsKernelBaseLdr = GetModule64LdrTable( L"KERNELBASE.dll" ); lpsKernelBaseLdr->LoadCount = 0xffff; lpsKernelBaseLdr->Flags += LDRP_ENTRY_PROCESSED | LDRP_PROCESS_ATTACH_CALLED; return TRUE; }
extern __declspec(dllexport) void * LoadLibrary64A( char * lpcLibraryName ) { if( sFunctions.LoadLibraryA == NULL ) { sFunctions.LoadLibraryA = GetProcAddress64( GetModuleBase64( L"kernel32.dll" ), "LoadLibraryA" ); } return (void *)X64Call( sFunctions.LoadLibraryA, 1, (DWORD64)lpcLibraryName ); }
DWORD64 Wow64Local::LoadLibrary64(const wchar_t* path) { _UNICODE_STRING_T<DWORD64> upath = {0}; DWORD64 hModule = 0; DWORD64 pfnLdrLoad = GetProcAddress64(GetNTDLL64(), "LdrLoadDll"); upath.Length = (WORD)wcslen(path) * sizeof(wchar_t); upath.MaximumLength = (WORD)upath.Length; upath.Buffer = (DWORD64)path; X64Call(pfnLdrLoad, NULL, 0, &upath, &hModule); return hModule; };
extern "C" SIZE_T __cdecl VirtualQueryEx64(HANDLE hProcess, DWORD64 lpAddress, MEMORY_BASIC_INFORMATION64* lpBuffer, SIZE_T dwLength) { static DWORD64 ntqvm = 0; if (0 == ntqvm) { ntqvm = GetProcAddress64(getNTDLL64(), "NtQueryVirtualMemory"); if (0 == ntqvm) return 0; } DWORD64 ret = 0; DWORD64 status = X64Call(ntqvm, 6, (DWORD64)hProcess, lpAddress, (DWORD64)0, (DWORD64)lpBuffer, (DWORD64)dwLength, (DWORD64)&ret); if (STATUS_SUCCESS != status) SetLastErrorFromX64Call(status); return (SIZE_T)ret; }
extern "C" BOOL __cdecl SetThreadContext64(HANDLE hThread, _CONTEXT64_2* lpContext) { static DWORD64 stc = 0; if (0 == stc) { stc = GetProcAddress64(getNTDLL64(), "NtSetContextThread"); if (0 == stc) return 0; } DWORD64 ret = X64Call(stc, 2, (DWORD64)hThread, (DWORD64)lpContext); if (STATUS_SUCCESS != ret) { SetLastErrorFromX64Call(ret); return FALSE; } else return TRUE; }
DWORD64 WoW64dm::LoadLibrary64( const wchar_t* path ) { BOOL isWOW = FALSE; IsWow64Process(_hProcess, &isWOW); // Inject into x64 if(isWOW == FALSE) { DWORD64 memptr = 0; VirtualAllocEx64(memptr, 0x1000, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE); if(memptr != 0) { DWORD size = 0; DWORD64 hKernel32 = GetModuleHandle64(L"Kernel32.dll", &size); DWORD64 pLoadLib = GetProcAddress64(hKernel32, size, "LoadLibraryW"); if(pLoadLib != 0 && WriteProcessMemory64(memptr, (LPVOID)path, (wcslen(path) + 1)*sizeof(wchar_t), 0) == STATUS_SUCCESS) { DWORD64 status = 0; if(CreateRemoteThread64(pLoadLib, memptr, status, true) != FALSE && status == STATUS_SUCCESS) { VirtualFreeEx64(memptr, 0x1000, MEM_RELEASE); return status; } } VirtualFreeEx64(memptr, 0x1000, MEM_FREE); } return FALSE; } // Inject into WOW64 else { return LoadLibraryRemoteWOW64(path); } }
extern "C" BOOL __cdecl VirtualProtectEx64(HANDLE hProcess, DWORD64 lpAddress, SIZE_T dwSize, DWORD flNewProtect, DWORD* lpflOldProtect) { static DWORD64 ntpvm = 0; if (0 == ntpvm) { ntpvm = GetProcAddress64(getNTDLL64(), "NtProtectVirtualMemory"); if (0 == ntpvm) return 0; } DWORD64 tmpAddr = lpAddress; DWORD64 tmpSize = dwSize; DWORD64 ret = X64Call(ntpvm, 5, (DWORD64)hProcess, (DWORD64)&tmpAddr, (DWORD64)&tmpSize, (DWORD64)flNewProtect, (DWORD64)lpflOldProtect); if (STATUS_SUCCESS != ret) { SetLastErrorFromX64Call(ret); return FALSE; } else return TRUE; }
extern "C" BOOL __cdecl VirtualFreeEx64(HANDLE hProcess, DWORD64 lpAddress, SIZE_T dwSize, DWORD dwFreeType) { static DWORD64 ntfvm = 0; if (0 == ntfvm) { ntfvm = GetProcAddress64(getNTDLL64(), "NtFreeVirtualMemory"); if (0 == ntfvm) return 0; } DWORD64 tmpAddr = lpAddress; DWORD64 tmpSize = dwSize; DWORD64 ret = X64Call(ntfvm, 4, (DWORD64)hProcess, (DWORD64)&tmpAddr, (DWORD64)&tmpSize, (DWORD64)dwFreeType); if (STATUS_SUCCESS != ret) { SetLastErrorFromX64Call(ret); return FALSE; } else return TRUE; }
extern "C" DWORD64 __cdecl VirtualAllocEx64(HANDLE hProcess, DWORD64 lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect) { static DWORD64 ntavm = 0; if (0 == ntavm) { ntavm = GetProcAddress64(getNTDLL64(), "NtAllocateVirtualMemory"); if (0 == ntavm) return 0; } DWORD64 tmpAddr = lpAddress; DWORD64 tmpSize = dwSize; DWORD64 ret = X64Call(ntavm, 6, (DWORD64)hProcess, (DWORD64)&tmpAddr, (DWORD64)0, (DWORD64)&tmpSize, (DWORD64)flAllocationType, (DWORD64)flProtect); if (STATUS_SUCCESS != ret) { SetLastErrorFromX64Call(ret); return FALSE; } else return tmpAddr; }
extern "C" BOOL __cdecl WriteProcessMemory64(HANDLE hProcess, DWORD64 lpBaseAddress, LPVOID lpBuffer, SIZE_T nSize, SIZE_T *lpNumberOfBytesWritten) { static DWORD64 nrvm = 0; if (0 == nrvm) { nrvm = GetProcAddress64(getNTDLL64(), "NtWriteVirtualMemory"); if (0 == nrvm) return 0; } DWORD64 numOfBytes = lpNumberOfBytesWritten ? *lpNumberOfBytesWritten : 0; DWORD64 ret = X64Call(nrvm, 5, (DWORD64)hProcess, lpBaseAddress, (DWORD64)lpBuffer, (DWORD64)nSize, (DWORD64)&numOfBytes); if (STATUS_SUCCESS != ret) { SetLastErrorFromX64Call(ret); return FALSE; } else { if (lpNumberOfBytesWritten) *lpNumberOfBytesWritten = (SIZE_T)numOfBytes; return TRUE; } }
bool injectdll_x64(const PROCESS_INFORMATION& pi, const std::wstring& dll) { static unsigned char sc[] = { 0x9c, // pushfq 0x50, // push rax 0x51, // push rcx 0x52, // push rdx 0x53, // push rbx 0x55, // push rbp 0x56, // push rsi 0x57, // push rdi 0x41, 0x50, // push r8 0x41, 0x51, // push r9 0x41, 0x52, // push r10 0x41, 0x53, // push r11 0x41, 0x54, // push r12 0x41, 0x55, // push r13 0x41, 0x56, // push r14 0x41, 0x57, // push r15 0x48, 0x83, 0xEC, 0x28, // sub rsp, 0x28 0x49, 0xB9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov r9, 0 // DllHandle 0x49, 0xB8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov r8, 0 // DllPath 0x48, 0xB8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov rax,0 // LdrLoadDll 0x48, 0x31, // xor rcx,rcx 0xC9, 0x48, // xor rdx,rdx 0xFF, 0xD0, // call rax LdrLoadDll 0x48, 0x83, 0xC4, 0x28, // add rsp, 0x28 0x41, 0x5F, // pop r15 0x41, 0x5E, // pop r14 0x41, 0x5D, // pop r13 0x41, 0x5C, // pop r12 0x41, 0x5B, // pop r11 0x41, 0x5A, // pop r10 0x41, 0x59, // pop r9 0x41, 0x58, // pop r8 0x5F, // pop rdi 0x5E, // pop rsi 0x5D, // pop rbp 0x5B, // pop rbx 0x5A, // pop rdx 0x59, // pop rcx 0x58, // pop rax 0x9D, // popfq 0xFF, 0x25, 0x00, 0x00, 0x00, 0x00, // jmp offset 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 // rip }; InitWow64ext(); DWORD64 pfLoadLibrary = (DWORD64)GetProcAddress64(GetModuleHandle64(L"ntdll.dll"), "LdrLoadDll"); if (!pfLoadLibrary) { return false; } struct UNICODE_STRING { USHORT Length; USHORT MaximumLength; DWORD64 Buffer; }; SIZE_T memsize = sizeof(DWORD64) + sizeof(UNICODE_STRING) + (dll.size() + 1) * sizeof(wchar_t); DWORD64 memory = VirtualAllocEx64(pi.hProcess, NULL, memsize, MEM_COMMIT, PAGE_READWRITE); if (!memory) { return false; } DWORD64 shellcode = VirtualAllocEx64(pi.hProcess, NULL, sizeof(sc), MEM_COMMIT, PAGE_EXECUTE_READWRITE); if (!shellcode) { return false; } UNICODE_STRING us; us.Length = (USHORT)(dll.size() * sizeof(wchar_t)); us.MaximumLength = us.Length + sizeof(wchar_t); us.Buffer = memory + sizeof(UNICODE_STRING); SIZE_T written = 0; BOOL ok = FALSE; ok = WriteProcessMemory64(pi.hProcess, memory, &us, sizeof(UNICODE_STRING), &written); if (!ok || written != sizeof(UNICODE_STRING)) { return false; } ok = WriteProcessMemory64(pi.hProcess, us.Buffer, (void*)dll.data(), us.MaximumLength, &written); if (!ok || written != us.MaximumLength) { return false; } _CONTEXT64 ctx = { 0 }; ctx.ContextFlags = CONTEXT_CONTROL; if (!GetThreadContext64(pi.hThread, &ctx)) { return false; } DWORD64 handle = us.Buffer + us.MaximumLength; memcpy(sc + 30, &handle, sizeof(handle)); memcpy(sc + 40, &memory, sizeof(memory)); memcpy(sc + 50, &pfLoadLibrary, sizeof(pfLoadLibrary)); memcpy(sc + 98, &ctx.Rip, sizeof(ctx.Rip)); ok = WriteProcessMemory64(pi.hProcess, shellcode, &sc, sizeof(sc), &written); if (!ok || written != sizeof(sc)) { return false; } ctx.ContextFlags = CONTEXT_CONTROL; ctx.Rip = shellcode; if (!SetThreadContext64(pi.hThread, &ctx)) { return false; } return true; }
/* Memory layout. Function additionally writes Activation Context pointer into TEB for RtlQueryInformationActivationContext. ------------------------------------------------------------------------------------ | Return handle | UNICODE_STRING | dll path | padding | executable code | ------------------------------------------------------------------------------------ */ DWORD64 WoW64dm::LoadLibraryRemoteWOW64( const wchar_t* path ) { DWORD64 memptr = 0; int idx = 0; _UNICODE_STRING_T<DWORD64> upath = {0}; VirtualAllocEx64(memptr, 0x1000, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE); if(memptr != 0) { DWORD size = 0; DWORD64 hNtdll = GetModuleHandle64(L"ntdll.dll", &size); DWORD64 pfnLdrLoadDll = GetProcAddress64(hNtdll, size, "LdrLoadDll"); upath.Length = wcslen(path) * sizeof(wchar_t); upath.MaximumLength = upath.Length; upath.Buffer = memptr + 0x100; DWORD64 codeAddr = memptr + 0xA00; uint8_t code[] = { // Enter x64 mode 0x6A, 0x33, 0xE8, 0x00, 0x00, 0x00, 0x00, 0x83, 0x04, 0x24, 0x05, 0xCB, 0x65, 0x48, 0x8B, 0x04, 0x25, 0x30, 0x00, 0x00, 0x00, // mov rax, gs:[30] 0x48, 0xBA, 0xEF, 0xBE, 0xAD, 0xDE, 0xEF, 0xBE, 0xAD, 0xDE, // movabs rdx, memptr + 0x700 0x48, 0x89, 0x90, 0xC8, 0x02, 0x00, 0x00, // mov QWORD PTR [rax + 0x2c8],rdx 0x48, 0x89, 0xE5, // mov rbp, rsp 0x48, 0x83, 0xE4, 0xF0, // and rsp, 0xfffffffffffffff0 0x48, 0x83, 0xEC, 0x28, // sub rsp, 0x30 0x48, 0x31, 0xC9, // xor rcx, rcx 0x48, 0x31, 0xD2, // xor rdx, rdx 0x49, 0xB8, 0xEF, 0xBE, 0xAD, 0xDE, 0xEF, 0xBE, 0xAD, 0xDE, // movabs r8, &upath 0x49, 0xB9, 0xEF, 0xBE, 0xAD, 0xDE, 0xEF, 0xBE, 0xAD, 0xDE, // movabs r9, &memptr 0x48, 0xB8, 0xEF, 0xBE, 0xAD, 0xDE, 0xEF, 0xBE, 0xAD, 0xDE, // movabs rax, LdrLoadDll //0xCC, 0xFF, 0xD0, // call rax 0x48, 0x89, 0xEC, // mov rsp, rbp // Leave x64 mode 0xE8, 0x00, 0x00, 0x00, 0x00, 0xC7, 0x44, 0x24, 0x04, 0x23, 0x00, 0x00, 0x00, 0x83, 0x04, 0x24, 0x0D, 0xCB, 0xC2, 0x04, 0x00 // retn 0x4 }; DWORD64 patch[] = { memptr + 0x700, memptr + 0x10, memptr, pfnLdrLoadDll }; // Patch immediate memory values for(uint8_t* ptr = code; ptr < (code + sizeof(code) - 8); ptr++) { if(*(DWORD64*)ptr == (DWORD64)0xDEADBEEFDEADBEEF) { *(DWORD64*)ptr = patch[idx]; idx++; } } if(WriteProcessMemory64(memptr + 0x10, &upath, sizeof(upath), 0) == STATUS_SUCCESS && WriteProcessMemory64(upath.Buffer, (LPVOID)path, upath.Length + sizeof(wchar_t), 0) == STATUS_SUCCESS && WriteProcessMemory64(codeAddr, code, sizeof(code), 0) == STATUS_SUCCESS) { DWORD64 status = 0; if(CreateRemoteThread64(codeAddr, 0, status, true) != FALSE && (status & 0xFFFFFFFF) == STATUS_SUCCESS) { DWORD64 module = 0; ReadProcessMemory64(memptr, &module, sizeof(module), 0); VirtualFreeEx64(memptr, 0x1000, MEM_RELEASE); return module; } } VirtualFreeEx64(memptr, 0x1000, MEM_FREE); } return 0; }
DWORD64 WoW64dm::GetProcAddress64( DWORD64 hModule, DWORD size, const char* funcName ) { if(hModule == 0 || size == 0) return 0; std::unique_ptr<uint8_t[]> buf(new uint8_t[size]()); if(ReadProcessMemory64(hModule, buf.get(), size, 0) != STATUS_SUCCESS) return 0; IMAGE_NT_HEADERS64* inh = (IMAGE_NT_HEADERS64*)(buf.get() + ((IMAGE_DOS_HEADER*)buf.get())->e_lfanew); IMAGE_DATA_DIRECTORY& idd = inh->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]; if (idd.VirtualAddress == 0) return 0; IMAGE_EXPORT_DIRECTORY* ied = (IMAGE_EXPORT_DIRECTORY*)(buf.get() + idd.VirtualAddress); DWORD* rvaTable = (DWORD*)(buf.get() + ied->AddressOfFunctions); WORD* ordTable = (WORD*) (buf.get() + ied->AddressOfNameOrdinals); DWORD* nameTable = (DWORD*)(buf.get() + ied->AddressOfNames); for (DWORD i = 0; i < ied->NumberOfFunctions; i++) { WORD OrdIndex = 0xFFFF; char *pName = nullptr; // Find by index if((size_t)funcName <= 0xFFFF) { OrdIndex = (WORD)i; } // Find by name else if((size_t)funcName > 0xFFFF && i < ied->NumberOfNames) { pName = (char*)(nameTable[i] + (size_t)buf.get()); OrdIndex = (WORD)ordTable[i]; } else return 0; if(((size_t)funcName <= 0xFFFF && (WORD)funcName == (OrdIndex + ied->Base)) || ((size_t)funcName > 0xFFFF && strcmp(pName, funcName) == 0)) { DWORD64 pFunc = (DWORD64)(rvaTable[OrdIndex] + hModule); // Check forwarded export if(pFunc >= hModule + idd.VirtualAddress && pFunc <= hModule + idd.VirtualAddress + idd.Size) { char forwardStr[255] = {0}; DWORD size = 0; ReadProcessMemory64(pFunc, forwardStr, sizeof(forwardStr), 0); std::string chainExp(forwardStr); std::wstring wchainExp(chainExp.begin(), chainExp.end()); std::wstring strDll = wchainExp.substr(0, wchainExp.find(L".")) + L".dll"; std::string strName = chainExp.substr(chainExp.find(".") + 1, strName.npos); DWORD64 hChainMod = GetModuleHandle64(strDll.c_str(), &size); // Import by ordinal if(strName.find("#") == 0) return GetProcAddress64(hChainMod, size, (const char*)atoi(strName.c_str() + 1)); // Import by name else return GetProcAddress64(hChainMod, size, strName.c_str()); } return pFunc; } } return 0; }
static INJECT_RESULT Win32Inject64(DWORD dwProcessID, const wchar_t* dllFilePath) { int path_length = std::wcslen(dllFilePath); HANDLE hTargetProcess = ::OpenProcess(PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ, FALSE, dwProcessID); if (hTargetProcess == NULL) { return INJECT_FAIL_OPENPROCESS; } int alloc_size = sizeof(DWORD64); alloc_size += sizeof(_UNICODE_STRING_T<DWORD64>); alloc_size += (path_length + 1) * sizeof(wchar_t); DWORD64 lpVirtualMemExec = VirtualAllocEx64(hTargetProcess, NULL, sizeof(exec_code), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); DWORD64 lpVirtualMemParameters = VirtualAllocEx64(hTargetProcess, NULL, alloc_size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); if(lpVirtualMemExec == NULL || lpVirtualMemParameters == NULL) { if(lpVirtualMemExec != NULL) { VirtualFreeEx64(hTargetProcess, lpVirtualMemExec, sizeof(exec_code), MEM_RESERVE | MEM_COMMIT); } if(lpVirtualMemParameters != NULL) { VirtualFreeEx64(hTargetProcess, lpVirtualMemParameters, alloc_size, MEM_RESERVE | MEM_COMMIT); } ::CloseHandle(hTargetProcess); return INJECT_FAIL_VIRTUALALLOC; } DWORD64 ntdll64 = GetModuleHandle64(L"ntdll.dll"); DWORD64 ntdll_LdrLoadDll = GetProcAddress64(ntdll64, "LdrLoadDll"); DWORD64 ntdll_RtlExitUserThread = GetProcAddress64(ntdll64, "RtlExitUserThread"); DWORD64 ntdll_RtlCreateUserThread = GetProcAddress64(ntdll64, "RtlCreateUserThread"); if(ntdll_LdrLoadDll == 0 || ntdll_RtlExitUserThread == 0 || ntdll_RtlCreateUserThread == 0) { VirtualFreeEx64(hTargetProcess, lpVirtualMemExec, sizeof(exec_code), MEM_RESERVE | MEM_COMMIT); VirtualFreeEx64(hTargetProcess, lpVirtualMemParameters, alloc_size, MEM_RESERVE | MEM_COMMIT); ::CloseHandle(hTargetProcess); return INJECT_FAIL_GETPROCADDRESS; } unsigned char* parameters = new unsigned char[alloc_size]; std::memset(parameters, 0, alloc_size); _UNICODE_STRING_T<DWORD64>* upath = reinterpret_cast<_UNICODE_STRING_T<DWORD64>*>(parameters + sizeof(DWORD64)); upath->Length = (path_length) * sizeof(wchar_t); upath->MaximumLength = (path_length + 1) * sizeof(wchar_t); wchar_t* path = reinterpret_cast<wchar_t*>(parameters + sizeof(DWORD64) + sizeof(_UNICODE_STRING_T<DWORD64>)); std::wcscpy(path, dllFilePath); upath->Buffer = lpVirtualMemParameters + sizeof(DWORD64) + sizeof(_UNICODE_STRING_T<DWORD64>); unsigned char exec_code_copy[sizeof(exec_code)]; std::memcpy(exec_code_copy, exec_code, sizeof(exec_code_copy)); union { DWORD64 dw64; unsigned char bytes[8]; } cvt; // arg4 cvt.dw64 = lpVirtualMemParameters; std::memcpy(exec_code_copy + 2 + PrefixCodeLength, cvt.bytes, sizeof(cvt.bytes)); // arg3 cvt.dw64 = lpVirtualMemParameters + sizeof(DWORD64); std::memcpy(exec_code_copy + 12 + PrefixCodeLength, cvt.bytes, sizeof(cvt.bytes)); // rax = LdrLoadDll cvt.dw64 = ntdll_LdrLoadDll; std::memcpy(exec_code_copy + 42 + PrefixCodeLength, cvt.bytes, sizeof(cvt.bytes)); // rax = RtlExitUserThread cvt.dw64 = ntdll_RtlExitUserThread; std::memcpy(exec_code_copy + 64 + PrefixCodeLength, cvt.bytes, sizeof(cvt.bytes)); if(FALSE == WriteProcessMemory64(hTargetProcess, lpVirtualMemExec, exec_code_copy, sizeof(exec_code), NULL) || FALSE == WriteProcessMemory64(hTargetProcess, lpVirtualMemParameters, parameters, alloc_size, NULL)) { VirtualFreeEx64(hTargetProcess, lpVirtualMemExec, sizeof(exec_code), MEM_RESERVE | MEM_COMMIT); VirtualFreeEx64(hTargetProcess, lpVirtualMemParameters, alloc_size, MEM_RESERVE | MEM_COMMIT); ::CloseHandle(hTargetProcess); delete[] parameters; return INJECT_FAIL_WRITEPROCESSMEMERY; } DWORD64 hRemoteThread = 0; struct { DWORD64 UniqueProcess; DWORD64 UniqueThread; } client_id; X64Call(ntdll_RtlCreateUserThread, 10, (DWORD64)hTargetProcess, // ProcessHandle (DWORD64)NULL, // SecurityDescriptor (DWORD64)FALSE, // CreateSuspended (DWORD64)0, // StackZeroBits (DWORD64)NULL, // StackReserved (DWORD64)NULL, // StackCommit lpVirtualMemExec, // StartAddress (DWORD64)NULL, // StartParameter (DWORD64)&hRemoteThread, // ThreadHandle (DWORD64)&client_id // ClientID ); INJECT_RESULT result = INJECT_OK; if(hRemoteThread == 0) { result = INJECT_FAIL_CREATEREMOTETHREAD; } else { ::WaitForSingleObject((HANDLE)hRemoteThread, 3000); } VirtualFreeEx64(hTargetProcess, lpVirtualMemExec, sizeof(exec_code), MEM_RESERVE | MEM_COMMIT); VirtualFreeEx64(hTargetProcess, lpVirtualMemParameters, alloc_size, MEM_RESERVE | MEM_COMMIT); ::CloseHandle(hTargetProcess); delete[] parameters; return result; }
#include "WoW64Utils.h" /* @28 */ NTSTATUS NTAPI NtWow64ReadVirtualMemory64( _In_ HANDLE ProcessHandle, _In_ DWORD64 BaseAddress, _Out_ PVOID Buffer, _In_ DWORD64 NumberOfBytesToRead, _Out_opt_ DWORD64 *NumberOfBytesRead OPTIONAL ) { DWORD64 Proc64 = IsWoW64() ? GetProcAddress64(GetNtdll64(), "NtReadVirtualMemory") : 0; if (Proc64) return (NTSTATUS)x64Call(Proc64, 5, (DWORD64)ProcessHandle, (DWORD64)BaseAddress, (DWORD64)Buffer, (DWORD64)NumberOfBytesToRead, (DWORD64)NumberOfBytesRead); else return STATUS_NOT_IMPLEMENTED; } /* @28 */ NTSTATUS NTAPI NtWow64WriteVirtualMemory64( _In_ HANDLE ProcessHandle, _In_ DWORD64 BaseAddress, _In_ PVOID Buffer,