diff --git a/MemoryModule/LoadDllMemoryApi.cpp b/MemoryModule/LoadDllMemoryApi.cpp new file mode 100644 index 0000000..132b2b9 --- /dev/null +++ b/MemoryModule/LoadDllMemoryApi.cpp @@ -0,0 +1,38 @@ +#include "LoadDllMemoryApi.h" +#include "Native.h" + +HMEMORYMODULE WINAPI LoadLibraryMemory(PVOID BufferAddress) { + HMEMORYMODULE hMemoryModule = nullptr; + NTSTATUS status = NtLoadDllMemory(&hMemoryModule, BufferAddress, 0); + if (!NT_SUCCESS(status)) { + SetLastError(RtlNtStatusToDosError(status)); + } + return hMemoryModule; +} + +HMEMORYMODULE WINAPI LoadLibraryMemoryExA(PVOID BufferAddress, size_t Reserved, LPCSTR DllBaseName, LPCSTR DllFullName, DWORD Flags) { + HMEMORYMODULE hMemoryModule = nullptr; + NTSTATUS status = NtLoadDllMemoryExA(&hMemoryModule, nullptr, Flags, BufferAddress, Reserved, DllBaseName, DllFullName); + if (!NT_SUCCESS(status)) { + SetLastError(RtlNtStatusToDosError(status)); + } + return hMemoryModule; +} + +HMEMORYMODULE WINAPI LoadLibraryMemoryExW(PVOID BufferAddress, size_t Reserved, LPCWSTR DllBaseName, LPCWSTR DllFullName, DWORD Flags) { + HMEMORYMODULE hMemoryModule = nullptr; + NTSTATUS status = NtLoadDllMemoryExW(&hMemoryModule, nullptr, Flags, BufferAddress, Reserved, DllBaseName, DllFullName); + if (!NT_SUCCESS(status)) { + SetLastError(RtlNtStatusToDosError(status)); + } + return hMemoryModule; +} + +BOOL WINAPI FreeLibraryMemory(HMEMORYMODULE hMemoryModule) { + NTSTATUS status = NtUnloadDllMemory(hMemoryModule); + if (!NT_SUCCESS(status)) { + SetLastError(RtlNtStatusToDosError(status)); + return FALSE; + } + return TRUE; +} diff --git a/MemoryModule/LoadDllMemoryApi.h b/MemoryModule/LoadDllMemoryApi.h index 5cb787e..abef6f5 100644 --- a/MemoryModule/LoadDllMemoryApi.h +++ b/MemoryModule/LoadDllMemoryApi.h @@ -1,72 +1,49 @@ #pragma once #include -typedef PVOID HMEMORYMODULE, HMEMORYRSRC; +typedef HMODULE HMEMORYMODULE; +typedef PVOID HMEMORYRSRC; + +#define MemoryModuleToModule(_hMemoryModule_) (HMODULE(_hMemoryModule_)) + +#ifndef NT_SUCCESS +#define NT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0) +#endif //Deprecated API #ifndef _DEPRECATED -/** - * Load DLL from memory location with the given size. - * - * All dependencies are resolved using default LoadLibrary/GetProcAddress - * calls through the Windows API. - */ + NOT_BUILD_WINDOWS_DEPRECATE -__drv_preferredFunction("NtLoadDllMemory*", "Deprecated. Use NtLoadDllMemory or NtLoadDllMemoryEx.") +__drv_preferredFunction("LoadLibraryMemory", "Deprecated. Use LoadLibraryMemory.") HMEMORYMODULE MemoryLoadLibrary(const void*); -/** - * Get address of exported method. Supports loading both by name and by - * ordinal value. - */ NOT_BUILD_WINDOWS_DEPRECATE __drv_preferredFunction("GetProcAddress", "Deprecated. Use Win32API GetProcAddress.") FARPROC MemoryGetProcAddress(HMEMORYMODULE, LPCSTR); -/** - * Free previously loaded DLL. - */ NOT_BUILD_WINDOWS_DEPRECATE -__drv_preferredFunction("NtUnloadDllMemory", "Deprecated. Use NtUnloadDllMemory.") +__drv_preferredFunction("FreeLibrayMemory", "Deprecated. Use FreeLibrayMemory.") bool MemoryFreeLibrary(HMEMORYMODULE); -/** - * Find the location of a resource with the specified type and name. - */ NOT_BUILD_WINDOWS_DEPRECATE __drv_preferredFunction("FindResource", "Deprecated. Use Win32API FindResource.") HMEMORYRSRC MemoryFindResource(HMEMORYMODULE, LPCTSTR, LPCTSTR); -/** - * Find the location of a resource with the specified type, name and language. - */ NOT_BUILD_WINDOWS_DEPRECATE __drv_preferredFunction("FindResourceEx", "Deprecated. Use Win32API FindResourceEx.") HMEMORYRSRC MemoryFindResourceEx(HMEMORYMODULE, LPCTSTR, LPCTSTR, WORD); -/** - * Get the size of the resource in bytes. - */ NOT_BUILD_WINDOWS_DEPRECATE __drv_preferredFunction("SizeofResource", "Deprecated. Use Win32API SizeofResource.") DWORD MemorySizeofResource(HMEMORYMODULE, HMEMORYRSRC); -/** - * Get a pointer to the contents of the resource. - */ NOT_BUILD_WINDOWS_DEPRECATE __drv_preferredFunction("LoadResource", "Deprecated. Use Win32API LoadResource.") LPVOID MemoryLoadResource(HMEMORYMODULE, HMEMORYRSRC); -/** - * Load a string resource. - */ NOT_BUILD_WINDOWS_DEPRECATE __drv_preferredFunction("LoadString*", "Deprecated. Use Win32API LoadStringA or LoadStringW.") int MemoryLoadString(HMEMORYMODULE, UINT, LPTSTR, int); -/** - * Load a string resource with a given language. - */ NOT_BUILD_WINDOWS_DEPRECATE __drv_preferredFunction("LoadString*", "Deprecated. Use Win32API LoadStringA or LoadStringW.") int MemoryLoadStringEx(HMEMORYMODULE, UINT, LPTSTR, int, WORD); @@ -104,6 +81,9 @@ NTSTATUS NTAPI NtLoadDllMemory( //If this flag is specified, this routine will not fail even if the call to LdrpTlsData fails. #define LOAD_FLAGS_NOT_FAIL_IF_HANDLE_TLS 0x20000000 +//If this flag is specified, the input image buffer will not be checked before loading. +#define LOAD_FLAGS_PASS_IMAGE_CHECK 0x40000000 + //If this flag is specified, exception handling will not be supported. #define LOAD_FLAGS_NOT_ADD_INVERTED_FUNCTION 0x00000001 @@ -157,15 +137,21 @@ extern "C" { __declspec(noreturn) VOID NTAPI NtUnloadDllMemoryAndExitThread(IN HMEMORYMODULE BaseAddress, IN DWORD dwExitCode); } -#define LoadLibraryMemory NtLoadDllMemory -#define FreeLibraryMemory NtUnloadDllMemory +HMEMORYMODULE WINAPI LoadLibraryMemory(PVOID BufferAddress); + +HMEMORYMODULE WINAPI LoadLibraryMemoryExA(PVOID BufferAddress, size_t Reserved, LPCSTR DllBaseName, LPCSTR DllFullName, DWORD Flags); + +HMEMORYMODULE WINAPI LoadLibraryMemoryExW(PVOID BufferAddress, size_t Reserved, LPCWSTR DllBaseName, LPCWSTR DllFullName, DWORD Flags); + +BOOL WINAPI FreeLibraryMemory(HMEMORYMODULE hMemoryModule); + #define FreeLibraryMemoryAndExitThread NtUnloadDllMemoryAndExitThread #ifdef UNICODE #define NtLoadDllMemoryEx NtLoadDllMemoryExW -#define LoadLibraryMemoryEx NtLoadDllMemoryExW +#define LoadLibraryMemoryEx LoadLibraryMemoryExW #else #define NtLoadDllMemoryEx NtLoadDllMemoryExA -#define LoadLibraryMemoryEx NtLoadDllMemoryExA +#define LoadLibraryMemoryEx LoadLibraryMemoryExA #endif diff --git a/MemoryModule/MemoryModule.cpp b/MemoryModule/MemoryModule.cpp index 80f0c63..c6914f3 100644 --- a/MemoryModule/MemoryModule.cpp +++ b/MemoryModule/MemoryModule.cpp @@ -28,7 +28,7 @@ static PIMAGE_NT_HEADERS WINAPI GetImageNtHeaders(PMEMORYMODULE pModule) { if (pModule->Signature != MEMORY_MODULE_SIGNATURE)return nullptr; PIMAGE_DOS_HEADER dos = (PIMAGE_DOS_HEADER)((LPBYTE)pModule - pModule->SizeofHeaders); PIMAGE_NT_HEADERS headers = (PIMAGE_NT_HEADERS)((LPBYTE)dos + dos->e_lfanew); - if (headers->OptionalHeader.ImageBase /*+ pModule->headers_align*/ != (ULONG64)pModule->codeBase)return nullptr; + if (headers->OptionalHeader.ImageBase != (ULONG64)pModule->codeBase)return nullptr; return headers; } @@ -109,53 +109,35 @@ static int ProtectionFlags[2][2][2] = { {PAGE_EXECUTE_READ, PAGE_EXECUTE_READWRITE}, }, }; -static SIZE_T GetRealSectionSize(PMEMORYMODULE module, PIMAGE_SECTION_HEADER section); -static VOID FinalSectionsProtect(PMEMORYMODULE module) { - PIMAGE_NT_HEADERS headers = GetImageNtHeaders(module); - PIMAGE_SECTION_HEADER sections = IMAGE_FIRST_SECTION(headers); - DWORD protect, oldProtect; - bool executable, readable, writeable; -#ifdef _WIN64 - uintptr_t imageOffset = ((uintptr_t)headers->OptionalHeader.ImageBase & 0xffffffff00000000); -#else - static const uintptr_t imageOffset = 0; -#endif - for (WORD i = 0; i < headers->FileHeader.NumberOfSections; ++i, ++sections) { - executable = (sections->Characteristics & IMAGE_SCN_MEM_EXECUTE); - readable = (sections->Characteristics & IMAGE_SCN_MEM_READ); - writeable = (sections->Characteristics & IMAGE_SCN_MEM_WRITE); - protect = ProtectionFlags[executable][readable][writeable]; - if (sections->Characteristics & IMAGE_SCN_MEM_NOT_CACHED) protect |= PAGE_NOCACHE; - VirtualProtect((LPVOID)((uintptr_t)sections->Misc.PhysicalAddress | imageOffset), - GetRealSectionSize(module, sections), protect, &oldProtect); - } - return; -} static BOOL CopySections(const unsigned char* data, PMEMORYMODULE module) { - LPBYTE codeBase = module->codeBase; LPVOID dest; PIMAGE_NT_HEADERS headers = GetImageNtHeaders(module); - PIMAGE_SECTION_HEADER section = IMAGE_FIRST_SECTION(headers); + PIMAGE_SECTION_HEADER section = headers ? IMAGE_FIRST_SECTION(headers) : nullptr; size_t alloc_size = 0; bool cp = false; + + if (!headers) { + SetLastError(ERROR_BAD_EXE_FORMAT); + return FALSE; + } for (int i = 0; i < headers->FileHeader.NumberOfSections; i++, section++) { alloc_size = headers->OptionalHeader.SectionAlignment; cp = false; if (section->SizeOfRawData) { __try { - ProbeForRead(data, static_cast(section->PointerToRawData) + section->SizeOfRawData); + ProbeForRead(data + static_cast(section->PointerToRawData), section->SizeOfRawData); } __except (EXCEPTION_EXECUTE_HANDLER) { + SetLastError(ERROR_BAD_EXE_FORMAT); return FALSE; } alloc_size = section->SizeOfRawData; cp = true; } if (alloc_size) { - if (!(dest = VirtualAlloc(codeBase + section->VirtualAddress, alloc_size, MEM_COMMIT, PAGE_READWRITE))) { - //section = IMAGE_FIRST_SECTION(headers); - //for (int j = 0; j < i; ++j, ++section)VirtualFree(codeBase + section->VirtualAddress, 0, MEM_RELEASE); + if (!(dest = VirtualAlloc((LPSTR)headers->OptionalHeader.ImageBase + section->VirtualAddress, alloc_size, MEM_COMMIT, PAGE_READWRITE))) { + SetLastError(ERROR_OUTOFMEMORY); return FALSE; } section->Misc.PhysicalAddress = (DWORD)((uintptr_t)dest & 0xffffffff); @@ -184,18 +166,34 @@ static SIZE_T GetRealSectionSize(PMEMORYMODULE module, PIMAGE_SECTION_HEADER sec } static BOOL FinalizeSection(PMEMORYMODULE module, PSECTIONFINALIZEDATA sectionData) { + DWORD protect, oldProtect; + BOOL executable; + BOOL readable; + BOOL writeable; + PIMAGE_NT_HEADERS headers = GetImageNtHeaders(module); + if (!sectionData->size) return TRUE; if (sectionData->characteristics & IMAGE_SCN_MEM_DISCARDABLE) { // section is not needed any more and can safely be freed if (sectionData->address == sectionData->alignedAddress && - (sectionData->last || GetImageNtHeaders(module)->OptionalHeader.SectionAlignment == module->pageSize || !(sectionData->size % module->pageSize))) { -#pragma warning (disable:6250) + (sectionData->last || headers->OptionalHeader.SectionAlignment == module->pageSize || + (sectionData->size % module->pageSize) == 0) + ) +#pragma warning(disable:6250) VirtualFree(sectionData->address, sectionData->size, MEM_DECOMMIT); -#pragma warning (default:6250) - } +#pragma warning(default:6250) return TRUE; } - return TRUE; + + // determine protection flags based on characteristics + executable = (sectionData->characteristics & IMAGE_SCN_MEM_EXECUTE) != 0; + readable = (sectionData->characteristics & IMAGE_SCN_MEM_READ) != 0; + writeable = (sectionData->characteristics & IMAGE_SCN_MEM_WRITE) != 0; + protect = ProtectionFlags[executable][readable][writeable]; + if (sectionData->characteristics & IMAGE_SCN_MEM_NOT_CACHED) protect |= PAGE_NOCACHE; + + // change memory access flags + return VirtualProtect(sectionData->address, sectionData->size, protect, &oldProtect); } static BOOL FinalizeSections(PMEMORYMODULE module) { @@ -214,16 +212,17 @@ static BOOL FinalizeSections(PMEMORYMODULE module) { sectionData.last = FALSE; section++; - // loop through all sections and change access flags for (int i = 1; i < headers->FileHeader.NumberOfSections; i++, section++) { LPVOID sectionAddress = (LPVOID)((uintptr_t)section->Misc.PhysicalAddress | imageOffset); LPVOID alignedAddress = AlignAddressDown(sectionAddress, module->pageSize); SIZE_T sectionSize = GetRealSectionSize(module, section); if (sectionData.alignedAddress == alignedAddress || (uintptr_t)sectionData.address + sectionData.size > (uintptr_t) alignedAddress) { - if (!(section->Characteristics & IMAGE_SCN_MEM_DISCARDABLE) || !(sectionData.characteristics & IMAGE_SCN_MEM_DISCARDABLE)) + if ((section->Characteristics & IMAGE_SCN_MEM_DISCARDABLE) == 0 || (sectionData.characteristics & IMAGE_SCN_MEM_DISCARDABLE) == 0) { sectionData.characteristics = (sectionData.characteristics | section->Characteristics) & ~IMAGE_SCN_MEM_DISCARDABLE; - else + } + else { sectionData.characteristics |= section->Characteristics; + } sectionData.size = (((uintptr_t)sectionAddress) + ((uintptr_t)sectionSize)) - (uintptr_t)sectionData.address; continue; } @@ -293,68 +292,80 @@ static BOOL PerformBaseRelocation(PMEMORYMODULE module, ptrdiff_t delta) { return TRUE; } +static BOOL GetImportAddressTableEntryCountAndVerify(PMEMORYMODULE module, LPDWORD Count, PIMAGE_IMPORT_DESCRIPTOR* IAT) { + __try { + PIMAGE_NT_HEADERS headers = GetImageNtHeaders(module); + PIMAGE_DATA_DIRECTORY dir = GET_HEADER_DICTIONARY(headers, IMAGE_DIRECTORY_ENTRY_IMPORT); + PIMAGE_IMPORT_DESCRIPTOR iat = *IAT = (dir && dir->Size) ? decltype(iat)(headers->OptionalHeader.ImageBase + dir->VirtualAddress) : nullptr; + *Count = 0; + if (!iat)return TRUE; + ProbeForRead(iat, sizeof(IMAGE_IMPORT_DESCRIPTOR)); + while (iat->Name) { + ++*Count; + ++iat; + ProbeForRead(iat, sizeof(IMAGE_IMPORT_DESCRIPTOR)); + } + return TRUE; + } + __except (EXCEPTION_EXECUTE_HANDLER) { + SetLastError(RtlNtStatusToDosError(GetExceptionCode())); + return FALSE; + } +} +static void FreeLoadedModule(PMEMORYMODULE module) { + for (DWORD i = 0; i < module->dwModulesCount; ++i) FreeLibrary(module->hModulesList[i]); + delete[]module->hModulesList; + module->hModulesList = nullptr; + module->dwModulesCount = 0; + return; +} static BOOL BuildImportTable(PMEMORYMODULE module) { unsigned char* codeBase = module->codeBase; PIMAGE_IMPORT_DESCRIPTOR importDesc; - BOOL result = TRUE; - PIMAGE_NT_HEADERS headers = GetImageNtHeaders(module); - PIMAGE_DATA_DIRECTORY directory = GET_HEADER_DICTIONARY(headers, IMAGE_DIRECTORY_ENTRY_IMPORT); - if (directory->Size == 0) { - return TRUE; + DWORD count; + if (!GetImportAddressTableEntryCountAndVerify(module, &count, &importDesc)) { + SetLastError(ERROR_BAD_EXE_FORMAT); + return FALSE; } - - importDesc = (PIMAGE_IMPORT_DESCRIPTOR)(codeBase + directory->VirtualAddress); - for (; !IsBadReadPtr(importDesc, sizeof(IMAGE_IMPORT_DESCRIPTOR)) && importDesc->Name; importDesc++) { - uintptr_t* thunkRef; - FARPROC* funcRef; - HMODULE* tmp; - HMODULE handle = LoadLibraryA((LPCSTR)(codeBase + importDesc->Name)); - if (!handle) { - SetLastError(ERROR_MOD_NOT_FOUND); - result = FALSE; - break; - } - - if (!(tmp = (HMODULE*)realloc(module->hModulesList, (static_cast(module->dwModulesCount) + 1)* (sizeof(HMODULE))))) { - FreeLibrary(handle); - SetLastError(ERROR_OUTOFMEMORY); - result = FALSE; - break; - } - module->hModulesList = tmp; - - module->hModulesList[module->dwModulesCount++] = handle; - if (importDesc->OriginalFirstThunk) { - thunkRef = (uintptr_t*)(codeBase + importDesc->OriginalFirstThunk); + if (!importDesc || !count)return TRUE; + if (!(module->hModulesList = new HMODULE[count])) { + SetLastError(ERROR_OUTOFMEMORY); + return FALSE; + } + RtlZeroMemory(module->hModulesList, sizeof(HMODULE) * count); + __try { + for (DWORD i = 0; i < count; ++i, ++importDesc) { + uintptr_t* thunkRef; + FARPROC* funcRef; + HMODULE handle = LoadLibraryA((LPCSTR)(codeBase + importDesc->Name)); + if (!handle) { + FreeLoadedModule(module); + SetLastError(ERROR_MOD_NOT_FOUND); + return FALSE; + } + module->hModulesList[module->dwModulesCount++] = handle; + thunkRef = (uintptr_t*)(codeBase + (importDesc->OriginalFirstThunk ? importDesc->OriginalFirstThunk : importDesc->FirstThunk)); funcRef = (FARPROC*)(codeBase + importDesc->FirstThunk); - } - else { - // no hint table - thunkRef = (uintptr_t*)(codeBase + importDesc->FirstThunk); - funcRef = (FARPROC*)(codeBase + importDesc->FirstThunk); - } - for (; *thunkRef; thunkRef++, funcRef++) { - if (IMAGE_SNAP_BY_ORDINAL(*thunkRef)) { - *funcRef = GetProcAddress(handle, (LPCSTR)IMAGE_ORDINAL(*thunkRef)); + while (*thunkRef) { + *funcRef = GetProcAddress( + handle, + IMAGE_SNAP_BY_ORDINAL(*thunkRef) ? (LPCSTR)IMAGE_ORDINAL(*thunkRef) : (LPCSTR)PIMAGE_IMPORT_BY_NAME(codeBase + (*thunkRef))->Name + ); + if (!*funcRef) { + FreeLoadedModule(module); + SetLastError(ERROR_PROC_NOT_FOUND); + return FALSE; + } + ++thunkRef; + ++funcRef; } - else { - PIMAGE_IMPORT_BY_NAME thunkData = (PIMAGE_IMPORT_BY_NAME)(codeBase + (*thunkRef)); - *funcRef = GetProcAddress(handle, (LPCSTR)&thunkData->Name); - } - if (*funcRef == 0) { - result = FALSE; - break; - } - } - - if (!result) { - FreeLibrary(handle); - SetLastError(ERROR_PROC_NOT_FOUND); - break; } } - - return result; + __except (EXCEPTION_EXECUTE_HANDLER) { + SetLastError(RtlNtStatusToDosError(GetExceptionCode())); + return FALSE; + } + return TRUE; } HMEMORYMODULE MemoryLoadLibrary(const void* data) { @@ -423,7 +434,7 @@ HMEMORYMODULE MemoryLoadLibrary(const void* data) { SetLastError(ERROR_BAD_EXE_FORMAT); return nullptr; } - alignedImageSize += headers_align = (DWORD)AlignValueUp(sizeof(HMEMORYMODULE) + old_header->OptionalHeader.SizeOfHeaders, sysInfo.dwPageSize); + alignedImageSize += headers_align = (DWORD)AlignValueUp(sizeof(MEMORYMODULE) + old_header->OptionalHeader.SizeOfHeaders, sysInfo.dwPageSize); // reserve memory for image of library // XXX: is it correct to commit the complete memory region at once? @@ -494,7 +505,6 @@ HMEMORYMODULE MemoryLoadLibrary(const void* data) { // mark memory pages depending on section headers and release // sections that are marked as "discardable" if (!FinalizeSections(hMemoryModule)) goto error; - FinalSectionsProtect(hMemoryModule); // TLS callbacks are executed BEFORE the main loading if (!ExecuteTLS(hMemoryModule)) goto error; @@ -509,16 +519,16 @@ HMEMORYMODULE MemoryLoadLibrary(const void* data) { } } __except (EXCEPTION_EXECUTE_HANDLER) { - SetLastError(ERROR_ACCESS_DENIED); + SetLastError(RtlNtStatusToDosError(GetExceptionCode())); goto error; } hMemoryModule->initialized = TRUE; } - return base; + return (HMEMORYMODULE)base; error: // cleanup - MemoryFreeLibrary(hMemoryModule); + MemoryFreeLibrary((HMEMORYMODULE)base); return nullptr; } @@ -533,19 +543,18 @@ bool MemoryFreeLibrary(HMEMORYMODULE mod) { (*DllEntry)((HINSTANCE)module->codeBase, DLL_PROCESS_DETACH, 0); } if (module->nameExportsTable)delete[] module->nameExportsTable; - if (module->hModulesList != nullptr) { - int i; - for (i = 0; i < module->dwModulesCount; i++) { + if (module->hModulesList) { + for (DWORD i = 0; i < module->dwModulesCount; ++i) { if (module->hModulesList[i]) { FreeLibrary(module->hModulesList[i]); } } - free(module->hModulesList); + delete[] module->hModulesList; } #ifdef _WIN64 FreePointerList(module->blockedMemory); #endif - if (module->codeBase != nullptr) VirtualFree(mod, 0, MEM_RELEASE); + if (module->codeBase) VirtualFree(mod, 0, MEM_RELEASE); return true; } @@ -570,7 +579,11 @@ FARPROC MemoryGetProcAddress(HMEMORYMODULE mod, LPCSTR name) { DWORD idx = 0; PIMAGE_EXPORT_DIRECTORY exports; PIMAGE_NT_HEADERS headers = GetImageNtHeaders(module); - PIMAGE_DATA_DIRECTORY directory = GET_HEADER_DICTIONARY(headers, IMAGE_DIRECTORY_ENTRY_EXPORT); + PIMAGE_DATA_DIRECTORY directory = headers ? GET_HEADER_DICTIONARY(headers, IMAGE_DIRECTORY_ENTRY_EXPORT) : nullptr; + if (!headers) { + SetLastError(ERROR_INVALID_HANDLE); + return nullptr; + } if (directory->Size == 0) { // no export table found SetLastError(ERROR_PROC_NOT_FOUND); @@ -756,13 +769,18 @@ static PIMAGE_RESOURCE_DIRECTORY_ENTRY _MemorySearchResourceEntry(void* root, PI HMEMORYRSRC MemoryFindResourceEx(HMEMORYMODULE module, LPCTSTR name, LPCTSTR type, WORD language) { PMEMORYMODULE mod = MapMemoryModuleHandle(module); unsigned char* codeBase = mod->codeBase; - PIMAGE_DATA_DIRECTORY directory = GET_HEADER_DICTIONARY(GetImageNtHeaders(mod), IMAGE_DIRECTORY_ENTRY_RESOURCE); + PIMAGE_NT_HEADERS headers = GetImageNtHeaders(mod); + PIMAGE_DATA_DIRECTORY directory = headers ? GET_HEADER_DICTIONARY(headers, IMAGE_DIRECTORY_ENTRY_RESOURCE) : nullptr; PIMAGE_RESOURCE_DIRECTORY rootResources; PIMAGE_RESOURCE_DIRECTORY nameResources; PIMAGE_RESOURCE_DIRECTORY typeResources; PIMAGE_RESOURCE_DIRECTORY_ENTRY foundType; PIMAGE_RESOURCE_DIRECTORY_ENTRY foundName; PIMAGE_RESOURCE_DIRECTORY_ENTRY foundLanguage; + if (!headers) { + SetLastError(ERROR_INVALID_HANDLE); + return nullptr; + } if (directory->Size == 0) { // no resource table found SetLastError(ERROR_RESOURCE_DATA_NOT_FOUND); diff --git a/MemoryModule/MemoryModule.h b/MemoryModule/MemoryModule.h index a32d5a8..3767cf0 100644 --- a/MemoryModule/MemoryModule.h +++ b/MemoryModule/MemoryModule.h @@ -24,7 +24,7 @@ typedef struct POINTER_LIST { void* address; } POINTER_LIST; #endif -typedef void* HMEMORYMODULE; +typedef HMODULE HMEMORYMODULE; typedef void* HMEMORYRSRC; typedef struct _MEMORYMODULE { /* diff --git a/MemoryModule/MemoryModule.vcxproj b/MemoryModule/MemoryModule.vcxproj index 4882657..d9fd5ed 100644 --- a/MemoryModule/MemoryModule.vcxproj +++ b/MemoryModule/MemoryModule.vcxproj @@ -19,6 +19,7 @@ + diff --git a/MemoryModule/MemoryModule.vcxproj.filters b/MemoryModule/MemoryModule.vcxproj.filters index 52ad386..828e32d 100644 --- a/MemoryModule/MemoryModule.vcxproj.filters +++ b/MemoryModule/MemoryModule.vcxproj.filters @@ -24,6 +24,9 @@ Source Files + + Source Files + diff --git a/MemoryModule/NativeFunctionsInternal.cpp b/MemoryModule/NativeFunctionsInternal.cpp index 02ff20b..1d1656b 100644 --- a/MemoryModule/NativeFunctionsInternal.cpp +++ b/MemoryModule/NativeFunctionsInternal.cpp @@ -82,7 +82,7 @@ static ULONG NTAPI LdrHashEntry(IN const UNICODE_STRING& str, IN bool _xor = tru return result; } -static HANDLE NTAPI RtlFindtLdrpHeap() { +static HANDLE NTAPI RtlFindLdrpHeap() { PLIST_ENTRY ListHead, ListEntry; PLDR_DATA_TABLE_ENTRY CurEntry; MEMORY_BASIC_INFORMATION mbi{}; @@ -109,13 +109,13 @@ static PLIST_ENTRY NTAPI RtlFindLdrpHashTable() { } static PVOID NTAPI NtAllocateLdrpHeap(IN size_t size) { - HANDLE heap = RtlFindtLdrpHeap(); + HANDLE heap = RtlFindLdrpHeap(); if (!heap)return nullptr; return RtlAllocateHeap(heap, HEAP_ZERO_MEMORY, size); } static BOOL NTAPI NtFreeLdrpHeap(IN PVOID buffer) { - HANDLE LdrpHeap = RtlFindtLdrpHeap(); + HANDLE LdrpHeap = RtlFindLdrpHeap(); if (!LdrpHeap)return FALSE; return RtlFreeHeap(LdrpHeap, 0, buffer); } @@ -455,7 +455,19 @@ static bool NTAPI NtFreeLdrDataTableEntry(IN PLDR_DATA_TABLE_ENTRY LdrEntry) { NtRemoveModuleBaseAddressIndexNode(LdrEntry); } case win7: - case vista: + case vista: { + if (NtLdrDataTableEntrySize() == sizeof(LDR_DATA_TABLE_ENTRY_VISTA) || + NtLdrDataTableEntrySize() == sizeof(LDR_DATA_TABLE_ENTRY_WIN7)) { + PLDR_DATA_TABLE_ENTRY_VISTA entry = (decltype(entry))LdrEntry; + PLIST_ENTRY head = &entry->ForwarderLinks, next = head->Flink; + while (head != next) { + PLDR_DATA_TABLE_ENTRY dep = *(decltype(&dep))((size_t*)next + 2); + LdrUnloadDll(dep->DllBase); + next = next->Flink; + NtFreeLdrpHeap(next->Blink); + } + } + } case xp: { NtFreeLdrpHeap(LdrEntry->BaseDllName.Buffer); NtFreeLdrpHeap(LdrEntry->FullDllName.Buffer); @@ -646,6 +658,52 @@ static NTSTATUS NTAPI NtMapDllMemory(IN HMEMORYMODULE ViewBase, IN DWORD dwFlags return STATUS_SUCCESS; } +#ifndef _INLINE_INTERNALS +static __forceinline WORD CalcCheckSum(DWORD StartValue, LPVOID BaseAddress, DWORD WordCount) { + LPWORD Ptr = (LPWORD)BaseAddress; + DWORD Sum = StartValue; + for (DWORD i = 0; i < WordCount; i++) { + Sum += *Ptr; + if (HIWORD(Sum) != 0) Sum = LOWORD(Sum) + HIWORD(Sum); + Ptr++; + } + return (WORD)(LOWORD(Sum) + HIWORD(Sum)); +} +BOOLEAN __forceinline WINAPI CheckSumBufferedFile(LPVOID BaseAddress, DWORD BufferLength) { + PIMAGE_NT_HEADERS header = RtlImageNtHeader(BaseAddress); + DWORD CalcSum = CalcCheckSum(0, BaseAddress, (BufferLength + 1) / sizeof(WORD)); + DWORD HdrSum = header->OptionalHeader.CheckSum; + if (!HdrSum)return TRUE; + + if (!header) return FALSE; + if (LOWORD(CalcSum) >= LOWORD(HdrSum)) CalcSum -= LOWORD(HdrSum); + else CalcSum = ((LOWORD(CalcSum) - LOWORD(HdrSum)) & 0xFFFF) - 1; + if (LOWORD(CalcSum) >= HIWORD(HdrSum)) CalcSum -= HIWORD(HdrSum); + else CalcSum = ((LOWORD(CalcSum) - HIWORD(HdrSum)) & 0xFFFF) - 1; + CalcSum += BufferLength; + return HdrSum == CalcSum; +} +#endif +BOOLEAN NTAPI RtlIsValidImageBuffer(PVOID Buffer) { + BOOLEAN result = FALSE; + __try { + PIMAGE_NT_HEADERS headers = RtlImageNtHeader(Buffer); + PIMAGE_SECTION_HEADER sections = headers ? IMAGE_FIRST_SECTION(headers) : nullptr; + size_t SizeofImage = headers ? headers->OptionalHeader.SizeOfHeaders : 0; + if (!sections)return result; + + ProbeForRead(sections, headers->FileHeader.NumberOfSections * sizeof(IMAGE_SECTION_HEADER)); + for (WORD i = 0; i < headers->FileHeader.NumberOfSections; ++i, ++sections) + SizeofImage += sections->SizeOfRawData; + ProbeForRead(Buffer, SizeofImage); + result = CheckSumBufferedFile(Buffer, SizeofImage); + } + __except (EXCEPTION_EXECUTE_HANDLER) { + SetLastError(RtlNtStatusToDosError(GetExceptionCode())); + } + return result; +} + NTSTATUS NTAPI NtLoadDllMemory(OUT HMEMORYMODULE* BaseAddress, IN LPVOID BufferAddress, IN size_t BufferSize) { return NtLoadDllMemoryExW(BaseAddress, nullptr, LOAD_FLAGS_NOT_FAIL_IF_HANDLE_TLS, BufferAddress, BufferSize, nullptr, nullptr); } @@ -662,13 +720,12 @@ NTSTATUS NTAPI NtLoadDllMemoryExW( NTSTATUS status = STATUS_SUCCESS; PLDR_DATA_TABLE_ENTRY ModuleEntry = nullptr; PIMAGE_NT_HEADERS headers = nullptr; - UNREFERENCED_PARAMETER(BufferSize); + if (BufferSize)return STATUS_INVALID_PARAMETER_5; __try { - //ProbeForRead(BufferAddress, BufferSize); - if (BufferSize)status = STATUS_INVALID_PARAMETER_5; *BaseAddress = nullptr; if (LdrEntry)*LdrEntry = nullptr; + if (!(dwFlags & LOAD_FLAGS_PASS_IMAGE_CHECK) && !RtlIsValidImageBuffer(BufferAddress))status = STATUS_INVALID_IMAGE_FORMAT; } __except (EXCEPTION_EXECUTE_HANDLER) { status = GetExceptionCode(); @@ -697,13 +754,13 @@ NTSTATUS NTAPI NtLoadDllMemoryExW( !wcsnicmp(DllName, CurEntry->BaseDllName.Buffer, CurEntry->BaseDllName.Length / sizeof(wchar_t))) { /* Let's compare their headers */ if (!(h2 = RtlImageNtHeader(CurEntry->DllBase)))continue; - if (!(module = MapMemoryModuleHandle(CurEntry->DllBase)))continue; + if (!(module = MapMemoryModuleHandle((HMEMORYMODULE)CurEntry->DllBase)))continue; if ((h1->OptionalHeader.SizeOfCode == h2->OptionalHeader.SizeOfCode) && (h1->OptionalHeader.SizeOfHeaders == h2->OptionalHeader.SizeOfHeaders)) { /* This is our entry!, update load count and return success */ if (!module->UseReferenceCount || dwFlags & LOAD_FLAGS_NOT_USE_REFERENCE_COUNT)return STATUS_INVALID_PARAMETER_3; NtUpdateReferenceCount(CurEntry, FLAG_REFERENCE); - *BaseAddress = CurEntry->DllBase; + *BaseAddress = (HMEMORYMODULE)CurEntry->DllBase; if (LdrEntry)*LdrEntry = CurEntry; return STATUS_SUCCESS; } @@ -880,14 +937,11 @@ static VOID NTAPI RtlpInsertInvertedFunctionTable(IN PRTL_INVERTED_FUNCTION_TABL PIMAGE_RUNTIME_FUNCTION_ENTRY FunctionTable; ULONG Index; ULONG SizeOfTable = 0; - PIMAGE_NT_HEADERS headers = RtlImageNtHeader(ImageBase); - PIMAGE_DATA_DIRECTORY dir = &headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXCEPTION]; - bool need = RtlIsWindowsVersionOrGreater(6, 2, 0); + bool IsWin8OrGreater = RtlIsWindowsVersionOrGreater(6, 2, 0); - Index = (ULONG)need; + Index = (ULONG)IsWin8OrGreater; CurrentSize = InvertedTable->Count; if (CurrentSize != InvertedTable->MaxCount) { - //if (need)_InterlockedIncrement(&InvertedTable->Epoch); if (CurrentSize != 0) { while (Index < CurrentSize) { if (ImageBase < InvertedTable->Entries[Index].ImageBase)break; @@ -901,21 +955,15 @@ static VOID NTAPI RtlpInsertInvertedFunctionTable(IN PRTL_INVERTED_FUNCTION_TABL } } - FunctionTable = (decltype(FunctionTable))((size_t)ImageBase + dir->VirtualAddress); - if (FunctionTable != RtlImageDirectoryEntryToData(ImageBase, TRUE, IMAGE_DIRECTORY_ENTRY_EXCEPTION, &SizeOfTable) || SizeOfTable != dir->Size) { - __fastfail(STATUS_BAD_DATA); - } - //SizeOfTable = dir->Size; - + FunctionTable = (decltype(FunctionTable))RtlImageDirectoryEntryToData(ImageBase, TRUE, IMAGE_DIRECTORY_ENTRY_EXCEPTION, &SizeOfTable); InvertedTable->Entries[Index].ExceptionDirectory = FunctionTable; InvertedTable->Entries[Index].ImageBase = ImageBase; InvertedTable->Entries[Index].ImageSize = SizeOfImage; InvertedTable->Entries[Index].ExceptionDirectorySize = SizeOfTable; InvertedTable->Count++; - //if (need)_InterlockedIncrement(&InvertedTable->Epoch); } else { - need ? (InvertedTable->Overflow = TRUE) : (InvertedTable->Epoch = TRUE); + IsWin8OrGreater ? (InvertedTable->Overflow = TRUE) : (InvertedTable->Epoch = TRUE); } #else @@ -1007,16 +1055,12 @@ static VOID NTAPI RtlpRemoveInvertedFunctionTable(IN PRTL_INVERTED_FUNCTION_TABL } if (InvertedTable->Count != InvertedTable->MaxCount) { -#ifdef _WIN64 - //InvertedTable->Overflow = FALSE; -#else if (IsWin8OrGreater) { - InvertedTable->NextEntrySEHandlerTableEncoded = FALSE; + PRTL_INVERTED_FUNCTION_TABLE_64(InvertedTable)->Overflow = FALSE; } else { - InvertedTable->Overflow = FALSE; + PRTL_INVERTED_FUNCTION_TABLE_WIN7_32(InvertedTable)->Overflow = FALSE; } -#endif } return; @@ -1107,7 +1151,7 @@ static __forceinline bool NTAPI RtlIsModuleUnloaded(PLDR_DATA_TABLE_ENTRY entry) } else { return entry->DllBase == nullptr; - } + } } static PVOID FindLdrpInvertedFunctionTable32() { // _RTL_INVERTED_FUNCTION_TABLE x86 @@ -1133,14 +1177,14 @@ static PVOID FindLdrpInvertedFunctionTable32() { DWORD SEHTable, SEHCount; BYTE Offset = 0x20; //sizeof(_RTL_INVERTED_FUNCTION_TABLE_ENTRY)*2 - if (RtlIsWindowsVersionOrGreater(10, 0, 0)) lpSectionName = ".mrdata"; + if (RtlIsWindowsVersionOrGreater(6, 3, 0)) lpSectionName = ".mrdata"; else if (!RtlIsWindowsVersionOrGreater(6, 2, 0)) Offset = 0xC; while (ListEntry != ListHead) { CurEntry = CONTAINING_RECORD(ListEntry, LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks); ListEntry = ListEntry->Flink; if (RtlIsModuleUnloaded(CurEntry))continue; //skip unloaded module - if (IsValidMemoryModuleHandle(CurEntry->DllBase))continue; //skip our memory module. + if (IsValidMemoryModuleHandle((HMEMORYMODULE)CurEntry->DllBase))continue; //skip our memory module. if (CurEntry->DllBase == hNtdll && Offset == 0x20)continue; //Win10 skip first entry, if the base of ntdll is smallest. hModule = (HMODULE)(hModule ? min(hModule, CurEntry->DllBase) : CurEntry->DllBase); } @@ -1200,7 +1244,7 @@ static PVOID FindLdrpInvertedFunctionTable64() { CurEntry = CONTAINING_RECORD(ListEntry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks); ListEntry = ListEntry->Flink; //Make sure the smallest base address is not our memory module - if (IsValidMemoryModuleHandle(CurEntry->DllBase))continue; + if (IsValidMemoryModuleHandle((HMEMORYMODULE)CurEntry->DllBase))continue; hModule = (HMODULE)(hModule ? min(hModule, CurEntry->DllBase) : CurEntry->DllBase); } ModuleHeaders = RtlImageNtHeader(hModule); @@ -1255,7 +1299,7 @@ static NTSTATUS NTAPI RtlProtectMrdata(IN SIZE_T Protect) { NTSTATUS NTAPI RtlInsertInvertedFunctionTable(IN PVOID BaseAddress, IN size_t ImageSize) { static auto table = PRTL_INVERTED_FUNCTION_TABLE(RtlFindLdrpInvertedFunctionTable()); if (!table)return STATUS_NOT_SUPPORTED; - bool need_virtual_protect = RtlIsWindowsVersionOrGreater(8, 3, 0); + bool need_virtual_protect = RtlIsWindowsVersionOrGreater(6, 3, 0); NTSTATUS status; if (need_virtual_protect) { @@ -1267,17 +1311,12 @@ NTSTATUS NTAPI RtlInsertInvertedFunctionTable(IN PVOID BaseAddress, IN size_t Im status = RtlProtectMrdata(PAGE_READONLY); if (!NT_SUCCESS(status))return status; } - -#ifdef _WIN64 - if (RtlIsWindowsVersionOrGreater(6, 2, 0)) return table->Overflow ? STATUS_INVALID_ADDRESS : STATUS_SUCCESS; - else return table->Epoch ? STATUS_INVALID_ADDRESS : STATUS_SUCCESS; -#else - return (need_virtual_protect ? table->NextEntrySEHandlerTableEncoded : table->Overflow) ? STATUS_INVALID_ADDRESS : STATUS_SUCCESS; -#endif + return (RtlIsWindowsVersionOrGreater(6, 2, 0) ? PRTL_INVERTED_FUNCTION_TABLE_64(table)->Overflow : PRTL_INVERTED_FUNCTION_TABLE_WIN7_32(table)->Overflow) ? + STATUS_NO_MEMORY : STATUS_SUCCESS; } NTSTATUS NTAPI RtlRemoveInvertedFunctionTable(IN PVOID ImageBase) { static auto table = PRTL_INVERTED_FUNCTION_TABLE(RtlFindLdrpInvertedFunctionTable()); - bool need_virtual_protect = RtlIsWindowsVersionOrGreater(10, 0, 0); + bool need_virtual_protect = RtlIsWindowsVersionOrGreater(6, 3, 0); NTSTATUS status; if (need_virtual_protect) { @@ -1297,10 +1336,18 @@ static NTSTATUS NTAPI LdrpHandleTlsDataXp(PLDR_DATA_TABLE_ENTRY LdrEntry) { return STATUS_NOT_SUPPORTED; } static NTSTATUS NTAPI RtlFindLdrpHandleTlsData(PVOID* _LdrpHandleTlsData, bool* stdcall) { + static PVOID _LdrpHandleTlsData_ = (PVOID)~0; NTSTATUS status = STATUS_SUCCESS; + __try { - *_LdrpHandleTlsData = nullptr; - *stdcall = false; + if (_LdrpHandleTlsData_ != (PVOID)~0) { + *_LdrpHandleTlsData = _LdrpHandleTlsData_; + if (_LdrpHandleTlsData_ == nullptr)status = STATUS_NOT_SUPPORTED; + } + else { + *_LdrpHandleTlsData = _LdrpHandleTlsData_ = nullptr; + *stdcall = false; + } } __except (EXCEPTION_EXECUTE_HANDLER) { status = GetExceptionCode(); @@ -1420,7 +1467,7 @@ static NTSTATUS NTAPI RtlFindLdrpHandleTlsData(PVOID* _LdrpHandleTlsData, bool* SEARCH_CONTEXT SearchContext{ SearchContext.MemoryBuffer = const_cast(Feature),SearchContext.BufferLength = Size - 1 }; if (NT_SUCCESS(RtlFindMemoryBlockFromModuleSection(GetModuleHandleW(L"ntdll.dll"), ".text", &SearchContext))) SearchContext.OutBufferPtr -= OffsetOfFunctionBegin; - if (!(*_LdrpHandleTlsData = SearchContext.MemoryBlockInSection))return STATUS_NOT_SUPPORTED; + if (!(*_LdrpHandleTlsData = _LdrpHandleTlsData_ = SearchContext.MemoryBlockInSection))return STATUS_NOT_SUPPORTED; *stdcall = !RtlIsWindowsVersionOrGreater(6, 3, 0); return status; } @@ -1493,7 +1540,7 @@ NTSTATUS NTAPI NtQuerySystemMemoryModuleFeatures(OUT PDWORD pFeatures) { } if (RtlFindLdrpModuleBaseAddressIndex())features |= MEMORY_FEATURE_MODULE_BASEADDRESS_INDEX; - if (RtlFindtLdrpHeap())features |= MEMORY_FEATURE_LDRP_HEAP; + if (RtlFindLdrpHeap())features |= MEMORY_FEATURE_LDRP_HEAP; if (RtlFindLdrpHashTable())features |= MEMORY_FEATURE_LDRP_HASH_TABLE; if (RtlFindLdrpInvertedFunctionTable())features |= MEMORY_FEATURE_INVERTED_FUNCTION_TABLE; if (NT_SUCCESS(RtlFindLdrpHandleTlsData(&pfn, &value)) && pfn)features |= MEMORY_FEATURE_LDRP_HANDLE_TLS_DATA; diff --git a/MemoryModule/NativeFunctionsInternal.h b/MemoryModule/NativeFunctionsInternal.h index bc6a8e1..1ce1732 100644 --- a/MemoryModule/NativeFunctionsInternal.h +++ b/MemoryModule/NativeFunctionsInternal.h @@ -421,6 +421,9 @@ NTSTATUS NTAPI NtLoadDllMemory( //If this flag is specified, this routine will not fail even if the call to LdrpTlsData fails. #define LOAD_FLAGS_NOT_FAIL_IF_HANDLE_TLS 0x20000000 +//If this flag is specified, the input image buffer will not be checked before loading. +#define LOAD_FLAGS_PASS_IMAGE_CHECK 0x40000000 + //If this flag is specified, exception handling will not be supported. #define LOAD_FLAGS_NOT_ADD_INVERTED_FUNCTION 0x00000001 diff --git a/README.md b/README.md index 4ba59bf..ecf9b7a 100644 --- a/README.md +++ b/README.md @@ -6,25 +6,18 @@ MemoryModulePP, used to load a DLL from memory. MemoryModulePP is compatible wit **MemoryModulePP is developed based on [MemoryModule][ref1].** -**This repository is under development.** - - > In order to support 32-bit dll exception handling, the dll should enable the /SAFESEH linker option, > otherwise the exception handler cannot pass the RtlIsValidHandler () check when an exception occurs -## New Features - - Support Win8 - ## Features - - Compatible with Win32 API (GetModuleHandleA/W/Ex GetModuleFileNameA/W/Ex GetProcAddress and any Resource API) + - Compatible with Win32 API (GetModuleHandle, GetModuleFileName, GetProcAddress and any Resource API) - Support for C++ exceptions and SEH - - Compatible with Win7 and Win10 - Optimized MEMORYMODULE structure - Use reference counting, repeated loading of the same module will update the reference counting, please refer to NtLoadDllMemoryExW - The above features can be turned off through the dwFlags parameter of NtLoadDllMemoryExW - Support for TLS(Thread Local Storage) - DllMain can receive four types of notifications - - Support Win10 forward export + - Support forward export ## Tech @@ -34,13 +27,11 @@ MemoryModulePP uses many open source projects and references to work properly: * [MemoryModule][ref1] - Load dll from memory, reference and improve part of this repository's code. * [Blackbone][ref2] - Windows memory hacking library, Referenced the idea of exception handling. * [Exceptions on Windows x64][ref3] - How Windows x64 Exception Handling Works. (Russian) -* [Reactos][ref4] - How WIndows loads dll. +* [Reactos][ref4] - How Windows loads dll. ## Todos + - Looking for a good way to locate the LdrpHandleTlsData function, or implement this function. - - Compatible with Win8 and x86 architecture - - Improve MEMORYPODULE structure - - Improve NtLoadDllMemoryExW function [ref0]: @@ -48,4 +39,5 @@ MemoryModulePP uses many open source projects and references to work properly: [ref2]: [ref3]: [ref4]: + [ref5]: diff --git a/a/dllmain.cpp b/a/dllmain.cpp index 3a21854..1a27854 100644 --- a/a/dllmain.cpp +++ b/a/dllmain.cpp @@ -82,7 +82,7 @@ int __test__() { static thread_local int x = 0xffccffdd; DWORD WINAPI Thread(PVOID) { printf("[1] ThreadLocalStoragePointer = %p\n", NtCurrentTeb()->ThreadLocalStoragePointer); - return x == 0xffccffdd ? 0 : 1; const auto i = offsetof(CONTEXT, Dr0); + return x == 0xffccffdd ? 0 : 1; } int thread() { diff --git a/test/test.cpp b/test/test.cpp index 8866f26..5e5e217 100644 --- a/test/test.cpp +++ b/test/test.cpp @@ -1,16 +1,11 @@ -//#include "../MemoryModule/NativeFunctionsInternal.h" #include "../MemoryModule/LoadDllMemoryApi.h" -#ifndef NT_SUCCESS -#define NT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0) -#endif #include #pragma warning(disable:4996) -int main() { - //return ((int(*)(int))GetProcAddress(LoadLibraryW(L"a.dll"), "exception"))(0); +static PVOID ReadDllFile(LPCSTR FileName) { LPVOID buffer; size_t size; - FILE* f = fopen("a.dll", "rb"); + FILE* f = fopen(FileName, "rb"); if (!f)return 0; _fseeki64(f, 0, SEEK_END); if (!(size = _ftelli64(f))) { @@ -20,6 +15,11 @@ int main() { _fseeki64(f, 0, SEEK_SET); fread(buffer = new char[size], 1, size, f); fclose(f); + return buffer; +} + +int test_default() { + LPVOID buffer = ReadDllFile("a.dll"); HMEMORYMODULE m1 = nullptr, m2 = m1; HMODULE hModule = nullptr; @@ -93,73 +93,76 @@ int main() { end: delete[]buffer; if (m1)NtUnloadDllMemory(m1); + FreeLibrary(LoadLibraryW(L"wininet.dll")); FreeLibrary(GetModuleHandleW(L"wininet.dll")); if (m2)NtUnloadDllMemory(m2); return 0; } +#define WSADESCRIPTION_LEN 256 +#define WSASYS_STATUS_LEN 128 +typedef USHORT ADDRESS_FAMILY; +typedef int (PASCAL* WSAStartup_t)(WORD wVersionRequired, LPWSADATA lpWSAData); +typedef int (PASCAL* WSACleanup_t)(void); +typedef SOCKET (PASCAL* socket_t)(int af, int type, int protocol); +typedef int (PASCAL* closesocket_t)(SOCKET s); +typedef int (PASCAL* connect_t)(SOCKET s, const struct sockaddr FAR* name, int namelen); +typedef unsigned long (PASCAL* inet_addr_t)(const char FAR* cp); +typedef u_short (PASCAL* htons_t)(u_short hostshort); -//#include -//#include "../MemoryModule/NativeFunctionsInternal.h" -// -//bool c; -//static thread_local int x = -1; -// -//DWORD WINAPI Thread(PVOID) { -// printf("[1] x = %d\n", x); -// x = 0; -// c = true; -// while (c)Sleep(100); -// return x; -//} -// -//int main() { -// x = 1; -// c = false; -// HANDLE hThread = CreateThread(nullptr, 0, Thread, nullptr, 0, nullptr); -// DWORD ex = 0; -// if (hThread) { -// while (!c)Sleep(100); -// printf("[0] x = %d\n", x); -// c = false; -// WaitForSingleObject(hThread, 0xffffffff); -// GetExitCodeThread(hThread, &ex); -// CloseHandle(hThread); -// printf("[0] Exit = %d\n", ex); -// } -// -// PLIST_ENTRY entry = &NtCurrentPeb()->Ldr->InLoadOrderModuleList; -// PLDR_DATA_TABLE_ENTRY_WIN7 data = nullptr; -// -// while (entry != entry->Flink) { -// entry = entry->Flink; -// data = CONTAINING_RECORD(entry, LDR_DATA_TABLE_ENTRY_WIN7, InLoadOrderLinks); -// } -// -// return 0; -//} +int test_ws2_32() { + PVOID buffer = ReadDllFile("C:\\Windows\\system32\\ws2_32.dll"); -//#include "../MemoryModule/Native.h" -//#include -// -//static thread_local int x = 0xffccffdd; -// -//DWORD WINAPI Thread(PVOID) { -// printf("[1] ThreadLocalStoragePointer = %p\n", NtCurrentTeb()->ThreadLocalStoragePointer); -// return x == 0xffccffdd ? 0 : 1; -//} -// -//int main() { -// x = 2; -// printf("[0] ThreadLocalStoragePointer = %p\n", NtCurrentTeb()->ThreadLocalStoragePointer); -// HANDLE hThread = CreateThread(nullptr, 0, Thread, nullptr, 0, nullptr); -// DWORD ret = -1; -// if (hThread) { -// WaitForSingleObject(hThread, 0xffffffff); -// GetExitCodeThread(hThread, &ret); -// CloseHandle(hThread); -// return ret; -// } -// return -1; -//} + HMEMORYMODULE hMemoryModule = nullptr; + HMODULE hModule = nullptr; + NTSTATUS status; + + WSAData data{}; + SOCKET sock = INVALID_SOCKET; + sockaddr_in addr{}; + WSAStartup_t _WSAStartup = nullptr; + WSACleanup_t _WSACleanup = nullptr; + socket_t _socket = nullptr; + closesocket_t _closesocket = nullptr; + connect_t _connect = nullptr; + inet_addr_t _inet_addr = nullptr; + htons_t _htons = nullptr; + + hMemoryModule = LoadLibraryMemoryExW(buffer, 0, L"ws2.dll", nullptr, LOAD_FLAGS_NOT_FAIL_IF_HANDLE_TLS); + hModule = MemoryModuleToModule(hMemoryModule); + if (buffer)delete[]buffer; + if (!hModule)return 0; + + _WSAStartup = (decltype(_WSAStartup)(GetProcAddress(hModule, "WSAStartup"))); + _WSACleanup = (decltype(_WSACleanup)(GetProcAddress(hModule, "WSACleanup"))); + _socket = (decltype(_socket)(GetProcAddress(hModule, "socket"))); + _closesocket = (decltype(_closesocket)(GetProcAddress(hModule, "closesocket"))); + _connect = (decltype(_connect)(GetProcAddress(hModule, "connect"))); + _inet_addr = (decltype(_inet_addr)(GetProcAddress(hModule, "inet_addr"))); + _htons = (decltype(_htons)(GetProcAddress(hModule, "htons"))); + if (!_WSAStartup || !_WSACleanup || !_socket || !_closesocket || !_connect || !_inet_addr || !_htons)goto end; + + if (_WSAStartup(MAKEWORD(2, 2), &data) != 0)goto end; + if ((sock = _socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET)goto end; + addr.sin_family = AF_INET; + addr.sin_port = _htons(80); + addr.sin_addr.S_un.S_addr = _inet_addr("1.1.1.1"); + if (_connect(sock, (sockaddr*)&addr, sizeof(addr)) == SOCKET_ERROR)goto end; + + //success + printf("ws2_32 completed successfully.\n"); + +end: + if (sock != INVALID_SOCKET && _closesocket)_closesocket(sock); + if (_WSACleanup)_WSACleanup(); + FreeLibraryMemory(hMemoryModule); + return 0; +} + +int main() { + test_default(); + test_ws2_32(); + + return 0; +}