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; };
BOOL FreeKnownDllPage( wchar_t * lpwzKnownDllName ) { DWORD64 hSection = 0; DWORD64 lvpBaseAddress = 0; DWORD64 lvpRealBaseAddress = 0; DWORD64 stViewSize = 0; DWORD64 stRegionSize = 0; PTEB64 psTeb; X64Call( sFunctions.LdrGetKnownDllSectionHandle, 3, (DWORD64)lpwzKnownDllName, (DWORD64)0, (DWORD64)&hSection ); psTeb = NtTeb64(); psTeb->NtTib.ArbitraryUserPointer = (DWORD64)lpwzKnownDllName; X64Call( sFunctions.NtMapViewOfSection, 10, (DWORD64)hSection, (DWORD64)-1, (DWORD64)&lvpBaseAddress, (DWORD64)0, (DWORD64)0, (DWORD64)0, (DWORD64)&stViewSize, (DWORD64)ViewUnmap, (DWORD64)0, (DWORD64)PAGE_READONLY ); lvpRealBaseAddress = (DWORD64)GetModule64PEBaseAddress( (void *)lvpBaseAddress ); X64Call( sFunctions.NtFreeVirtualMemory, 4, (DWORD64)-1, (DWORD64)&lvpRealBaseAddress, (DWORD64)&stRegionSize, (DWORD64)MEM_RELEASE ); X64Call( sFunctions.NtUnmapViewOfSection, 2, (DWORD64)-1, (DWORD64)lvpBaseAddress ); return TRUE; }
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; }
DWORD64 Wow64Local::GetProcAddress64(DWORD64 hModule, const char* funcName) { if(0 == _LdrGetProcedureAddress) { _LdrGetProcedureAddress = GetLdrGetProcedureAddress(); if(0 == _LdrGetProcedureAddress) return 0; } // It's actually an ANSI string _UNICODE_STRING_T<DWORD64> fName = {0}; fName.Buffer = (DWORD64)funcName; fName.Length = (WORD)strlen(funcName); fName.MaximumLength = fName.Length + 1; DWORD64 funcRet = 0; X64Call(_LdrGetProcedureAddress, hModule, &fName, 0, &funcRet); return funcRet; }
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; }
extern "C" DWORD64 __cdecl GetProcAddress64(DWORD64 hModule, char* funcName) { static DWORD64 _LdrGetProcedureAddress = 0; if (0 == _LdrGetProcedureAddress) { _LdrGetProcedureAddress = getLdrGetProcedureAddress(); if (0 == _LdrGetProcedureAddress) return 0; } _UNICODE_STRING_T<DWORD64> fName = { 0 }; fName.Buffer = (DWORD64)funcName; fName.Length = (WORD)strlen(funcName); fName.MaximumLength = fName.Length + 1; DWORD64 funcRet = 0; X64Call(_LdrGetProcedureAddress, 4, (DWORD64)hModule, (DWORD64)&fName, (DWORD64)0, (DWORD64)&funcRet); return funcRet; }
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; } }
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; }