#include "CRemoteLoader.h" #include #include #pragma comment (lib, "DbgHelp.lib") // // Pube lick functions // void CRemoteLoader::SetProcess(HANDLE hProcess, DWORD dwProcessId) { HMODULE hNtDll = (HMODULE)Utils::GetLocalModuleHandle("ntdll.dll"); fnNTQIP = (tNTQIP)Utils::GetProcAddress(hNtDll, "NtQueryInformationProcess"); fnNTQSI = (tNTQSI)Utils::GetProcAddress(hNtDll, "NtQuerySystemInformation"); m_hProcess = hProcess; m_dwProcessId = dwProcessId; m_bIs64bit = GetProcessPlatform() == 2 ? true : false; } HMODULE CRemoteLoader::LdrpLoadDll(LPCCH Path) { WCHAR WideCharModule[MAX_PATH] = { 0 }; size_t charsConverted; mbstowcs_s(&charsConverted, WideCharModule, Path, MAX_PATH); return LdrpLoadDll(WideCharModule); } HMODULE CRemoteLoader::LdrpLoadDll(LPCWCH Path) { if (Path == NULL) { #ifdef DEBUG_MESSAGES_ENABLED DebugShout("[LdrpLoadDll] Path is NULL"); #endif return NULL; } FARPROC RemoteLdrpLoadDll = (FARPROC)Utils::GetProcAddress(Utils::GetLocalModuleHandle("ntdll.dll"), "LdrpLoadDll");//GetRemoteProcAddressA("ntdll.dll", "LdrLoadDll"); if (RemoteLdrpLoadDll == NULL) { #ifdef DEBUG_MESSAGES_ENABLED DebugShout("[LdrpLoadDll] RemoteLdrLoadDll resolve failure"); #endif return NULL; } #ifdef DEBUG_MESSAGES_ENABLED DebugShout("[LdrpLoadDll] LdrpLoadDll = 0x%IX", RemoteLdrpLoadDll); #endif NTSTATUS Status; UNICODE_STRING DllString1; ZeroMemory(&DllString1, sizeof(UNICODE_STRING)); UNICODE_STRING DllString2; ZeroMemory(&DllString2, sizeof(UNICODE_STRING)); UNICODE_STRING LdrApiDefaultExtension; ZeroMemory(&LdrApiDefaultExtension, sizeof(UNICODE_STRING)); UNICODE_STRING* DllName = new UNICODE_STRING; PUNICODE_STRING pPath = nullptr; ULONG_PTR cookie = 0; wchar_t wBuf[255] = { 0 }; std::wstring path(Path); if (path.rfind(L".dll") != std::wstring::npos) path.erase(path.rfind(L".dll")); static HMODULE hNtdll = Utils::GetLocalModuleHandle("ntdll.dll"); static tRtlInitUnicodeString RtlInitUnicodeString = (tRtlInitUnicodeString)Utils::GetProcAddress(hNtdll, "RtlInitUnicodeString"); static tRtlFreeUnicodeString RtlFreeUnicodeString = (tRtlFreeUnicodeString)Utils::GetProcAddress(hNtdll, "RtlFreeUnicodeString"); static tRtlNtStatusToDosError RtlNtStatusToDosError = (tRtlNtStatusToDosError)Utils::GetProcAddress(hNtdll, "RtlNtStatusToDosError"); static tRtlDosApplyFileIsolationRedirection_Ustr RtlDosApplyFileIsolationRedirection_Ustr = (tRtlDosApplyFileIsolationRedirection_Ustr)Utils::GetProcAddress(hNtdll, "RtlDosApplyFileIsolationRedirection_Ustr"); RtlInitUnicodeString(DllName, path.c_str()); RtlInitUnicodeString(&LdrApiDefaultExtension, L".DLL"); DllString1.Buffer = wBuf; DllString1.Length = NULL; DllString1.MaximumLength = ARRAYSIZE(wBuf); BOOLEAN RedirectedDll = FALSE; /* Check if the SxS Assemblies specify another file */ Status = RtlDosApplyFileIsolationRedirection_Ustr(TRUE, DllName, &LdrApiDefaultExtension, &DllString1, &DllString2, &DllName, NULL, NULL, NULL); /* Check success */ if (NT_SUCCESS(Status)) RedirectedDll = TRUE; ULONG Flags = NULL; // Maybe use flags later. Idk. void* flagsPtr = CommitMemory((void*)&Flags, sizeof(ULONG)); void* ReturnPointerValue = RemoteAllocateMemory(sizeof(size_t)); if (m_bIs64bit) { // Backup RCX, RDX, R8 and R9 on stack BeginCall64(); // PushInt64((unsigned __int64)RedirectedDll); PushInt64((unsigned __int64)NULL); PushInt64((unsigned __int64)flagsPtr); PushUNICODEStringStructure(DllName); PushInt64((unsigned __int64)ReturnPointerValue); PushInt64((unsigned __int64)TRUE); PushCall(CCONV_WIN64, RemoteLdrpLoadDll); // // Module Handle is located in RDX and at QWORD PTR [ReturnPointerValue]. // Could do 'mov rax, [ReturnPointerValue]' but it takes many more opcodes to do so. // We could also just RPM twice on ReturnPointerValue but it's better just to get it from rdx. // // mov rax, rdx AddByteToBuffer(0x48); AddByteToBuffer(0x89); AddByteToBuffer(0xD0); // mov [ReturnPointerValue], rax AddByteToBuffer(0x48); AddByteToBuffer(0xA3); AddLong64ToBuffer((unsigned __int64)ReturnPointerValue); // Restore RCX, RDX, R8 and R9 from stack and return EndCall64(); } else { PushInt(RedirectedDll); PushInt(NULL); PushInt((unsigned int)flagsPtr); PushUNICODEStringStructure(DllName); PushInt((unsigned long)ReturnPointerValue); PushInt(TRUE); PushCall(CCONV_STDCALL, RemoteLdrpLoadDll); // // Module Handle is located in [EDX]. // To avoid calling RPM twice, we pass the [edx] into eax instead of just edx. // // mov eax,DWORD PTR [edx] AddByteToBuffer(0x8B); AddByteToBuffer(0x02); // mov ptr, eax AddByteToBuffer(0xA3); AddLongToBuffer((unsigned long)ReturnPointerValue); // xor eax, eax AddByteToBuffer(0x33); AddByteToBuffer(0xC0); // ret 4 AddByteToBuffer(0xC2); AddByteToBuffer(0x04); AddByteToBuffer(0x00); } if (!ExecuteRemoteThreadBuffer(m_CurrentRemoteThreadBuffer, true)) { #ifdef DEBUG_MESSAGES_ENABLED DebugShout("[LdrpLoadDll] ExecuteRemoteThreadBuffer failed"); #endif RemoteFreeMemory(ReturnPointerValue, sizeof(size_t)); return NULL; } #ifdef DEBUG_MESSAGES_ENABLED DebugShout("[LdrpLoadDll] ExecuteRemoteThreadBuffer succeeded"); #endif HMODULE RemoteModuleHandle = 0; if (ReadProcessMemory(m_hProcess, ReturnPointerValue, &RemoteModuleHandle, sizeof(HMODULE), NULL)) { RemoteFreeMemory(ReturnPointerValue, sizeof(size_t)); } else { RemoteFreeMemory(ReturnPointerValue, sizeof(size_t)); if (RemoteModuleHandle == 0) RemoteModuleHandle = GetRemoteModuleHandleW(Path); } return RemoteModuleHandle; } HMODULE CRemoteLoader::LoadDependencyA(LPCCH Path) { WCHAR Module[MAX_PATH] = { 0 }; size_t charsConverted; mbstowcs_s(&charsConverted, Module, Path, MAX_PATH); return LoadDependencyW(Module); } HMODULE CRemoteLoader::LoadDependencyW(LPCWCH Path) { if (Path == NULL) { #ifdef DEBUG_MESSAGES_ENABLED DebugShout("[LoadDependencyW] szString is NULL"); #endif return NULL; } FARPROC RemoteLdrLoadDll = (FARPROC)Utils::GetProcAddress(Utils::GetLocalModuleHandle("ntdll.dll"), "LdrLoadDll");//GetRemoteProcAddressA("ntdll.dll", "LdrLoadDll"); if (RemoteLdrLoadDll == NULL) { #ifdef DEBUG_MESSAGES_ENABLED DebugShout("[LoadDependencyW] RemoteLdrLoadDll resolve failure"); #endif return NULL; } #ifdef DEBUG_MESSAGES_ENABLED DebugShout("[LoadDependencyW] LdrLoadDll = 0x%IX", RemoteLdrLoadDll); #endif // Make new unicode string object static tRtlInitUnicodeString RtlInitUnicodeString = (tRtlInitUnicodeString)Utils::GetProcAddress(Utils::GetLocalModuleHandle("ntdll.dll"), "RtlInitUnicodeString"); UNICODE_STRING unicodePath; RtlInitUnicodeString(&unicodePath, Path); ULONG Flags = NULL; // Maybe use flags later. Idk. void* flagsPtr = CommitMemory((void*)&Flags, sizeof(ULONG)); void* ReturnPointerValue = RemoteAllocateMemory(sizeof(size_t)); if (m_bIs64bit) { // Backup RCX, RDX, R8 and R9 on stack BeginCall64(); // PushInt64(NULL); PushInt64((unsigned __int64)flagsPtr); PushUNICODEStringStructure(&unicodePath); PushInt64((unsigned __int64)ReturnPointerValue); PushCall(CCONV_WIN64, RemoteLdrLoadDll); // // Module Handle is located in RDX and at QWORD PTR [ReturnPointerValue]. // Could do 'mov rax, [ReturnPointerValue]' but it takes many more opcodes to do so. // We could also just RPM twice on ReturnPointerValue but it's better just to get it from rdx. // // mov rax, rdx AddByteToBuffer(0x48); AddByteToBuffer(0x89); AddByteToBuffer(0xD0); // mov [ReturnPointerValue], rax AddByteToBuffer(0x48); AddByteToBuffer(0xA3); AddLong64ToBuffer((unsigned __int64)ReturnPointerValue); // Restore RCX, RDX, R8 and R9 from stack and return EndCall64(); } else { PushInt(NULL); PushInt((unsigned int)flagsPtr); PushUNICODEStringStructure(&unicodePath); PushInt((unsigned long)ReturnPointerValue); PushCall(CCONV_STDCALL, RemoteLdrLoadDll); // // Module Handle is located in [EDX]. // To avoid calling RPM twice, we pass the [edx] into eax instead of just edx. // // mov eax,DWORD PTR [edx] AddByteToBuffer(0x8B); AddByteToBuffer(0x02); // mov ptr, eax AddByteToBuffer(0xA3); AddLongToBuffer((unsigned long)ReturnPointerValue); // xor eax, eax AddByteToBuffer(0x33); AddByteToBuffer(0xC0); // ret 4 AddByteToBuffer(0xC2); AddByteToBuffer(0x04); AddByteToBuffer(0x00); } if (!ExecuteRemoteThreadBuffer(m_CurrentRemoteThreadBuffer, true)) { #ifdef DEBUG_MESSAGES_ENABLED DebugShout("[LoadLibraryByPathW] ExecuteRemoteThreadBuffer failed"); #endif RemoteFreeMemory(ReturnPointerValue, sizeof(size_t)); return NULL; } #ifdef DEBUG_MESSAGES_ENABLED DebugShout("[LoadModuleByNameW] ExecuteRemoteThreadBuffer succeeded"); #endif HMODULE RemoteModuleHandle = 0; if (ReadProcessMemory(m_hProcess, ReturnPointerValue, &RemoteModuleHandle, sizeof(HMODULE), NULL)) { RemoteFreeMemory(ReturnPointerValue, sizeof(size_t)); } else { RemoteFreeMemory(ReturnPointerValue, sizeof(size_t)); if (RemoteModuleHandle == 0) RemoteModuleHandle = GetRemoteModuleHandleW(Path); } return RemoteModuleHandle; } HMODULE CRemoteLoader::LoadLibraryByPathA(LPCCH Path, ULONG Flags/*= NULL*/) { WCHAR Module[MAX_PATH] = { 0 }; size_t charsConverted; mbstowcs_s(&charsConverted, Module, Path, MAX_PATH); return LoadLibraryByPathW(Module, Flags); } HMODULE CRemoteLoader::LoadLibraryByPathW(LPCWCH Path, ULONG Flags/*= NULL*/) { if (Path == NULL) { #ifdef DEBUG_MESSAGES_ENABLED DebugShout("[LoadLibraryByPathW] szString is NULL"); #endif return NULL; } FARPROC RemoteLdrLoadDll = (FARPROC)Utils::GetProcAddress(Utils::GetLocalModuleHandle("ntdll.dll"), "LdrLoadDll"); //GetRemoteProcAddressA("ntdll.dll", "LdrLoadDll"); if (RemoteLdrLoadDll == NULL) { #ifdef DEBUG_MESSAGES_ENABLED DebugShout("[LoadLibraryByPathW] RemoteLdrLoadDll resolve failure"); #endif return NULL; } #ifdef DEBUG_MESSAGES_ENABLED DebugShout("[LoadLibraryByPathW] LdrLoadDll = 0x%IX", RemoteLdrLoadDll); #endif // Make new unicode string object static tRtlInitUnicodeString RtlInitUnicodeString = (tRtlInitUnicodeString)Utils::GetProcAddress(Utils::GetLocalModuleHandle("ntdll.dll"), "RtlInitUnicodeString"); UNICODE_STRING unicodePath; RtlInitUnicodeString(&unicodePath, Path); void* flagsPtr = CommitMemory((void*)&Flags, sizeof(ULONG)); void* ReturnPointerValue = RemoteAllocateMemory(sizeof(size_t)); if (m_bIs64bit) { // Backup RCX, RDX, R8 and R9 on stack BeginCall64(); // PushInt64(NULL); PushInt64((unsigned __int64)flagsPtr); PushUNICODEStringStructure(&unicodePath); PushInt64((unsigned __int64)ReturnPointerValue); PushCall(CCONV_WIN64, RemoteLdrLoadDll); // // Module Handle is located in RDX and at QWORD PTR [ReturnPointerValue]. // Could do 'mov rax, [ReturnPointerValue]' but it takes many more opcodes to do so. // We could also just RPM twice on ReturnPointerValue but it's better just to get it from rdx. // // mov rax, rdx AddByteToBuffer(0x48); AddByteToBuffer(0x89); AddByteToBuffer(0xD0); // mov [ReturnPointerValue], rax AddByteToBuffer(0x48); AddByteToBuffer(0xA3); AddLong64ToBuffer((unsigned __int64)ReturnPointerValue); // Restore RCX, RDX, R8 and R9 from stack and return EndCall64(); } else { PushInt(NULL); PushInt((unsigned int)flagsPtr); PushUNICODEStringStructure(&unicodePath); PushInt((unsigned long)ReturnPointerValue); PushCall(CCONV_STDCALL, RemoteLdrLoadDll); // // Module Handle is located in [EDX]. // To avoid calling RPM twice, we pass the [edx] into eax instead of just edx. // // mov eax,DWORD PTR [edx] AddByteToBuffer(0x8B); AddByteToBuffer(0x02); // mov ptr, eax AddByteToBuffer(0xA3); AddLongToBuffer((unsigned long)ReturnPointerValue); // xor eax, eax AddByteToBuffer(0x33); AddByteToBuffer(0xC0); // ret 4 AddByteToBuffer(0xC2); AddByteToBuffer(0x04); AddByteToBuffer(0x00); } if (ExecuteRemoteThreadBuffer(m_CurrentRemoteThreadBuffer) == false) { #ifdef DEBUG_MESSAGES_ENABLED DebugShout("[LoadLibraryByPathW] ExecuteRemoteThreadBuffer failed"); #endif RemoteFreeMemory(ReturnPointerValue, sizeof(size_t)); return NULL; } #ifdef DEBUG_MESSAGES_ENABLED DebugShout("[LoadModuleByNameW] ExecuteRemoteThreadBuffer succeeded"); #endif HMODULE RemoteModuleHandle = 0; if (ReadProcessMemory(m_hProcess, ReturnPointerValue, &RemoteModuleHandle, sizeof(HMODULE), NULL)) { RemoteFreeMemory(ReturnPointerValue, sizeof(size_t)); } else { RemoteFreeMemory(ReturnPointerValue, sizeof(size_t)); if (RemoteModuleHandle == 0) RemoteModuleHandle = GetRemoteModuleHandleW(Path); } return RemoteModuleHandle; } HMODULE CRemoteLoader::LoadLibraryByPathIntoMemoryA(LPCCH Path, BOOL PEHeader) { HMODULE hReturnValue = NULL; #ifdef DEBUG_MESSAGES_ENABLED DebugShout("[LoadLibraryByPathIntoMemoryA] %s", Path); #endif ModuleFile File = InitModuleFile(Path); if (File.IsValid() == FALSE) { #ifdef DEBUG_MESSAGES_ENABLED DebugShout("[LoadLibraryByPathIntoMemoryA] Failed to open file handle!"); #endif MessageBox(0, "Failed to open DLL file!", "Injectora", MB_ICONERROR); return NULL; } hReturnValue = LoadLibraryFromMemory(File.Buffer, File.Size, PEHeader); if (FreeModuleFile(File) == FALSE) { #ifdef DEBUG_MESSAGES_ENABLED DebugShout("[LoadLibraryByPathIntoMemoryA] Failed to free file handle..."); #endif } return hReturnValue; } HMODULE CRemoteLoader::LoadLibraryByPathIntoMemoryW(LPCWCH Path, BOOL PEHeader) { CHAR PathAnsi[MAX_PATH] = { 0 }; size_t charsConverted; wcstombs_s(&charsConverted, PathAnsi, Path, MAX_PATH); return LoadLibraryByPathIntoMemoryA(PathAnsi, PEHeader); } HMODULE CRemoteLoader::LoadLibraryFromMemory(PVOID BaseAddress, DWORD SizeOfModule, BOOL PEHeader) { #ifdef DEBUG_MESSAGES_ENABLED DebugShout("[LoadLibraryFromMemory] BaseAddress (0x%IX) - SizeOfModule (0x%X)", BaseAddress, SizeOfModule); #endif IMAGE_NT_HEADERS* ImageNtHeaders = ToNts(BaseAddress); if (ImageNtHeaders == NULL) { #ifdef DEBUG_MESSAGES_ENABLED DebugShout("[LoadLibraryFromMemory] Invalid Image: No IMAGE_NT_HEADERS"); #endif return NULL; } if (ImageNtHeaders->FileHeader.NumberOfSections == 0) { #ifdef DEBUG_MESSAGES_ENABLED DebugShout("[LoadLibraryFromMemory] Invalid Image: No Sections"); #endif return NULL; } if ( m_bIs64bit) { // // Create Remote Procedure Call environment. No need for this in 32 bit // DWORD err = CreateRPCEnvironment(); if (err != ERROR_SUCCESS) { #ifdef DEBUG_MESSAGES_ENABLED DebugShout("[LoadLibraryFromMemory] CreateRPCEnvironment failed. Error 0x%X", err); #endif return NULL; } // // Create activation context for the module we're injecting. Not needed for x86 modules. // #ifdef DEBUG_MESSAGES_ENABLED DebugShout("[LoadLibraryFromMemory] Creating Activation Context!"); #endif if (!CreateActx(BaseAddress)) { #ifdef DEBUG_MESSAGES_ENABLED DebugShout("[LoadLibraryFromMemory] Failed to obtain embedded resource! Continuing anyway without Activation Context..."); #endif } else { #ifdef DEBUG_MESSAGES_ENABLED DebugShout("[LoadLibraryFromMemory] Createed Activation Context successfully!"); #endif } } // We do not trust the value of hdr.OptionalHeader.SizeOfImage so we calculate our own SizeOfImage. // This is the size of the continuous memory block that can hold the headers and all sections. // size_t rva_low = (!PEHeader) ? ((size_t)-1) : 0; size_t rva_high = 0; PIMAGE_SECTION_HEADER ImageSectionHeader = (PIMAGE_SECTION_HEADER)((ULONG_PTR)&ImageNtHeaders->OptionalHeader + ImageNtHeaders->FileHeader.SizeOfOptionalHeader); for (size_t i = 0; i < ImageNtHeaders->FileHeader.NumberOfSections; ++i) { if (!ImageSectionHeader[i].Misc.VirtualSize) continue; if (ImageSectionHeader[i].VirtualAddress < rva_low) rva_low = ImageSectionHeader[i].VirtualAddress; if ((ImageSectionHeader[i].VirtualAddress + ImageSectionHeader[i].Misc.VirtualSize) > rva_high) rva_high = ImageSectionHeader[i].VirtualAddress + ImageSectionHeader[i].Misc.VirtualSize; } // Calculated Image Size // size_t ImageSize = rva_high - rva_low; #ifdef DEBUG_MESSAGES_ENABLED DebugShout("[LoadLibraryFromMemory] Calculated size (0x%IX)", ImageSize); #endif if ((ImageNtHeaders->OptionalHeader.ImageBase % 4096) != 0) { #ifdef DEBUG_MESSAGES_ENABLED DebugShout("[LoadLibraryFromMemory] Invalid Image: Not Page Aligned"); #endif return NULL; } if (ImageNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].Size && ::ImageDirectoryEntryToData(BaseAddress, TRUE, IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR, NULL)) { #ifdef DEBUG_MESSAGES_ENABLED DebugShout("[LoadLibraryFromMemory] This method is not supported for Managed executables!"); #endif return NULL; } #ifdef DEBUG_MESSAGES_ENABLED DebugShout("[LoadLibraryFromMemory] Good, no COM/CLR data found!"); #endif // SizeOfImage NOT the same as module size MOTHERFUCKER // http://www.youtube.com/watch?v=pele5vptVgc void* AllocatedRemoteMemory = RemoteAllocateMemory(ImageSize); if (AllocatedRemoteMemory == NULL) { #ifdef DEBUG_MESSAGES_ENABLED DebugShout("[LoadLibraryFromMemory] Failed to allocate remote memory for module!"); #endif return NULL; } #ifdef DEBUG_MESSAGES_ENABLED DebugShout("[LoadLibraryFromMemory] Allocated remote module at [0x%IX]!", AllocatedRemoteMemory); DebugShout("[LoadLibraryFromMemory] Processing Import Tables....\n"); #endif if (ProcessImportTable(BaseAddress, AllocatedRemoteMemory) == FALSE) { #ifdef DEBUG_MESSAGES_ENABLED DebugShout("[LoadLibraryFromMemory] Failed to fix imports!"); #endif return NULL; } if (ProcessDelayedImportTable(BaseAddress, AllocatedRemoteMemory) == FALSE) { #ifdef DEBUG_MESSAGES_ENABLED DebugShout("[LoadLibraryFromMemory] Failed to fix delayed imports!"); #endif return NULL; } #ifdef DEBUG_MESSAGES_ENABLED DebugShout("[LoadLibraryFromMemory] Fixed Imports!"); DebugShout("[LoadLibraryFromMemory] Processing Relocations....\n"); #endif if (ProcessRelocations(BaseAddress, AllocatedRemoteMemory) == FALSE) { #ifdef DEBUG_MESSAGES_ENABLED DebugShout("[LoadLibraryFromMemory] Failed to process relocations!"); #endif RemoteFreeMemory(AllocatedRemoteMemory, SizeOfModule); return NULL; } #ifdef DEBUG_MESSAGES_ENABLED DebugShout("[LoadLibraryFromMemory] Fixed Relocations!"); DebugShout("[LoadLibraryFromMemory] Processing Sections!"); #endif if (ProcessSections(BaseAddress, AllocatedRemoteMemory, PEHeader) == FALSE) { #ifdef DEBUG_MESSAGES_ENABLED DebugShout("[LoadLibraryFromMemory] Failed to process sections!"); #endif } if (m_bIs64bit && PEHeader) EnableExceptions(BaseAddress, AllocatedRemoteMemory, ImageSize); #ifdef DEBUG_MESSAGES_ENABLED DebugShout("[LoadLibraryFromMemory] Processed sections!"); DebugShout("[LoadLibraryFromMemory] Processing TLS Callback Entries!"); #endif if (ProcessTlsEntries(BaseAddress, AllocatedRemoteMemory) == FALSE) { #ifdef DEBUG_MESSAGES_ENABLED DebugShout("[LoadModuleFromMemory] ProcessTlsEntries Failed!"); #endif // we can also choose to continue here, but we wont cause unsafe return NULL; } #ifdef DEBUG_MESSAGES_ENABLED DebugShout("[LoadModuleFromMemory] Processed Tls Entries!"); #endif // Security cookie if needed InitializeCookie(BaseAddress, AllocatedRemoteMemory); if (ImageNtHeaders->OptionalHeader.AddressOfEntryPoint) { FARPROC DllEntryPoint = MakePtr(FARPROC, AllocatedRemoteMemory, ImageNtHeaders->OptionalHeader.AddressOfEntryPoint); #ifdef DEBUG_MESSAGES_ENABLED DebugShout("[LoadModuleFromMemory] DllEntrypoint = 0x%IX", DllEntryPoint); #endif if (CallEntryPoint(AllocatedRemoteMemory, DllEntryPoint) == false) { #ifdef DEBUG_MESSAGES_ENABLED DebugShout("[LoadModuleFromMemory] Failed to execute remote thread buffer"); #endif } else { #ifdef DEBUG_MESSAGES_ENABLED DebugShout("[LoadModuleFromMemory] Executed the remote thread buffer successfully [0x%IX]", DllEntryPoint); #endif } } else { #ifdef DEBUG_MESSAGES_ENABLED DebugShout("[LoadModuleFromMemory] AddressOfEntryPoint is NULL"); #endif } #ifdef DEBUG_MESSAGES_ENABLED DebugShout("[LoadModuleFromMemory] Returning Pointer (0x%IX)", AllocatedRemoteMemory); #endif return (HMODULE)AllocatedRemoteMemory; } // Private functions HMODULE CRemoteLoader::GetRemoteModuleHandleA(const char* Module) { void* dwModuleHandle = 0; PPROCESS_BASIC_INFORMATION pbi = NULL; PEB peb; PEB_LDR_DATA peb_ldr; // Try to allocate buffer HANDLE hHeap = GetProcessHeap(); DWORD dwSize = sizeof(PROCESS_BASIC_INFORMATION); pbi = (PPROCESS_BASIC_INFORMATION)HeapAlloc(hHeap, HEAP_ZERO_MEMORY, dwSize); ULONG dwSizeNeeded = 0; NTSTATUS dwStatus = fnNTQIP(m_hProcess, ProcessBasicInformation, pbi, dwSize, &dwSizeNeeded); if (dwStatus >= 0 && dwSize < dwSizeNeeded) { if (pbi) HeapFree(hHeap, 0, pbi); pbi = (PPROCESS_BASIC_INFORMATION)HeapAlloc(hHeap, HEAP_ZERO_MEMORY, dwSizeNeeded); if (!pbi) { #ifdef _DEBUG printf("Couldn't allocate heap buffer!\n"); #endif return NULL; } dwStatus = fnNTQIP(m_hProcess, ProcessBasicInformation, pbi, dwSizeNeeded, &dwSizeNeeded); } // Did we successfully get basic info on process if (dwStatus >= 0) { // Read Process Environment Block (PEB) if (pbi->PebBaseAddress) { SIZE_T dwBytesRead = 0; if (ReadProcessMemory(m_hProcess, pbi->PebBaseAddress, &peb, sizeof(peb), &dwBytesRead)) { dwBytesRead = 0; if (ReadProcessMemory(m_hProcess, peb.Ldr, &peb_ldr, sizeof(peb_ldr), &dwBytesRead)) { LIST_ENTRY *pLdrListHead = (LIST_ENTRY *)peb_ldr.InLoadOrderModuleList.Flink; LIST_ENTRY *pLdrCurrentNode = peb_ldr.InLoadOrderModuleList.Flink; do { LDR_DATA_TABLE_ENTRY lstEntry = { 0 }; dwBytesRead = 0; if (!ReadProcessMemory(m_hProcess, (void*)pLdrCurrentNode, &lstEntry, sizeof(LDR_DATA_TABLE_ENTRY), &dwBytesRead)) { #ifdef _DEBUG char dbgOut[1024]; sprintf_s(dbgOut, "CRemoteLoader[GetRemoteModuleHandleA] Could not read list entry from LDR list. Error = %X", GetLastError()); MessageBox(0, dbgOut, "Injectora", MB_ICONERROR); #endif if (pbi) HeapFree(hHeap, 0, pbi); return NULL; } pLdrCurrentNode = lstEntry.InLoadOrderLinks.Flink; wchar_t wcsBaseDllName[MAX_PATH] = { 0 }; char strBaseDllName[MAX_PATH] = { 0 }; if (lstEntry.BaseDllName.Length > 0) { dwBytesRead = 0; if (ReadProcessMemory(m_hProcess, (LPCVOID)lstEntry.BaseDllName.Buffer, &wcsBaseDllName, lstEntry.BaseDllName.Length, &dwBytesRead)) { size_t bytesCopied = 0; wcstombs_s(&bytesCopied, strBaseDllName, wcsBaseDllName, MAX_PATH); } } //wchar_t wcsFullDllName[MAX_PATH] = { 0 }; //char strFullDllName[MAX_PATH] = { 0 }; //if (lstEntry.FullDllName.Length > 0) //{ // dwBytesRead = 0; // if (ReadProcessMemory(m_hProcess, (LPCVOID)lstEntry.FullDllName.Buffer, &wcsFullDllName, lstEntry.FullDllName.Length, &dwBytesRead)) // { // size_t bytesCopied = 0; // wcstombs_s(&bytesCopied, strFullDllName, wcsFullDllName, MAX_PATH); // } //} if (lstEntry.DllBase != nullptr && lstEntry.SizeOfImage != 0) { if (_stricmp(strBaseDllName, Module) == 0) { dwModuleHandle = lstEntry.DllBase; break; } } } while (pLdrListHead != pLdrCurrentNode); } // Get Ldr } // Read PEB } // Check for PEB } if (pbi) HeapFree(hHeap, 0, pbi); return (HMODULE)dwModuleHandle; } HMODULE CRemoteLoader::GetRemoteModuleHandleW(LPCWCH Module) { char ModuleAnsi[MAX_PATH] = { 0 }; size_t charsConverted; wcstombs_s(&charsConverted, ModuleAnsi, Module, MAX_PATH); return GetRemoteModuleHandleA(ModuleAnsi); } IMAGE_DOS_HEADER* CRemoteLoader::ToDos(PVOID BaseAddress) { PIMAGE_DOS_HEADER ImageDosHeader = (PIMAGE_DOS_HEADER)(BaseAddress); if (!ImageDosHeader) return NULL; if (ImageDosHeader->e_magic != IMAGE_DOS_SIGNATURE) return NULL; return ImageDosHeader; } IMAGE_NT_HEADERS* CRemoteLoader::ToNts(PVOID BaseAddress) { IMAGE_DOS_HEADER* ImageDosHeader = ToDos(BaseAddress); if (ImageDosHeader == 0) return 0; IMAGE_NT_HEADERS* ImageNtHeaders = (IMAGE_NT_HEADERS*)((DWORD_PTR)BaseAddress + ImageDosHeader->e_lfanew); if (ImageNtHeaders->Signature != IMAGE_NT_SIGNATURE) return 0; return ImageNtHeaders; } void* CRemoteLoader::RvaToPointer(ULONG RVA, PVOID BaseAddress) { PIMAGE_NT_HEADERS ImageNtHeaders = ToNts(BaseAddress); if (ImageNtHeaders == 0) return 0; return ::ImageRvaToVa(ImageNtHeaders, BaseAddress, RVA, 0); } BOOL CRemoteLoader::CallEntryPoint(void* BaseAddress, FARPROC Entrypoint) { if (m_bIs64bit) { // ActivateActCtx if (m_pAContext) { size_t rsp_dif = 0x28; rsp_dif = Utils::Align(rsp_dif, 0x10); // sub rsp, (rsp_dif + 8) AddByteToBuffer(0x48); AddByteToBuffer(0x83); AddByteToBuffer(0xEC); AddByteToBuffer((unsigned char)(rsp_dif + 8)); // >>> // >>> // mov rax, m_pAContext AddByteToBuffer(0x48); AddByteToBuffer(0xB8); AddLong64ToBuffer((size_t)m_pAContext); // mov rax, [rax] AddByteToBuffer(0x48); AddByteToBuffer(0x8B); AddByteToBuffer(0x00); // mov rcx, rax -> first parameter AddByteToBuffer(0x48); AddByteToBuffer(0x89); AddByteToBuffer(0xC1); // mov rdx, (m_pAContext + sizeof(HANDLE)) -> second parameter LoadParam64((size_t)m_pAContext + sizeof(HANDLE), PARAM_INDEX_RDX); // mov r13, calladdress AddByteToBuffer(0x49); AddByteToBuffer(0xBD); AddLong64ToBuffer((size_t)ActivateActCtx); // call r13 AddByteToBuffer(0x41); AddByteToBuffer(0xFF); AddByteToBuffer(0xD5); // >>> // >>> // add rsp, (rsp_dif + 8) AddByteToBuffer(0x48); AddByteToBuffer(0x83); AddByteToBuffer(0xC4); AddByteToBuffer((unsigned char)(rsp_dif + 8)); } /* Call the actual entry point */ PushInt64((unsigned __int64)BaseAddress); PushInt64(DLL_PROCESS_ATTACH); PushInt64(0x00); PushCall(CCONV_WIN64, Entrypoint); // DeactivateActCtx if (m_pAContext) { size_t rsp_dif = 0x28; rsp_dif = Utils::Align(rsp_dif, 0x10); // sub rsp, (rsp_dif + 8) AddByteToBuffer(0x48); AddByteToBuffer(0x83); AddByteToBuffer(0xEC); AddByteToBuffer((unsigned char)(rsp_dif + 8)); // >>> // >>> // mov rax, m_pAContext + sizeof(HANDLE) AddByteToBuffer(0x48); AddByteToBuffer(0xB8); AddLong64ToBuffer((size_t)m_pAContext + sizeof(HANDLE)); // mov rax, [rax] AddByteToBuffer(0x48); AddByteToBuffer(0x8B); AddByteToBuffer(0x00); // mov rcx, 0 -> first parameter LoadParam64(0, PARAM_INDEX_RCX); // mov rdx, rax AddByteToBuffer(0x48); AddByteToBuffer(0x89); AddByteToBuffer(0xC2); // mov r13, calladdress AddByteToBuffer(0x49); AddByteToBuffer(0xBD); AddLong64ToBuffer((size_t)DeactivateActCtx); // call r13 AddByteToBuffer(0x41); AddByteToBuffer(0xFF); AddByteToBuffer(0xD5); // >>> // >>> // add rsp, (rsp_dif + 8) AddByteToBuffer(0x48); AddByteToBuffer(0x83); AddByteToBuffer(0xC4); AddByteToBuffer((unsigned char)(rsp_dif + 8)); } // Signal wait event SaveRetValAndSignalEvent(); // Restore registers from stack and return EndCall64(); size_t result; if (ExecuteInWorkerThread(m_CurrentRemoteThreadBuffer, result) != ERROR_SUCCESS) { TerminateWorkerThread(); DestroyRemoteThreadBuffer(); return FALSE; } return TRUE; } // x86 injection PushInt((INT)BaseAddress); PushInt(DLL_PROCESS_ATTACH); PushInt(0); PushCall(CCONV_STDCALL, Entrypoint); // Zero eax and return // xor eax, eax AddByteToBuffer(0x33); AddByteToBuffer(0xC0); // ret 4 AddByteToBuffer(0xC2); AddByteToBuffer(0x04); AddByteToBuffer(0x00); #ifdef DEBUG_MESSAGES_ENABLED DebugShout("\nCallEntryPoint [0x%IX]:", Entrypoint); #endif return ExecuteRemoteThreadBuffer(m_CurrentRemoteThreadBuffer, true); } bool CRemoteLoader::CreateActx(PVOID BaseAddress) { if (CreateTempManifestFileFromMemory(BaseAddress, 2)) { bool ret = CreateActxFromManifest(m_tempManifest); remove(m_tempManifest); ZeroMemory(m_tempManifest, MAX_PATH); return ret; } else { #ifdef DEBUG_MESSAGES_ENABLED DebugShout("[LoadLibraryFromMemory] Failed to get temp manifest from memory using Resource ID 2. Trying ID 1..."); #endif //if (CreateTempManifestFileFromMemory(BaseAddress, 1)) //{ // bool ret = CreateActxFromManifest(m_tempManifest); // remove(m_tempManifest); // ZeroMemory(m_tempManifest, MAX_PATH); // return ret; //} //else return false; } } bool CRemoteLoader::CreateTempManifestFileFromMemory(PVOID BaseAddress, DWORD ResourceId) { void* ManifestResource = NULL; DWORD ManifestSize = GetEmbeddedManifestResourceFromMemory(BaseAddress, ResourceId, &ManifestResource); if (ManifestResource) { if (!SetBaseDirectory()) { #ifdef DEBUG_MESSAGES_ENABLED DebugShout("[CreateTempManifestFileFromMemory] Failed to get base directory to create temp manifest in!"); #endif return false; } strcpy_s(m_tempManifest, m_baseDir); char randomFilename[MAX_PATH]; sprintf_s(randomFilename, "%IX", GetTickCount64()); strcat_s(m_tempManifest, randomFilename); #ifdef DEBUG_MESSAGES_ENABLED DebugShout("[CreateTempManifestFileFromMemory] Temp file: %s", m_tempManifest); #endif FILE* f; errno_t err = fopen_s(&f, m_tempManifest, "w"); if (f && err == NULL) fwrite(ManifestResource, sizeof(char), ManifestSize, f); fclose(f); return true; } #ifdef DEBUG_MESSAGES_ENABLED DebugShout("[CreateTempManifestFileFromMemory] Failed to obtain embedded Manifest resource from memory!"); #endif return false; } DWORD CRemoteLoader::GetEmbeddedManifestResourceFromMemory(PVOID BaseAddress, DWORD ResourceId, void** Resource) { PIMAGE_NT_HEADERS ImageNtHeaders = ToNts(BaseAddress); if (ImageNtHeaders == NULL) return FALSE; DWORD ResourceSize = ImageNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].Size; if (ResourceSize) { PIMAGE_RESOURCE_DIRECTORY RootResourceDir = (PIMAGE_RESOURCE_DIRECTORY)RvaToPointer(ImageNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress, BaseAddress); if (RootResourceDir) { const IMAGE_RESOURCE_DIR_STRING_U* dir_string = 0; // // enumerate all types // for (WORD i = 0; i < RootResourceDir->NumberOfIdEntries + RootResourceDir->NumberOfNamedEntries; i++) { PIMAGE_RESOURCE_DIRECTORY_ENTRY EntryType = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(RootResourceDir + 1 + i); if ((EntryType->OffsetToDirectory) >= ResourceSize) return NULL; PIMAGE_RESOURCE_DIRECTORY ResType = (PIMAGE_RESOURCE_DIRECTORY)((PBYTE)RootResourceDir + (EntryType->OffsetToDirectory)); if (EntryType->NameIsString) { dir_string = reinterpret_cast((PBYTE)RootResourceDir + EntryType->NameOffset); #ifdef DEBUG_MESSAGES_ENABLED DebugShout("[GetEmbeddedManifestResourceFromMemory] Resource Id: %S", &dir_string->NameString[0]); #endif } else { #ifdef DEBUG_MESSAGES_ENABLED DebugShout("[GetEmbeddedManifestResourceFromMemory] Resource Id: %i", EntryType->Id); #endif } // // enumerate all names // for (WORD j = 0; j < ResType->NumberOfIdEntries + ResType->NumberOfNamedEntries; j++) { PIMAGE_RESOURCE_DIRECTORY_ENTRY EntryIdentifier = reinterpret_cast(ResType + 1 + j); if ((EntryIdentifier->OffsetToDirectory) >= ResourceSize) return NULL; // Check if the resource ID is what we're looking for or not if (EntryIdentifier->Id != ResourceId) continue; PIMAGE_RESOURCE_DIRECTORY ResIdentifier = (PIMAGE_RESOURCE_DIRECTORY)((PBYTE)RootResourceDir + (EntryIdentifier->OffsetToDirectory)); if (EntryIdentifier->NameIsString) { dir_string = reinterpret_cast((PBYTE)RootResourceDir + EntryIdentifier->NameOffset); #ifdef DEBUG_MESSAGES_ENABLED DebugShout("[GetEmbeddedManifestResourceFromMemory] Resource Id: %S", &dir_string->NameString[0]); #endif } else { #ifdef DEBUG_MESSAGES_ENABLED DebugShout("[GetEmbeddedManifestResourceFromMemory] Resource Id: %i", EntryIdentifier->Id); #endif } // // enumerate all languages // now we have access to the offsets of the data // for (WORD k = 0; k < ResIdentifier->NumberOfIdEntries + ResIdentifier->NumberOfNamedEntries; k++) { PIMAGE_RESOURCE_DIRECTORY_ENTRY DataLangEntry = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(ResIdentifier + 1 + k); if ((DataLangEntry->OffsetToDirectory) >= ResourceSize) return FALSE; PIMAGE_RESOURCE_DATA_ENTRY pData = (PIMAGE_RESOURCE_DATA_ENTRY)((PBYTE)RootResourceDir + (DataLangEntry->OffsetToDirectory)); if (DataLangEntry->NameIsString) { dir_string = reinterpret_cast((PBYTE)RootResourceDir + DataLangEntry->NameOffset); #ifdef DEBUG_MESSAGES_ENABLED DebugShout("[GetEmbeddedManifestResourceFromMemory] Resource Id: %S", &dir_string->NameString[0]); #endif } else { #ifdef DEBUG_MESSAGES_ENABLED DebugShout("[GetEmbeddedManifestResourceFromMemory] Resource Id: %i", DataLangEntry->Id); #endif } if (pData->Size == 0) continue; void* ResourceData = RvaToPointer(pData->OffsetToData, BaseAddress); if (ResourceData && (DWORD64)ResourceData == (DWORD64)-1) continue; // empty or encrypted resource? #ifdef DEBUG_MESSAGES_ENABLED DebugShout("[GetEmbeddedManifestResourceFromMemory] Resource Data: 0x%IX", ResourceData); #endif *Resource = ResourceData; return pData->Size; } } } } } // Empty or no resource directory return NULL; } // Set custom exception handler to bypass SafeSEH under DEP NTSTATUS CRemoteLoader::EnableExceptions(PVOID BaseAddress, PVOID RemoteAddress, size_t ImageSize) { #ifdef _M_AMD64 PIMAGE_NT_HEADERS ImageNtHeaders = ToNts(BaseAddress); if (ImageNtHeaders == NULL) return FALSE; size_t size = ImageNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXCEPTION].Size; PIMAGE_RUNTIME_FUNCTION_ENTRY pExpTable = (PIMAGE_RUNTIME_FUNCTION_ENTRY)RvaToPointer(ImageNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXCEPTION].VirtualAddress, BaseAddress); if (pExpTable) { size_t result = 0; size_t ExpTableAddr = (size_t)pExpTable - (size_t)BaseAddress + (size_t)RemoteAddress; BeginCall64(); PushInt64(ExpTableAddr); PushInt64(size / sizeof(IMAGE_RUNTIME_FUNCTION_ENTRY)); PushInt64((size_t)RemoteAddress); PushCall(CCONV_WIN64, (FARPROC)RtlAddFunctionTable); SaveRetValAndSignalEvent(); EndCall64(); if (ExecuteInWorkerThread(m_CurrentRemoteThreadBuffer, result) != ERROR_SUCCESS) return false; return (CreateVEH((size_t)RemoteAddress, ImageSize) == ERROR_SUCCESS); } else return false; #else return true; #endif } DWORD CRemoteLoader::CreateVEH(size_t RemoteAddress /*= 0*/, size_t ImageSize /*= 0*/) { return GetLastError(); } // Calculate and set security cookie bool CRemoteLoader::InitializeCookie(PVOID BaseAddress, PVOID RemoteAddress) { PIMAGE_NT_HEADERS ImageNtHeaders = ToNts(BaseAddress); if (ImageNtHeaders == NULL) return FALSE; PIMAGE_LOAD_CONFIG_DIRECTORY pLC = (PIMAGE_LOAD_CONFIG_DIRECTORY)RvaToPointer(ImageNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG].VirtualAddress, BaseAddress); // // Cookie generation based on MSVC++ compiler // if (pLC && pLC->SecurityCookie) { FILETIME systime = { 0 }; LARGE_INTEGER PerformanceCount = { { 0 } }; uintptr_t cookie = 0; GetSystemTimeAsFileTime(&systime); QueryPerformanceCounter(&PerformanceCount); cookie = m_dwProcessId ^ m_dwWorkerThreadId ^ reinterpret_cast(&cookie); #ifdef _M_AMD64 cookie ^= *reinterpret_cast(&systime); cookie ^= (PerformanceCount.QuadPart << 32) ^ PerformanceCount.QuadPart; cookie &= 0xFFFFFFFFFFFF; if (cookie == 0x2B992DDFA232) cookie++; #else cookie ^= systime.dwHighDateTime ^ systime.dwLowDateTime; cookie ^= PerformanceCount.LowPart; cookie ^= PerformanceCount.HighPart; if (cookie == 0xBB40E64E) cookie++; else if (!(cookie & 0xFFFF0000)) cookie |= (cookie | 0x4711) << 16; #endif size_t RemoteCookieAddr = (size_t)pLC->SecurityCookie - (size_t)BaseAddress + (size_t)RemoteAddress; if (!WriteProcessMemory(m_hProcess, (void*)RemoteCookieAddr, (const void*)cookie, sizeof(uintptr_t), NULL)) { #ifdef DEBUG_MESSAGES_ENABLED DebugShout("[InitializeCookie] Failed to write generated security cookie!"); #endif return false; } return true; } #ifdef DEBUG_MESSAGES_ENABLED DebugShout("[InitializeCookie] No security cookie for module. Continuing."); #endif return true; } BOOL CRemoteLoader::ProcessImportTable(PVOID BaseAddress, PVOID RemoteAddress) { PIMAGE_NT_HEADERS ImageNtHeaders = ToNts(BaseAddress); if (ImageNtHeaders == NULL) return FALSE; if (ImageNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size) { PIMAGE_IMPORT_DESCRIPTOR ImageImportDescriptor = (PIMAGE_IMPORT_DESCRIPTOR)RvaToPointer(ImageNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress, BaseAddress); if (ImageImportDescriptor) { for (; ImageImportDescriptor->Name; ImageImportDescriptor++) { char* ModuleName = (char*)RvaToPointer(ImageImportDescriptor->Name, BaseAddress); if (ModuleName == NULL) { #ifdef DEBUG_MESSAGES_ENABLED DebugShout("[ProcessImportTable] Module name for entry NULL"); #endif continue; } #ifdef DEBUG_MESSAGES_ENABLED DebugShout("[ProcessImportTable] Module Name [%s]", ModuleName); #endif HMODULE ModuleBase = GetRemoteModuleHandleA(ModuleName); if (ModuleBase == NULL) { std::string strDll = ModuleName; std::wstring strBaseDll = L""; strBaseDll.assign(strDll.begin(), strDll.end()); ResolvePath(strBaseDll, EnsureFullPath); if (m_bIs64bit) ModuleBase = LoadDependencyW(strBaseDll.c_str()); else ModuleBase = LoadLibraryByPathIntoMemoryW(strBaseDll.c_str(), TRUE); // LoadDependencyW(strBaseDll.c_str()); if (ModuleBase == NULL) { #ifdef DEBUG_MESSAGES_ENABLED DebugShout("[ProcessImportTable] Failed to obtain module handle [%s]", ModuleName); #endif continue; } } IMAGE_THUNK_DATA *ImageThunkData = NULL; IMAGE_THUNK_DATA *ImageFuncData = NULL; if (ImageImportDescriptor->OriginalFirstThunk) { ImageThunkData = (IMAGE_THUNK_DATA*)RvaToPointer(ImageImportDescriptor->OriginalFirstThunk, BaseAddress); ImageFuncData = (IMAGE_THUNK_DATA*)RvaToPointer(ImageImportDescriptor->FirstThunk, BaseAddress); } else { ImageThunkData = (IMAGE_THUNK_DATA*)RvaToPointer(ImageImportDescriptor->FirstThunk, BaseAddress); ImageFuncData = (IMAGE_THUNK_DATA*)RvaToPointer(ImageImportDescriptor->FirstThunk, BaseAddress); } if (ImageThunkData == NULL) { #ifdef DEBUG_MESSAGES_ENABLED DebugShout("[ProcessImportTable] Image Thunk Data is NULL"); #endif } if (ImageFuncData == NULL) { #ifdef DEBUG_MESSAGES_ENABLED DebugShout("[ProcessImportTable] Image Func Data is NULL"); #endif } for (; ImageThunkData->u1.AddressOfData; ImageThunkData++, ImageFuncData++) { FARPROC FunctionAddress = NULL; bool bSnapByOrdinal = m_bIs64bit ? ((ImageThunkData->u1.Ordinal & IMAGE_ORDINAL_FLAG64) != 0) : ((ImageThunkData->u1.Ordinal & IMAGE_ORDINAL_FLAG32) != 0); if (bSnapByOrdinal) { SHORT Ordinal = (SHORT)(ImageThunkData->u1.Ordinal & 0xffff); FunctionAddress = (FARPROC)GetDependencyProcAddressA(ModuleBase, (const char*)Ordinal); // Failed to resolve import if (FunctionAddress == 0) { // TODO: Add error code #ifdef DEBUG_MESSAGES_ENABLED DebugShout("[ProcessImportTable] Failed to get import [%d] from image [%s]", Ordinal, ModuleName); #endif return FALSE; } #ifdef DEBUG_MESSAGES_ENABLED DebugShout("[ProcessImportTable] Processed (%s -> %i) -> (0x%IX)", ModuleName, Ordinal, FunctionAddress); #endif } else { PIMAGE_IMPORT_BY_NAME ImageImportByName = (PIMAGE_IMPORT_BY_NAME)RvaToPointer(*(DWORD*)ImageThunkData, BaseAddress); char* NameOfImport = (char*)ImageImportByName->Name; FunctionAddress = (FARPROC)GetDependencyProcAddressA(ModuleBase, NameOfImport); #ifdef DEBUG_MESSAGES_ENABLED DebugShout("[ProcessImportTable] Processed (%s -> %s) -> (0x%IX)", ModuleName, NameOfImport, FunctionAddress); #endif } ImageFuncData->u1.Function = (size_t)FunctionAddress; } } return TRUE; } else { #ifdef DEBUG_MESSAGES_ENABLED DebugShout("[ProcessImportTable] Size of table confirmed but pointer to data invalid!"); #endif return FALSE; } } else { #ifdef DEBUG_MESSAGES_ENABLED DebugShout("[ProcessImportTable] No Imports"); #endif return TRUE; } return FALSE; } BOOL CRemoteLoader::ProcessDelayedImportTable(PVOID BaseAddress, PVOID RemoteAddress) { PIMAGE_NT_HEADERS ImageNtHeaders = ToNts(BaseAddress); if (ImageNtHeaders == NULL) return FALSE; if (ImageNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT].Size) { PIMAGE_IMPORT_DESCRIPTOR ImageDelayedImportDescriptor = (PIMAGE_IMPORT_DESCRIPTOR)RvaToPointer(ImageNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT].VirtualAddress, BaseAddress); if (ImageDelayedImportDescriptor) { for (; ImageDelayedImportDescriptor->Name; ImageDelayedImportDescriptor++) { PCHAR ModuleName = (PCHAR)RvaToPointer(ImageDelayedImportDescriptor->Name, BaseAddress); if (ModuleName == NULL) { #ifdef DEBUG_MESSAGES_ENABLED DebugShout("[ProcessDelayedImportTable] Module name for entry NULL"); #endif continue; } #ifdef DEBUG_MESSAGES_ENABLED DebugShout("[ProcessDelayedImportTable] Module Name [%s]", ModuleName); #endif HMODULE ModuleBase = GetRemoteModuleHandleA(ModuleName); if (ModuleBase == NULL) { std::string strDll = ModuleName; std::wstring strBaseDll = L""; strBaseDll.assign(strDll.begin(), strDll.end()); ResolvePath(strBaseDll, EnsureFullPath); if (m_bIs64bit) ModuleBase = LoadDependencyW(strBaseDll.c_str()); else ModuleBase = LoadLibraryByPathIntoMemoryW(strBaseDll.c_str(), TRUE); //LoadDependencyW(strBaseDll.c_str()); if (ModuleBase == NULL) { #ifdef DEBUG_MESSAGES_ENABLED DebugShout("[ProcessDelayedImportTable] Failed to obtain module handle [%s]", ModuleName); #endif continue; } } IMAGE_THUNK_DATA *ImageThunkData = NULL; IMAGE_THUNK_DATA *ImageFuncData = NULL; if (ImageDelayedImportDescriptor->OriginalFirstThunk) { ImageThunkData = (IMAGE_THUNK_DATA*)RvaToPointer(ImageDelayedImportDescriptor->OriginalFirstThunk, BaseAddress); ImageFuncData = (IMAGE_THUNK_DATA*)RvaToPointer(ImageDelayedImportDescriptor->FirstThunk, BaseAddress); } else { ImageThunkData = (IMAGE_THUNK_DATA*)RvaToPointer(ImageDelayedImportDescriptor->FirstThunk, BaseAddress); ImageFuncData = (IMAGE_THUNK_DATA*)RvaToPointer(ImageDelayedImportDescriptor->FirstThunk, BaseAddress); } if (ImageThunkData == NULL) { #ifdef DEBUG_MESSAGES_ENABLED DebugShout("[ProcessDelayedImportTable] Image Thunk Data is NULL"); #endif } if (ImageFuncData == NULL) { #ifdef DEBUG_MESSAGES_ENABLED DebugShout("[ProcessDelayedImportTable] Image Func Data is NULL"); #endif } for (; ImageThunkData->u1.AddressOfData; ImageThunkData++, ImageFuncData++) { FARPROC FunctionAddress = NULL; bool bSnapByOrdinal = false; if (m_bIs64bit) bSnapByOrdinal = ((ImageThunkData->u1.Ordinal & IMAGE_ORDINAL_FLAG64) != 0); else bSnapByOrdinal = ((ImageThunkData->u1.Ordinal & IMAGE_ORDINAL_FLAG32) != 0); if (bSnapByOrdinal) { WORD Ordinal = (WORD)(ImageThunkData->u1.Ordinal & 0xffff); FunctionAddress = (FARPROC)GetDependencyProcAddressA(ModuleBase, (const char*)Ordinal); // Utils::GetProcAddress // Failed to resolve import if (FunctionAddress == 0) { // TODO: Add error code #ifdef DEBUG_MESSAGES_ENABLED printf("[ProcessDelayedImportTable] Failed to get import [%d] from image [%s]", Ordinal, ModuleName); #endif return FALSE; } #ifdef DEBUG_MESSAGES_ENABLED DebugShout("[ProcessDelayedImportTable] Processed (%s -> %i) -> (0x%IX)", ModuleName, Ordinal, FunctionAddress); #endif } else { PIMAGE_IMPORT_BY_NAME ImageImportByName = (PIMAGE_IMPORT_BY_NAME)RvaToPointer(*(DWORD*)ImageThunkData, BaseAddress); FunctionAddress = (FARPROC)GetDependencyProcAddressA(ModuleBase, (LPCCH)ImageImportByName->Name); // Utils::GetProcAddress // Failed to resolve import if (FunctionAddress == 0) { // TODO: Add error code #ifdef DEBUG_MESSAGES_ENABLED DebugShout("[ProcessDelayedImportTable] Failed to get import [%s] from image [%s]", (PCHAR)ImageImportByName->Name, ModuleName); #endif return FALSE; } #ifdef DEBUG_MESSAGES_ENABLED DebugShout("[ProcessDelayedImportTable] Processed (%s -> %s) -> (0x%IX)", ModuleName, (PCHAR)ImageImportByName->Name, FunctionAddress); #endif } ImageFuncData->u1.Function = (ULONGLONG)FunctionAddress; } } return TRUE; } else { #ifdef DEBUG_MESSAGES_ENABLED DebugShout("[ProcessDelayedImportTable] Size of table confirmed but pointer to data invalid!"); #endif return FALSE; } } else { #ifdef DEBUG_MESSAGES_ENABLED DebugShout("[ProcessDelayedImportTable] No Delayed Imports"); #endif return TRUE; } return FALSE; } FARPROC CRemoteLoader::GetRemoteProcAddressW(LPCWCH Module, LPCWCH procName) { char ModuleAnsi[MAX_PATH] = { 0 }; size_t charsConverted; wcstombs_s(&charsConverted, ModuleAnsi, Module, MAX_PATH); char ProcNameAnsi[MAX_PATH]; wcstombs_s(&charsConverted, ProcNameAnsi, procName, MAX_PATH); return GetRemoteProcAddressA(ModuleAnsi, ProcNameAnsi); } FARPROC CRemoteLoader::GetDependencyProcAddressW(HMODULE ModuleBase, LPCWCH procName) { char ProcAnsi[MAX_PATH]; size_t charsConverted; wcstombs_s(&charsConverted, ProcAnsi, procName, MAX_PATH); return GetDependencyProcAddressA(ModuleBase, ProcAnsi); } FARPROC CRemoteLoader::GetDependencyProcAddressA(HMODULE ModuleBase, LPCCH proc_name) { void* modb = (void*)ModuleBase; IMAGE_DOS_HEADER hdrDos = { 0 }; IMAGE_NT_HEADERS hdrNt32 = { 0 }; IMAGE_EXPORT_DIRECTORY* expData = { 0 }; void* pFunc = NULL; SIZE_T dwRead = 0; ReadProcessMemory(m_hProcess, (BYTE*)modb, &hdrDos, sizeof(IMAGE_DOS_HEADER), &dwRead); if (hdrDos.e_magic != IMAGE_DOS_SIGNATURE) return NULL; ReadProcessMemory(m_hProcess, (BYTE*)modb + hdrDos.e_lfanew, &hdrNt32, sizeof(IMAGE_NT_HEADERS), &dwRead); if (hdrNt32.Signature != IMAGE_NT_SIGNATURE) return NULL; size_t expBase = hdrNt32.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress; // Exports are present if (expBase) { DWORD expSize = hdrNt32.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size; expData = (IMAGE_EXPORT_DIRECTORY*)malloc(expSize); ReadProcessMemory(m_hProcess, (BYTE*)modb + expBase, expData, expSize, &dwRead); WORD *pAddressOfOrds = (WORD*) (expData->AddressOfNameOrdinals + (size_t)expData - expBase); DWORD *pAddressOfNames = (DWORD*)(expData->AddressOfNames + (size_t)expData - expBase); DWORD *pAddressOfFuncs = (DWORD*)(expData->AddressOfFunctions + (size_t)expData - expBase); for (DWORD i = 0; i < expData->NumberOfFunctions; ++i) { WORD OrdIndex = 0xFFFF; char *pName = NULL; // Find by index if ((size_t)proc_name <= 0xFFFF) OrdIndex = (WORD)i; // Find by name else if ((size_t)proc_name > 0xFFFF && i < expData->NumberOfNames) { pName = (char*)(pAddressOfNames[i] + (size_t)expData - expBase); OrdIndex = (WORD)pAddressOfOrds[i]; } else return 0; if (((size_t)proc_name <= 0xFFFF && (WORD)proc_name == (OrdIndex + expData->Base)) || ((size_t)proc_name > 0xFFFF && strcmp(pName, proc_name) == 0)) { pFunc = (void*)((size_t)modb + pAddressOfFuncs[OrdIndex]); // Check forwarded export if ((size_t)pFunc >= (size_t)modb + expBase && (size_t)pFunc <= (size_t)modb + expBase + expSize) { char forwardStr[255] = { 0 }; ReadProcessMemory(m_hProcess, pFunc, forwardStr, sizeof(forwardStr), &dwRead); std::string chainExp(forwardStr); std::string strDll = chainExp.substr(0, chainExp.find(".")) + ".dll"; std::string strName = chainExp.substr(chainExp.find(".") + 1, strName.npos); HMODULE hChainMod = GetRemoteModuleHandleA(strDll.c_str()); if (hChainMod == NULL) hChainMod = LoadDependencyA(strDll.c_str()); // Import by ordinal if (strName.find("#") == 0) return GetDependencyProcAddressA(hChainMod, (const char*)atoi(strName.c_str() + 1)); else // Import by name return GetDependencyProcAddressA(hChainMod, strName.c_str()); } break; } } // Free allocated data free(expData); } return (FARPROC)pFunc; } FARPROC CRemoteLoader::GetRemoteProcAddressW(LPCWCH Module, SHORT procOrdinal) { char ModuleAnsi[MAX_PATH]; size_t charsConverted; wcstombs_s(&charsConverted, ModuleAnsi, Module, MAX_PATH); return GetRemoteProcAddressA(ModuleAnsi, procOrdinal); } FARPROC CRemoteLoader::GetRemoteProcAddressA(LPCCH Module, LPCCH procName) { HMODULE hKernel32 = Utils::GetLocalModuleHandle("Kernel32.dll"); if (hKernel32 == NULL) return NULL; size_t GetProcAddressOffset = (size_t)GetProcAddress - (size_t)hKernel32; HMODULE hRemoteKernel32 = GetRemoteModuleHandleA("Kernel32.dll"); if (hRemoteKernel32 == NULL) return NULL; HMODULE hRemoteModule = GetRemoteModuleHandleA(Module); if (hRemoteModule == NULL) { #ifdef DEBUG_MESSAGES_ENABLED DebugShout("[GetRemoteProcAddressA] Failed to obtain module handle [%s]", Module); #endif return NULL; } PVOID ReturnPointerValue = RemoteAllocateMemory(sizeof(size_t)); if (m_bIs64bit) { // Backup RCX, RDX, R8, and R9 on stack BeginCall64(); PushInt64((unsigned __int64)hRemoteModule); PushANSIString((PCHAR)procName); PushCall(CCONV_WIN64, (FARPROC)((size_t)hRemoteKernel32 + (size_t)GetProcAddressOffset)); // mov [ReturnPointerValue], rax AddByteToBuffer(0x48); AddByteToBuffer(0xA3); AddLong64ToBuffer((unsigned __int64)ReturnPointerValue); SaveRetValAndSignalEvent(); // Restore RCX, RDX, R8, and R9 from stack and return EndCall64(); } else { PushInt((unsigned int)hRemoteModule); PushANSIString((PCHAR)procName); PushCall(CCONV_STDCALL, (FARPROC)((size_t)hRemoteKernel32 + (size_t)GetProcAddressOffset)); //mov ptr, eax AddByteToBuffer(0xA3); AddLongToBuffer((DWORD)ReturnPointerValue); //xor eax, eax AddByteToBuffer(0x33); AddByteToBuffer(0xC0); //retn 4 AddByteToBuffer(0xC2); AddByteToBuffer(0x04); AddByteToBuffer(0x00); } if (m_bIs64bit) { size_t result; if (ExecuteInWorkerThread(m_CurrentRemoteThreadBuffer, result) != ERROR_SUCCESS) { RemoteFreeMemory(ReturnPointerValue, sizeof(size_t)); return NULL; } } else { if (!ExecuteRemoteThreadBuffer(m_CurrentRemoteThreadBuffer, true)) { RemoteFreeMemory(ReturnPointerValue, sizeof(size_t)); return NULL; } } size_t ProcAddressRemote = 0; if (ReadProcessMemory(m_hProcess, ReturnPointerValue, &ProcAddressRemote, sizeof(size_t), NULL) == TRUE) { RemoteFreeMemory(ReturnPointerValue, sizeof(size_t)); return (FARPROC)ProcAddressRemote; } RemoteFreeMemory(ReturnPointerValue, sizeof(size_t)); return NULL; } FARPROC CRemoteLoader::GetRemoteProcAddressA(LPCCH Module, SHORT procOrdinal) { HMODULE hKernel32 = Utils::GetLocalModuleHandle("Kernel32.dll"); if (hKernel32 == NULL) return NULL; size_t GetProcAddressOffset = (size_t)GetProcAddress - (size_t)hKernel32; HMODULE hRemoteKernel32 = GetRemoteModuleHandleA("Kernel32.dll"); if (hRemoteKernel32 == NULL) return NULL; HMODULE hRemoteModule = GetRemoteModuleHandleA(Module); if (hRemoteModule == NULL) { std::string strDll = Module; std::wstring strBaseDll = L""; strBaseDll.assign(strDll.begin(), strDll.end()); ResolvePath(strBaseDll, EnsureFullPath); hRemoteModule = LoadDependencyW(strBaseDll.c_str()); if (hRemoteModule == NULL) return NULL; } PVOID ReturnPointerValue = RemoteAllocateMemory(sizeof(size_t)); PushInt((INT)hRemoteModule); PushInt((INT)procOrdinal); PushCall(CCONV_STDCALL, (FARPROC)((size_t)hRemoteKernel32 + (size_t)GetProcAddressOffset)); //mov ptr, eax AddByteToBuffer(0xA3); AddLongToBuffer((DWORD)ReturnPointerValue); //xor eax, eax AddByteToBuffer(0x33); AddByteToBuffer(0xC0); //retn 4 AddByteToBuffer(0xC2); AddByteToBuffer(0x04); AddByteToBuffer(0x00); if (!ExecuteRemoteThreadBuffer(m_CurrentRemoteThreadBuffer, true)) { RemoteFreeMemory(ReturnPointerValue, sizeof(DWORD)); return NULL; } size_t ProcAddressRemote = 0; if (ReadProcessMemory(m_hProcess, ReturnPointerValue, &ProcAddressRemote, sizeof(DWORD), NULL) == TRUE) { RemoteFreeMemory(ReturnPointerValue, sizeof(size_t)); return (FARPROC)ProcAddressRemote; } RemoteFreeMemory(ReturnPointerValue, sizeof(size_t)); return NULL; } BOOL CRemoteLoader::ProcessRelocation(size_t ImageBaseDelta, WORD Data, PBYTE RelocationBase) { BOOL bReturn = TRUE; switch (IMR_RELTYPE(Data)) { case IMAGE_REL_BASED_HIGH: { SHORT* Raw = (SHORT*)(RelocationBase + IMR_RELOFFSET(Data)); SHORT Backup = *Raw; *Raw += (ULONG)HIWORD(ImageBaseDelta); #ifdef DEBUG_MESSAGES_ENABLED DebugShout("[ProcessRelocation] IMAGE_REL_BASED_HIGH (0x%IX) -> (0x%IX)", Backup, *Raw); #endif break; } case IMAGE_REL_BASED_LOW: { SHORT* Raw = (SHORT*)(RelocationBase + IMR_RELOFFSET(Data)); SHORT Backup = *Raw; *Raw += (ULONG)LOWORD(ImageBaseDelta); #ifdef DEBUG_MESSAGES_ENABLED DebugShout("[ProcessRelocation] IMAGE_REL_BASED_LOW (0x%IX) -> (0x%X)", Backup, *Raw); #endif break; } case IMAGE_REL_BASED_HIGHLOW: { size_t* Raw = (size_t*)(RelocationBase + IMR_RELOFFSET(Data)); size_t Backup = *Raw; *Raw += (size_t)ImageBaseDelta; #ifdef DEBUG_MESSAGES_ENABLED DebugShout("[ProcessRelocation] IMAGE_REL_BASED_HIGHLOW (0x%IX) -> (0x%X)", Backup, *Raw); #endif break; } case IMAGE_REL_BASED_DIR64: { DWORD_PTR UNALIGNED* Raw = (DWORD_PTR UNALIGNED*)(RelocationBase + IMR_RELOFFSET(Data)); DWORD_PTR UNALIGNED Backup = *Raw; *Raw += ImageBaseDelta; #ifdef DEBUG_MESSAGES_ENABLED DebugShout("[ProcessRelocation] IMAGE_REL_BASED_DIR64 (0x%IX) -> (0x%IX)", Backup, *Raw); #endif break; } case IMAGE_REL_BASED_ABSOLUTE: // No action required { #ifdef DEBUG_MESSAGES_ENABLED DebugShout("[ProcessRelocation] IMAGE_REL_BASED_ABSOLUTE no need to process"); #endif break; } case IMAGE_REL_BASED_HIGHADJ: // no action required { #ifdef DEBUG_MESSAGES_ENABLED DebugShout("[ProcessRelocation] IMAGE_REL_BASED_HIGHADJ no need to process"); #endif break; } default: { #ifdef DEBUG_MESSAGES_ENABLED DebugShout("[ProcessRelocation] UNKNOWN RELOCATION (0x%IX)", IMR_RELTYPE(Data)); #endif bReturn = FALSE; break; } } // end of switch return bReturn; } BOOL CRemoteLoader::ProcessRelocations(PVOID BaseAddress, PVOID RemoteAddress) { IMAGE_NT_HEADERS* ImageNtHeaders = ToNts(BaseAddress); if (ImageNtHeaders == NULL) return FALSE; if (ImageNtHeaders->FileHeader.Characteristics & IMAGE_FILE_RELOCS_STRIPPED) { #ifdef DEBUG_MESSAGES_ENABLED DebugShout("[ProcessRelocations] Relocations have been stripped from this executable, continuing.."); #endif return TRUE; } else { size_t ImageBaseDelta = MakeDelta(size_t, RemoteAddress, ImageNtHeaders->OptionalHeader.ImageBase); #ifdef DEBUG_MESSAGES_ENABLED DebugShout("[ProcessRelocations] VirtualAddress (0x%IX)",ImageNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress); #endif DWORD RelocationSize = ImageNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size; #ifdef DEBUG_MESSAGES_ENABLED DebugShout("[ProcessRelocations] Relocation Size [0x%IX]", RelocationSize); #endif if (RelocationSize) { PIMAGE_BASE_RELOCATION RelocationDirectory = (PIMAGE_BASE_RELOCATION)RvaToPointer(ImageNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress, BaseAddress); if (RelocationDirectory) { #ifdef DEBUG_MESSAGES_ENABLED DebugShout("[ProcessRelocations] RelocationDirectory (0x%IX)", RelocationDirectory); #endif PVOID RelocationEnd = reinterpret_cast(RelocationDirectory) + RelocationSize; while (RelocationDirectory < RelocationEnd) { PBYTE RelocBase = static_cast(RvaToPointer(RelocationDirectory->VirtualAddress, BaseAddress)); DWORD NumRelocs = (RelocationDirectory->SizeOfBlock - 8) >> 1; PWORD RelocationData = reinterpret_cast(RelocationDirectory + 1); #ifdef DEBUG_MESSAGES_ENABLED DebugShout("[ProcessRelocations] RelocationData (0x%IX)", RelocationData); #endif for (DWORD i = 0; i < NumRelocs; ++i, ++RelocationData) { if (ProcessRelocation(ImageBaseDelta, *RelocationData, RelocBase) == FALSE) { #ifdef DEBUG_MESSAGES_ENABLED DebugShout("[ProcessRelocations] Unable to process relocation (%i)", i); #endif } } RelocationDirectory = reinterpret_cast(RelocationData); } } else { #ifdef DEBUG_MESSAGES_ENABLED DebugShout("[ProcessRelocations] Relocations have a size, but the pointer is invalid"); #endif return FALSE; } } else { #ifdef DEBUG_MESSAGES_ENABLED DebugShout("[ProcessRelocations] Relocations have have not been found in this executable, continuing.."); #endif return TRUE; } } return TRUE; } ULONG CRemoteLoader::GetSectionProtection(ULONG Characteristics) { ULONG Result = 0; if (Characteristics & IMAGE_SCN_MEM_NOT_CACHED) Result |= PAGE_NOCACHE; if (Characteristics & IMAGE_SCN_MEM_EXECUTE) { if (Characteristics & IMAGE_SCN_MEM_READ) { if (Characteristics & IMAGE_SCN_MEM_WRITE) Result |= PAGE_EXECUTE_READWRITE; else Result |= PAGE_EXECUTE_READ; } else if (Characteristics & IMAGE_SCN_MEM_WRITE) Result |= PAGE_EXECUTE_WRITECOPY; else Result |= PAGE_EXECUTE; } else if (Characteristics & IMAGE_SCN_MEM_READ) { if (Characteristics & IMAGE_SCN_MEM_WRITE) Result |= PAGE_READWRITE; else Result |= PAGE_READONLY; } else if (Characteristics & IMAGE_SCN_MEM_WRITE) Result |= PAGE_WRITECOPY; else Result |= PAGE_NOACCESS; return Result; } BOOL CRemoteLoader::ProcessSection(BYTE* Name, PVOID BaseAddress, PVOID RemoteAddress, ULONGLONG RawData, ULONGLONG VirtualAddress, ULONGLONG RawSize, ULONGLONG VirtualSize, ULONG ProtectFlag) { #ifdef DEBUG_MESSAGES_ENABLED DebugShout("[ProcessSection] ProcessSection( %s, 0x%IX, 0x%IX, 0x%IX, 0x%IX, 0x%IX, 0x%IX, 0x%IX )", Name, BaseAddress, RemoteAddress, RawData, VirtualAddress, RawSize, VirtualSize, ProtectFlag); #endif if (WriteProcessMemory(m_hProcess, MakePtr(PVOID, RemoteAddress, VirtualAddress), MakePtr(PVOID, BaseAddress, RawData), (SIZE_T)RawSize, NULL) == FALSE) { #ifdef DEBUG_MESSAGES_ENABLED DebugShout("[ProcessSection] Failed to write memory for [%s] -> [%s]", Name, LastErrorString()); #endif return FALSE; } DWORD dwOldProtect = NULL; if (VirtualProtectEx(m_hProcess, MakePtr(PVOID, RemoteAddress, VirtualAddress), (SIZE_T)VirtualSize, ProtectFlag, &dwOldProtect) == FALSE) { #ifdef DEBUG_MESSAGES_ENABLED DebugShout("[ProcessSection] Failed to protect memory for [%s] -> [%s]", Name, LastErrorString()); #endif return FALSE; } return TRUE; } BOOL CRemoteLoader::ProcessSections(PVOID BaseAddress, PVOID RemoteAddress, BOOL MapPEHeader) { PIMAGE_NT_HEADERS ImageNtHeaders = ToNts(BaseAddress); if (ImageNtHeaders == NULL) return FALSE; // Writing the PE header if (MapPEHeader) { if (WriteProcessMemory(m_hProcess, RemoteAddress, BaseAddress, ImageNtHeaders->OptionalHeader.SizeOfHeaders, NULL) == FALSE) { #ifdef DEBUG_MESSAGES_ENABLED DebugShout("[ProcessSections] Failed to map PE header!"); #endif } else { #ifdef DEBUG_MESSAGES_ENABLED DebugShout("[ProcessSections] Mapped PE Header successfully!"); #endif } } else { #ifdef DEBUG_MESSAGES_ENABLED DebugShout("[ProcessSections] PE Header mapping disabled, skipping."); #endif } // Write individual sections PIMAGE_SECTION_HEADER ImageSectionHeader = (PIMAGE_SECTION_HEADER)((ULONG_PTR)&ImageNtHeaders->OptionalHeader + ImageNtHeaders->FileHeader.SizeOfOptionalHeader); for (DWORD i = 0; i < ImageNtHeaders->FileHeader.NumberOfSections; i++) { if (_stricmp(".reloc", (char*)ImageSectionHeader[i].Name) == 0) { #ifdef DEBUG_MESSAGES_ENABLED DebugShout("[ProcessSections] Skipping \".reloc\" section."); #endif continue; // NOPE, do not process the .reloc section } // Skip discardable sections if (ImageSectionHeader[i].Characteristics & (IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_EXECUTE)) { ULONG Protection = GetSectionProtection(ImageSectionHeader[i].Characteristics); if (ProcessSection(ImageSectionHeader[i].Name, BaseAddress, RemoteAddress, ImageSectionHeader[i].PointerToRawData, ImageSectionHeader[i].VirtualAddress, ImageSectionHeader[i].SizeOfRawData, ImageSectionHeader[i].Misc.VirtualSize, Protection) == FALSE) { #ifdef DEBUG_MESSAGES_ENABLED DebugShout("[ProcessSections] Failed [%s]", ImageSectionHeader[i].Name); #endif } else { #ifdef DEBUG_MESSAGES_ENABLED DebugShout("[ProcessSections] Success [%s]", ImageSectionHeader[i].Name); #endif } } } return TRUE; } BOOL CRemoteLoader::ProcessTlsEntries(PVOID BaseAddress, PVOID RemoteAddress) { IMAGE_NT_HEADERS* ImageNtHeaders = ToNts(BaseAddress); if (ImageNtHeaders == NULL) return FALSE; if (ImageNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].Size == 0) { #ifdef DEBUG_MESSAGES_ENABLED DebugShout("[ProcessTlsEntries] No Tls entries to process"); #endif return TRUE; // Success when there is no Tls Entries <--- always hits here } #ifdef DEBUG_MESSAGES_ENABLED DebugShout("[ProcessTlsEntries] Tls Data detected!"); #endif PIMAGE_TLS_DIRECTORY TlsDirectory = (PIMAGE_TLS_DIRECTORY)RvaToPointer(ImageNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress, BaseAddress); if (TlsDirectory == NULL) return TRUE; // Success when there is no Tls entries / broken data? #ifdef DEBUG_MESSAGES_ENABLED DebugShout("[ProcessTlsEntries] TlsDirectory (0x%IX)", TlsDirectory); #endif if (TlsDirectory->AddressOfCallBacks == NULL) return TRUE; // Success when there is no Tls entries / broken data? #ifdef DEBUG_MESSAGES_ENABLED DebugShout("[ProcessTlsEntries] TlsDirectory->AddressOfCallBacks (0x%IX)", TlsDirectory->AddressOfCallBacks); #endif PIMAGE_TLS_CALLBACK TLSCallbacks[0xFF]; if (ReadProcessMemory(m_hProcess, (void*)TlsDirectory->AddressOfCallBacks, TLSCallbacks, sizeof(TLSCallbacks), NULL) == FALSE) { #ifdef DEBUG_MESSAGES_ENABLED DebugShout("[ProcessTlsEntries] ReadProcessMemory Failed"); #endif return FALSE; } BOOL SuccessValue = TRUE; for (int i = 0; TLSCallbacks[i]; i++) { #ifdef DEBUG_MESSAGES_ENABLED DebugShout("[ProcessTlsEntries] TLSCallbacks[%i] = 0x%IX (0x%IX)", i, TLSCallbacks[i], RemoteAddress); #endif // As a consequence of the relocation stuff mentioned above, pCallbacks[i] is already fixed if (CallEntryPoint(RemoteAddress, (FARPROC)TLSCallbacks[i]) == false) { #ifdef DEBUG_MESSAGES_ENABLED DebugShout("[ProcessTlsEntries] Failed to execute Tls Entry [%i]", i); #endif } else { #ifdef DEBUG_MESSAGES_ENABLED DebugShout("[ProcessTlsEntries] Called Tls Callback (0x%IX)", TLSCallbacks[i]); #endif } } return SuccessValue; } /////////////////////// // Private functions // /////////////////////// ModuleFile CRemoteLoader::InitModuleFile(LPCCH FileName) { ModuleFile r; r.Buffer = 0; r.Size = 0; HANDLE hFile = CreateFile(FileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (hFile == INVALID_HANDLE_VALUE) { #ifdef DEBUG_MESSAGES_ENABLED DebugShout("[InitModuleFile] CreateFile Failed"); #endif return r; } #ifdef DEBUG_MESSAGES_ENABLED DebugShout("[InitModuleFile] File opened"); #endif if (GetFileAttributesA(FileName) & FILE_ATTRIBUTE_COMPRESSED) { r.Size = GetCompressedFileSizeA(FileName, NULL); #ifdef DEBUG_MESSAGES_ENABLED DebugShout("[InitModuleFile] File is compressed!"); #endif } else { r.Size = GetFileSize(hFile, NULL); } #ifdef DEBUG_MESSAGES_ENABLED DebugShout("[InitModuleFile] Size [0x%IX]", r.Size); #endif if (r.Size == 0) { CloseHandle(hFile); return r; } unsigned char* AllocatedFile = (unsigned char*)VirtualAlloc(NULL, r.Size, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); if (AllocatedFile == NULL) { #ifdef DEBUG_MESSAGES_ENABLED DebugShout("[InitModuleFile] Failed to allocate buffer!"); #endif r.Size = 0; CloseHandle(hFile); return r; } #ifdef DEBUG_MESSAGES_ENABLED DebugShout("[InitModuleFile] Buffer allocated!"); #endif DWORD NumberOfBytesRead = 0; if (ReadFile(hFile, AllocatedFile, r.Size, &NumberOfBytesRead, FALSE) == FALSE) { #ifdef DEBUG_MESSAGES_ENABLED DebugShout("[InitModuleFile] Read file failed"); #endif r.Buffer = 0; r.Size = 0; } else { #ifdef DEBUG_MESSAGES_ENABLED DebugShout("[InitModuleFile] Read file complete [0x%IX]", NumberOfBytesRead); #endif r.Buffer = AllocatedFile; } #ifdef DEBUG_MESSAGES_ENABLED DebugShout("[InitModuleFile] Buffer [0x%IX]", r.Buffer); #endif CloseHandle(hFile); return r; } BOOL CRemoteLoader::FreeModuleFile(ModuleFile Handle) { if (Handle.Buffer) { VirtualFree(Handle.Buffer, Handle.Size, MEM_RELEASE); Handle.Buffer = 0; } Handle.Size = 0; return (Handle.Buffer == 0 && Handle.Size == 0); } TCHAR* CRemoteLoader::LastErrorString() { TCHAR* returnBuffer = 0; FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&returnBuffer, 0, NULL); return returnBuffer; } int CRemoteLoader::GetProcessPlatform() { return Utils::GetProcessPlatform(m_hProcess); } // // Deprecated functions that don't work with everything // FARPROC CRemoteLoader::GetRemoteProcAddress_DEPRECATED(HMODULE Module, LPCCH Function) { if (!Module) { #ifdef DEBUG_MESSAGES_ENABLED DebugShout("CRemoteLoader[GetRemoteProcAddress] LoadLibrary failed to load module!"); #endif return NULL; } return (FARPROC)GetRemoteProcAddressImpl_DEPRECATED(Module, (const char*)Function); } FARPROC CRemoteLoader::GetRemoteProcAddress_DEPRECATED(LPCCH Module, LPCCH Function) { HMODULE hMod = GetRemoteModuleHandleA(Module); if (!hMod) hMod = LoadDependencyA(Module); if (!hMod) { #ifdef DEBUG_MESSAGES_ENABLED DebugShout("CRemoteLoader[GetRemoteProcAddress] LoadLibrary failed to load module!"); #endif return NULL; } return (FARPROC)GetRemoteProcAddressImpl_DEPRECATED(hMod, (const char*)Function); } FARPROC CRemoteLoader::GetRemoteProcAddress_DEPRECATED(HMODULE Module, SHORT Function) { if (!Module) { #ifdef DEBUG_MESSAGES_ENABLED DebugShout("CRemoteLoader[GetRemoteProcAddress] LoadLibrary failed to load module!"); #endif return NULL; } return (FARPROC)GetRemoteProcAddressImpl_DEPRECATED(Module, (const char*)Function); } FARPROC CRemoteLoader::GetRemoteProcAddress_DEPRECATED(LPCCH Module, SHORT Function) { HMODULE hMod = GetRemoteModuleHandleA(Module); if (!hMod) hMod = LoadDependencyA(Module); if (!hMod) { #ifdef DEBUG_MESSAGES_ENABLED DebugShout("CRemoteLoader[GetRemoteProcAddress] LoadLibrary failed to load module!"); #endif return NULL; } return (FARPROC)GetRemoteProcAddressImpl_DEPRECATED(hMod, (const char*)Function); } void* CRemoteLoader::GetRemoteProcAddressImpl_DEPRECATED(HMODULE module, const char *proc_name) { char* modb = (char*)module; IMAGE_DOS_HEADER* dos_header = (IMAGE_DOS_HEADER *)modb; IMAGE_NT_HEADERS* nt_headers = (IMAGE_NT_HEADERS *)(modb + dos_header->e_lfanew); IMAGE_OPTIONAL_HEADER *opt_header = &nt_headers->OptionalHeader; IMAGE_DATA_DIRECTORY *exp_entry = (IMAGE_DATA_DIRECTORY *)(&opt_header->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]); IMAGE_EXPORT_DIRECTORY *exp_dir = (IMAGE_EXPORT_DIRECTORY *)((size_t)modb + exp_entry->VirtualAddress); DWORD* func_table = (DWORD*)((size_t)modb + exp_dir->AddressOfFunctions); WORD* ord_table = (WORD *)((size_t)modb + exp_dir->AddressOfNameOrdinals); DWORD* name_table = (DWORD*)((size_t)modb + exp_dir->AddressOfNames); void *address = NULL; DWORD i; /* is ordinal? */ if (((ULONG_PTR)proc_name >> 16) == 0) { WORD ordinal = LOWORD(proc_name); ULONG_PTR ord_base = exp_dir->Base; /* is valid ordinal? */ if (ordinal < ord_base || ordinal > ord_base + exp_dir->NumberOfFunctions) return NULL; /* taking ordinal base into consideration */ address = (void*)((size_t)modb + func_table[ordinal - ord_base]); } else { /* import by name */ for (i = 0; i < exp_dir->NumberOfNames; i++) { /* name table pointers are rvas */ char* procEntryName = (char*)((size_t)modb + name_table[i]); if (_stricmp(proc_name, procEntryName) == 0) { address = (void*)((size_t)modb + func_table[ord_table[i]]); break; } } } /* is forwarded? */ if ((char *)address >= (char*)exp_dir && (char*)address < (char*)exp_dir + exp_entry->Size) { HMODULE frwd_module = 0; char* dll_name = _strdup((char*)address); if (!dll_name) return NULL; char* func_name = strchr(dll_name, '.'); *func_name++ = 0; address = NULL; char dllName[256]; strcpy_s(dllName, dll_name); strcat_s(dllName, strlen(dll_name) + 4 + 1, ".dll"); /* is already loaded? */ frwd_module = (HMODULE)GetRemoteModuleHandleA(dllName); if (!frwd_module) { frwd_module = (HMODULE)LoadDependencyA(dllName); if (!frwd_module) { printf("GetRemoteProcAddress failed to load module using GetRemoteModuleHandle and LoadLibrary!"); return NULL; } } bool forwardByOrd = strchr(func_name, '#') == 0 ? false : true; if (forwardByOrd) // forwarded by ordinal { WORD func_ord = atoi(func_name + 1); address = GetRemoteProcAddressImpl_DEPRECATED(frwd_module, (const char*)func_ord); } else { address = GetRemoteProcAddressImpl_DEPRECATED(frwd_module, func_name); } free(dll_name); } return address; }