diff --git a/reflective-loader/loader.c b/reflective_loader/loader.c similarity index 78% rename from reflective-loader/loader.c rename to reflective_loader/loader.c index be9dad4..0b8a486 100644 --- a/reflective-loader/loader.c +++ b/reflective_loader/loader.c @@ -20,14 +20,14 @@ void Load(PBYTE pImage, DWORD dwFunctionHash, PVOID pvUserData, DWORD dwUserData return; } - FARPROC pLoadLibraryA = GetExportAddrFromHash(hKernel32, LOAD_LIBRARY_A_HASH); - FARPROC pGetProcAddress = GetExportAddrFromHash(hKernel32, GET_PROC_ADDRESS_HASH); - FARPROC pVirtualAlloc = GetExportAddrFromHash(hKernel32, VIRTUAL_ALLOC_HASH); - FARPROC pFlushInstructionCache = GetExportAddrFromHash(hKernel32, FLUSH_INSTRUCTION_CACHE_HASH); - FARPROC pVirtualProtect = GetExportAddrFromHash(hKernel32, VIRTUAL_PROTECT_HASH); - FARPROC pSleep = GetExportAddrFromHash(hKernel32, SLEEP_HASH); + LOAD_LIBRARY_W pLoadLibraryW = (LOAD_LIBRARY_W)GetExportAddrFromHash(hKernel32, LOAD_LIBRARY_W_HASH); + GET_PROC_ADDRESS pGetProcAddress = (GET_PROC_ADDRESS)GetExportAddrFromHash(hKernel32, GET_PROC_ADDRESS_HASH); + VIRTUAL_ALLOC pVirtualAlloc = (VIRTUAL_ALLOC)GetExportAddrFromHash(hKernel32, VIRTUAL_ALLOC_HASH); + FLUSH_INSTRUCTION_CACHE pFlushInstructionCache = (FLUSH_INSTRUCTION_CACHE)GetExportAddrFromHash(hKernel32, FLUSH_INSTRUCTION_CACHE_HASH); + VIRTUAL_PROTECT pVirtualProtect = (VIRTUAL_PROTECT)GetExportAddrFromHash(hKernel32, VIRTUAL_PROTECT_HASH); + SLEEP pSleep = (SLEEP)GetExportAddrFromHash(hKernel32, SLEEP_HASH); - if (!pLoadLibraryA || !pGetProcAddress || !pVirtualAlloc || !pFlushInstructionCache || !pVirtualProtect || !pSleep) + if (!pLoadLibraryW || !pGetProcAddress || !pVirtualAlloc || !pFlushInstructionCache || !pVirtualProtect || !pSleep) { return; } @@ -58,16 +58,16 @@ void Load(PBYTE pImage, DWORD dwFunctionHash, PVOID pvUserData, DWORD dwUserData ULONGLONG ullPreferredImageBase = pNtHeaders->OptionalHeader.ImageBase; // Try to allocate the image to the preferred base address - PBYTE pNewImageBase = (PBYTE)pVirtualAlloc((LPVOID)ullPreferredImageBase, dwImageSize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); + ULONG_PTR pNewImageBase = (ULONG_PTR)pVirtualAlloc((LPVOID)ullPreferredImageBase, dwImageSize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); if (!pNewImageBase) { // Allocate to a random address if the preferred base address is already occupied - pNewImageBase = (PBYTE)pVirtualAlloc(NULL, dwImageSize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); + pNewImageBase = (ULONG_PTR)pVirtualAlloc(NULL, dwImageSize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); } CopySections(pNewImageBase, pImage, pNtHeaders); - memcpy(pNewImageBase, pImage, pNtHeaders->OptionalHeader.SizeOfHeaders); + CopyHeaders(pNewImageBase, pImage, pNtHeaders); /* 3.) Process the image relocations (assumes the image couldn't be loaded to the preferred base address) @@ -85,7 +85,7 @@ void Load(PBYTE pImage, DWORD dwFunctionHash, PVOID pvUserData, DWORD dwUserData 4.) Resolve the imports by patching the Import Address Table (IAT) */ - if (!PatchImportAddressTable(pNewImageBase, pDataDirectory, pGetProcAddress)) + if (!PatchImportAddressTable(pNewImageBase, pDataDirectory, pLoadLibraryW, pGetProcAddress)) { return; } @@ -109,19 +109,19 @@ void Load(PBYTE pImage, DWORD dwFunctionHash, PVOID pvUserData, DWORD dwUserData else { // Execute user defined function - FARPROC pFunction = GetExportAddrFromHash((HMODULE)pNewImageBase, dwFunctionHash); + USER_FUNCTION pFunction = (USER_FUNCTION)GetExportAddrFromHash((HMODULE)pNewImageBase, dwFunctionHash); pFunction(pvUserData, dwUserDataLen); } } -void FinalizeRelocations(PBYTE pNewImageBase, PIMAGE_NT_HEADERS64 pNtHeaders, FARPROC pVirtualProtect, FARPROC pFlushInstructionCache) +void FinalizeRelocations(ULONG_PTR pNewImageBase, PIMAGE_NT_HEADERS64 pNtHeaders, VIRTUAL_PROTECT pVirtualProtect, FLUSH_INSTRUCTION_CACHE pFlushInstructionCache) { PIMAGE_SECTION_HEADER pSectionHeader = IMAGE_FIRST_SECTION(pNtHeaders); for (size_t i = 0; i < pNtHeaders->FileHeader.NumberOfSections; pSectionHeader++, i++) { DWORD dwOldProtect; - DWORD dwNewProtect; + DWORD dwNewProtect = 0; // Definitions for readability DWORD dwIsExecutable = (pSectionHeader->Characteristics & IMAGE_SCN_MEM_EXECUTE) != 0; @@ -168,13 +168,13 @@ void FinalizeRelocations(PBYTE pNewImageBase, PIMAGE_NT_HEADERS64 pNtHeaders, FA dwNewProtect = PAGE_EXECUTE_READWRITE; } - pVirtualProtect(pNewImageBase + pSectionHeader->VirtualAddress, pSectionHeader->SizeOfRawData, dwNewProtect, &dwOldProtect); + pVirtualProtect((LPVOID)(pNewImageBase + pSectionHeader->VirtualAddress), pSectionHeader->SizeOfRawData, dwNewProtect, &dwOldProtect); } - pFlushInstructionCache(-1, NULL, 0); + pFlushInstructionCache((HANDLE)-1, NULL, 0); } -BOOL PatchImportAddressTable(PBYTE pNewImageBase, PIMAGE_DATA_DIRECTORY pDataDirectory, FARPROC pGetProcAddress) +BOOL PatchImportAddressTable(ULONG_PTR pNewImageBase, PIMAGE_DATA_DIRECTORY pDataDirectory, LOAD_LIBRARY_W pLoadLibraryW, GET_PROC_ADDRESS pGetProcAddress) { PIMAGE_IMPORT_DESCRIPTOR pImportDescriptor = (PIMAGE_IMPORT_DESCRIPTOR)(pNewImageBase + pDataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress); @@ -194,7 +194,7 @@ BOOL PatchImportAddressTable(PBYTE pNewImageBase, PIMAGE_DATA_DIRECTORY pDataDir while (pImportDescriptor->Name) { - HMODULE hModule = pLoadLibraryA((LPCSTR)(pNewImageBase + pImportDescriptor->Name)); + HMODULE hModule = pLoadLibraryW((LPCWSTR)(pNewImageBase + pImportDescriptor->Name)); if (!hModule) { @@ -228,7 +228,7 @@ BOOL PatchImportAddressTable(PBYTE pNewImageBase, PIMAGE_DATA_DIRECTORY pDataDir return TRUE; } -BOOL ProcessRelocations(PBYTE pNewImageBase, PIMAGE_DATA_DIRECTORY pDataDirectory, ULONG_PTR ulpDelta) +BOOL ProcessRelocations(ULONG_PTR pNewImageBase, PIMAGE_DATA_DIRECTORY pDataDirectory, ULONG_PTR ulpDelta) { PIMAGE_BASE_RELOCATION pRelocation = (PIMAGE_BASE_RELOCATION)(pNewImageBase + pDataDirectory->VirtualAddress); @@ -278,30 +278,40 @@ BOOL ProcessRelocations(PBYTE pNewImageBase, PIMAGE_DATA_DIRECTORY pDataDirector return TRUE; } -void CopySections(PBYTE pNewImageBase, PVOID pImage, PIMAGE_NT_HEADERS64 pNtHeaders) +void CopySections(ULONG_PTR pNewImageBase, PVOID pImage, PIMAGE_NT_HEADERS64 pNtHeaders) { PIMAGE_SECTION_HEADER pSectionHeader = IMAGE_FIRST_SECTION(pNtHeaders); - PBYTE pSectionBase, pSectionData; for (size_t i = 0; i < pNtHeaders->FileHeader.NumberOfSections; pSectionHeader++, i++) { - pSectionBase = pNewImageBase + pSectionHeader->VirtualAddress; - pSectionData = pImage + pSectionHeader->PointerToRawData; + for (size_t j = 0; j < pSectionHeader->SizeOfRawData; j++) + { + *((PBYTE)pNewImageBase + pSectionHeader->VirtualAddress + j) = *((PBYTE)pImage + pSectionHeader->PointerToRawData + j); + } + } +} - memcpy(pSectionBase, pSectionData, pSectionHeader->SizeOfRawData); +void CopyHeaders(ULONG_PTR pNewImageBase, PVOID pImage, PIMAGE_NT_HEADERS64 pNtHeaders) +{ + for (size_t i = 0; i < pNtHeaders->OptionalHeader.SizeOfHeaders; i++) + { + *((PBYTE)pNewImageBase + i) = *((PBYTE)pImage + i); } } HMODULE GetModuleAddrFromHash(DWORD dwHash) { + // https://en.wikipedia.org/wiki/Win32_Thread_Information_Block #if defined(_WIN64) + // PEB is located at GS:[0x60] PPEB pPeb = (PPEB)__readgsqword(0x60); #else + // PEB is located at FS:[0x30] PPEB pPeb = (PPEB)__readfsdword(0x30); #endif - PMY_PEB_LDR_DATA pLdr = pPeb->Ldr; - PMY_LDR_DATA_TABLE_ENTRY pEntry = pLdr->InLoadOrderModuleList.Flink; + PMY_PEB_LDR_DATA pLdr = (PMY_PEB_LDR_DATA)pPeb->Ldr; + PMY_LDR_DATA_TABLE_ENTRY pEntry = (PMY_LDR_DATA_TABLE_ENTRY)pLdr->InLoadOrderModuleList.Flink; DWORD dwModuleHash; UNICODE_STRING strBaseDllName; @@ -315,13 +325,13 @@ HMODULE GetModuleAddrFromHash(DWORD dwHash) return pEntry->DllBase; } - pEntry = pEntry->InLoadOrderLinks.Flink; + pEntry = (PMY_LDR_DATA_TABLE_ENTRY)pEntry->InLoadOrderLinks.Flink; } return NULL; } -FARPROC GetExportAddrFromHash(HMODULE hModule, DWORD dwHash) +HMODULE GetExportAddrFromHash(HMODULE hModule, DWORD dwHash) { PIMAGE_NT_HEADERS64 pNtHeaders = GetNtHeaders((PBYTE)hModule); @@ -347,9 +357,11 @@ FARPROC GetExportAddrFromHash(HMODULE hModule, DWORD dwHash) wOrdinal = ((WORD *)((PBYTE)hModule + pExportDirectoryData->AddressOfNameOrdinals))[i]; dwFuncRva = ((DWORD *)((PBYTE)hModule + pExportDirectoryData->AddressOfFunctions))[wOrdinal]; - return (FARPROC)((PBYTE)hModule + dwFuncRva); + return (HMODULE)((PBYTE)hModule + dwFuncRva); } } + + return NULL; } PIMAGE_NT_HEADERS64 GetNtHeaders(PBYTE pImage) diff --git a/reflective-loader/loader.h b/reflective_loader/loader.h similarity index 50% rename from reflective-loader/loader.h rename to reflective_loader/loader.h index 7aae5f9..1bf7445 100644 --- a/reflective-loader/loader.h +++ b/reflective_loader/loader.h @@ -7,14 +7,23 @@ #define KERNEL32_DLL_HASH 0x6DDB9555 // #define NTDLL_DLL_HASH 0x1EDAB0ED -#define LOAD_LIBRARY_A_HASH 0xB7072FDB // TODO: change to LoadLibraryW +#define LOAD_LIBRARY_W_HASH 0xB7072FF1 #define GET_PROC_ADDRESS_HASH 0xDECFC1BF #define VIRTUAL_ALLOC_HASH 0x097BC257 #define FLUSH_INSTRUCTION_CACHE_HASH 0xEFB7BF9D #define VIRTUAL_PROTECT_HASH 0xE857500D #define SLEEP_HASH 0x0E07CD7E +// Signatures from MSDN +typedef HMODULE(WINAPI *LOAD_LIBRARY_W)(LPCWSTR); +typedef ULONG_PTR(WINAPI *GET_PROC_ADDRESS)(HMODULE, LPCSTR); +typedef LPVOID(WINAPI *VIRTUAL_ALLOC)(LPVOID, SIZE_T, DWORD, DWORD); +typedef BOOL(WINAPI *FLUSH_INSTRUCTION_CACHE)(HANDLE, LPCVOID, SIZE_T); +typedef BOOL(WINAPI *VIRTUAL_PROTECT)(LPVOID, SIZE_T, DWORD, PDWORD); +typedef VOID(WINAPI *SLEEP)(DWORD); + typedef BOOL(WINAPI *DLLMAIN)(HMODULE, DWORD, LPVOID); +typedef BOOL(WINAPI *USER_FUNCTION)(LPVOID, DWORD); typedef struct _MY_PEB_LDR_DATA { @@ -44,12 +53,14 @@ typedef struct WORD type : 4; } IMAGE_RELOC, *PIMAGE_RELOC; +PIMAGE_NT_HEADERS64 GetNtHeaders(PBYTE pImage); DWORD CalculateHash(UNICODE_STRING *BaseDllName); HMODULE GetModuleAddrFromHash(DWORD dwHash); -FARPROC GetExportAddrFromHash(HMODULE hModule, DWORD dwHash); +HMODULE GetExportAddrFromHash(HMODULE hModule, DWORD dwHash); -void CopySections(PBYTE pNewImageBase, PVOID pImage, PIMAGE_NT_HEADERS64 pNtHeaders); -BOOL ProcessRelocations(PBYTE pNewImageBase, PIMAGE_DATA_DIRECTORY pDataDirectory, ULONG_PTR ulpDelta); -BOOL PatchImportAddressTable(PBYTE pNewImageBase, PIMAGE_DATA_DIRECTORY pDataDirectory, FARPROC pGetProcAddress); -void FinalizeRelocations(PBYTE pNewImageBase, PIMAGE_NT_HEADERS64 pNtHeaders, FARPROC pVirtualProtect, FARPROC pFlushInstructionCache); +void CopySections(ULONG_PTR pNewImageBase, PVOID pImage, PIMAGE_NT_HEADERS64 pNtHeaders); +void CopyHeaders(ULONG_PTR pNewImageBase, PVOID pImage, PIMAGE_NT_HEADERS64 pNtHeaders); +BOOL ProcessRelocations(ULONG_PTR pNewImageBase, PIMAGE_DATA_DIRECTORY pDataDirectory, ULONG_PTR ulpDelta); +BOOL PatchImportAddressTable(ULONG_PTR pNewImageBase, PIMAGE_DATA_DIRECTORY pDataDirectory, LOAD_LIBRARY_W pLoadLibraryW, GET_PROC_ADDRESS pGetProcAddress); +void FinalizeRelocations(ULONG_PTR pNewImageBase, PIMAGE_NT_HEADERS64 pNtHeaders, VIRTUAL_PROTECT pVirtualProtect, FLUSH_INSTRUCTION_CACHE pFlushInstructionCache);