diff --git a/MemoryModule/MemoryModule.cpp b/MemoryModule/MemoryModule.cpp index 4ac8326..6676887 100644 --- a/MemoryModule/MemoryModule.cpp +++ b/MemoryModule/MemoryModule.cpp @@ -18,14 +18,6 @@ #define GET_HEADER_DICTIONARY(headers, idx) &headers->OptionalHeader.DataDirectory[idx] -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 != (ULONG64)pModule->codeBase)return nullptr; - return headers; -} - PMEMORYMODULE WINAPI MapMemoryModuleHandle(HMEMORYMODULE hModule) { __try { PIMAGE_DOS_HEADER dos = (PIMAGE_DOS_HEADER)hModule; @@ -46,50 +38,10 @@ bool WINAPI IsValidMemoryModuleHandle(HMEMORYMODULE hModule) { return MapMemoryModuleHandle(hModule) != nullptr; } -static inline uintptr_t AlignValueDown(uintptr_t value, uintptr_t alignment) { - return value & ~(alignment - 1); -} +#define AlignValueUp(value, alignment) ((size_t(value) + size_t(alignment) + 1) & ~(size_t(alignment) - 1)) -static inline LPVOID AlignAddressDown(LPVOID address, uintptr_t alignment) { - return (LPVOID)AlignValueDown((uintptr_t)address, alignment); -} +#define OffsetPointer(data, offset) LPVOID(LPBYTE(data) + ptrdiff_t(offset)) -static inline size_t AlignValueUp(size_t value, size_t alignment) { - return (value + alignment - 1) & ~(alignment - 1); -} - -static inline void* OffsetPointer(void* data, ptrdiff_t offset) { - return (void*)((uintptr_t)data + offset); -} - -static inline void OutputLastError(const char* msg) { -#ifndef DEBUG_OUTPUT - UNREFERENCED_PARAMETER(msg); -#else - LPVOID tmp; - char* tmpmsg; - FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, - nullptr, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&tmp, 0, nullptr); - tmpmsg = (char*)LocalAlloc(LPTR, strlen(msg) + strlen(tmp) + 3); - sprintf(tmpmsg, "%s: %s", msg, tmp); - OutputDebugString(tmpmsg); - LocalFree(tmpmsg); - LocalFree(tmp); -#endif -} - -#ifdef _WIN64 -static void FreePointerList(POINTER_LIST* head) { - POINTER_LIST* node = head; - while (node) { - POINTER_LIST* next; - VirtualFree(node->address, 0, MEM_RELEASE); - next = node->next; - delete node; - node = next; - } -} -#endif // Protection flags for memory pages (Executable, Readable, Writeable) static int ProtectionFlags[2][2][2] = { @@ -104,388 +56,325 @@ static int ProtectionFlags[2][2][2] = { }, }; -static BOOL CopySections(const unsigned char* data, PMEMORYMODULE module) { - LPVOID dest; - PIMAGE_NT_HEADERS headers = GetImageNtHeaders(module); - PIMAGE_SECTION_HEADER section = headers ? IMAGE_FIRST_SECTION(headers) : nullptr; - size_t alloc_size = 0; - bool cp = false; +static SYSTEM_INFO sysInfo = []()->SYSTEM_INFO { + SYSTEM_INFO tmp; + GetNativeSystemInfo(&tmp); + return tmp; +}(); - 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); - } - __except (EXCEPTION_EXECUTE_HANDLER) { - SetLastError(ERROR_BAD_EXE_FORMAT); - return FALSE; - } - alloc_size = section->SizeOfRawData; - cp = true; - } - if (alloc_size) { - 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); - RtlZeroMemory(dest, alloc_size); - if (cp) { - //section->VirtualAddress += module->headers_align; - RtlCopyMemory(dest, data + section->PointerToRawData, section->SizeOfRawData); - } - } - } - return TRUE; -} +NTSTATUS MemoryLoadLibrary( + _Out_ HMEMORYMODULE* MemoryModuleHandle, + _In_ LPCVOID data) { -static SIZE_T GetRealSectionSize(PMEMORYMODULE module, PIMAGE_SECTION_HEADER section) { - DWORD size = section->SizeOfRawData; - PIMAGE_NT_HEADERS headers = GetImageNtHeaders(module); - if (size == 0) { - if (section->Characteristics & IMAGE_SCN_CNT_INITIALIZED_DATA) { - size = headers->OptionalHeader.SizeOfInitializedData; - } - else if (section->Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA) { - size = headers->OptionalHeader.SizeOfUninitializedData; - } - } - return (SIZE_T)size; -} + PIMAGE_DOS_HEADER dos_header = nullptr; + PIMAGE_NT_HEADERS old_header = nullptr; + NTSTATUS status = STATUS_SUCCESS; -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 || 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) - 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) { - PIMAGE_NT_HEADERS headers = GetImageNtHeaders(module); - PIMAGE_SECTION_HEADER section = IMAGE_FIRST_SECTION(headers); -#ifdef _WIN64 - uintptr_t imageOffset = ((uintptr_t)headers->OptionalHeader.ImageBase & 0xffffffff00000000); -#else - static const uintptr_t imageOffset = 0; -#endif - SECTIONFINALIZEDATA sectionData; - sectionData.address = (LPVOID)((uintptr_t)section->Misc.PhysicalAddress | imageOffset); - sectionData.alignedAddress = AlignAddressDown(sectionData.address, module->pageSize); - sectionData.size = GetRealSectionSize(module, section); - sectionData.characteristics = section->Characteristics; - sectionData.last = FALSE; - section++; - - 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) == 0 || (sectionData.characteristics & IMAGE_SCN_MEM_DISCARDABLE) == 0) { - sectionData.characteristics = (sectionData.characteristics | section->Characteristics) & ~IMAGE_SCN_MEM_DISCARDABLE; - } - else { - sectionData.characteristics |= section->Characteristics; - } - sectionData.size = (((uintptr_t)sectionAddress) + ((uintptr_t)sectionSize)) - (uintptr_t)sectionData.address; - continue; - } - if (!FinalizeSection(module, §ionData)) return FALSE; - sectionData.address = sectionAddress; - sectionData.alignedAddress = alignedAddress; - sectionData.size = sectionSize; - sectionData.characteristics = section->Characteristics; - } - sectionData.last = TRUE; - return FinalizeSection(module, §ionData); -} - -typedef struct _REBASE_INFO { - USHORT Offset : 12; - USHORT Type : 4; -}REBASE_INFO, * PREBASE_INFO; -typedef struct _IMAGE_BASE_RELOCATION_HEADER { - DWORD VirtualAddress; - DWORD SizeOfBlock; - REBASE_INFO TypeOffset[ANYSIZE_ARRAY]; - - DWORD TypeOffsetCount()const { - return (this->SizeOfBlock - 8) / sizeof(_REBASE_INFO); - } -}IMAGE_BASE_RELOCATION_HEADER, * PIMAGE_BASE_RELOCATION_HEADER; -static BOOL PerformBaseRelocation(PMEMORYMODULE module, ptrdiff_t delta) { - unsigned char* codeBase = module->codeBase; - auto directory = GET_HEADER_DICTIONARY(GetImageNtHeaders(module), IMAGE_DIRECTORY_ENTRY_BASERELOC); - auto relocation = (PIMAGE_BASE_RELOCATION_HEADER)(codeBase + directory->VirtualAddress); - if (!directory->Size) return (delta == 0); - while (relocation->VirtualAddress > 0) { - auto relInfo = (_REBASE_INFO*)&relocation->TypeOffset; - for (DWORD i = 0; i < relocation->TypeOffsetCount(); ++i, ++relInfo) { - switch (relInfo->Type) { - case IMAGE_REL_BASED_HIGHLOW: *(DWORD*)(codeBase + relocation->VirtualAddress + relInfo->Offset) += (DWORD)delta; break; -#ifdef _WIN64 - case IMAGE_REL_BASED_DIR64: *(ULONGLONG*)(codeBase + relocation->VirtualAddress + relInfo->Offset) += (ULONGLONG)delta; break; -#endif - case IMAGE_REL_BASED_ABSOLUTE: - default: break; - } - } - // advance to next relocation block - //relocation->VirtualAddress += module->headers_align; - relocation = decltype(relocation)(OffsetPointer(relocation, relocation->SizeOfBlock)); - } - return TRUE; -} - -static BOOL GetImportAddressTableEntryCountAndVerify(PMEMORYMODULE module, LPDWORD Count, PIMAGE_IMPORT_DESCRIPTOR* IAT) { + // + // Check parameters + // __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; - DWORD count; - if (!GetImportAddressTableEntryCountAndVerify(module, &count, &importDesc)) { - SetLastError(ERROR_BAD_EXE_FORMAT); - return FALSE; - } - 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); - 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; - } - } - } - __except (EXCEPTION_EXECUTE_HANDLER) { - SetLastError(RtlNtStatusToDosError(GetExceptionCode())); - return FALSE; - } - return TRUE; -} -HMEMORYMODULE MemoryLoadLibrary(const void* data) { - PMEMORYMODULE hMemoryModule = nullptr; - PIMAGE_DOS_HEADER dos_header, new_dos_header; - PIMAGE_NT_HEADERS old_header, new_header; - unsigned char* base; - ptrdiff_t locationDelta; - static SYSTEM_INFO sysInfo{}; - PIMAGE_SECTION_HEADER section; - size_t optionalSectionSize; - size_t lastSectionEnd = 0; - size_t alignedImageSize; - DWORD headers_align; -#ifdef _WIN64 - POINTER_LIST* blockedMemory = nullptr; -#endif + *MemoryModuleHandle = nullptr; - __try { - ProbeForRead(data, sizeof(IMAGE_DOS_HEADER)); + // + // Check dos magic + // dos_header = (PIMAGE_DOS_HEADER)data; if (dos_header->e_magic != IMAGE_DOS_SIGNATURE) { - SetLastError(ERROR_BAD_EXE_FORMAT); - return nullptr; + status = STATUS_INVALID_IMAGE_FORMAT; + __leave; } - ProbeForRead(data, dos_header->e_lfanew + sizeof(IMAGE_NT_HEADERS)); + + // + // Check nt headers + // old_header = (PIMAGE_NT_HEADERS)((size_t)data + dos_header->e_lfanew); if (old_header->Signature != IMAGE_NT_SIGNATURE || - !ProbeForRead(data, old_header->OptionalHeader.SizeOfHeaders) || old_header->FileHeader.Machine != HOST_MACHINE || old_header->OptionalHeader.SectionAlignment & 1) { - SetLastError(ERROR_BAD_EXE_FORMAT); - return nullptr; + status = STATUS_INVALID_IMAGE_FORMAT; + __leave; } - //only dll image support + + // + // Only dll image support + // if (!(old_header->FileHeader.Characteristics & IMAGE_FILE_DLL)) { - SetLastError(ERROR_NOT_SUPPORTED); - return nullptr; + status = STATUS_NOT_SUPPORTED; + __leave; } } __except (EXCEPTION_EXECUTE_HANDLER) { - SetLastError(ERROR_INVALID_DATA); - return nullptr; + status = GetExceptionCode(); } - - section = IMAGE_FIRST_SECTION(old_header); - optionalSectionSize = old_header->OptionalHeader.SectionAlignment; - for (DWORD i = 0; i < old_header->FileHeader.NumberOfSections; i++, section++) { - size_t endOfSection; - if (section->SizeOfRawData == 0) { - // Section without data in the DLL - endOfSection = section->VirtualAddress + optionalSectionSize; - } - else { - endOfSection = static_cast(section->VirtualAddress) + section->SizeOfRawData; + if (!NT_SUCCESS(status)) return status; + + // + // Reserve the address range of image + // + LPBYTE base = (LPBYTE)VirtualAlloc( + LPVOID(old_header->OptionalHeader.ImageBase), + old_header->OptionalHeader.SizeOfImage, + MEM_RESERVE, + PAGE_READWRITE + ); + if (!base) { + if (old_header->OptionalHeader.DllCharacteristics & IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE) { + + base = (LPBYTE)VirtualAlloc( + nullptr, + old_header->OptionalHeader.SizeOfImage, + MEM_RESERVE, + PAGE_READWRITE + ); + if (!base) status = STATUS_NO_MEMORY; } - if (endOfSection > lastSectionEnd) { - lastSectionEnd = endOfSection; + if (!NT_SUCCESS(status)) { + return status; } } - if (!sysInfo.dwPageSize)GetNativeSystemInfo(&sysInfo); - alignedImageSize = AlignValueUp(old_header->OptionalHeader.SizeOfImage, sysInfo.dwPageSize); - if (alignedImageSize != AlignValueUp(lastSectionEnd, sysInfo.dwPageSize)) { - SetLastError(ERROR_BAD_EXE_FORMAT); - return nullptr; - } - 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? - // calling DllEntry raises an exception if we don't... - if (!(base = (LPBYTE)VirtualAlloc((LPVOID)(old_header->OptionalHeader.ImageBase), alignedImageSize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE))) { - if (!(old_header->OptionalHeader.DllCharacteristics & IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE)) { - SetLastError(ERROR_BAD_EXE_FORMAT); - return nullptr; - } - if (!(base = (LPBYTE)VirtualAlloc(nullptr, alignedImageSize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE))) { - SetLastError(ERROR_OUTOFMEMORY); - return nullptr; - } + // + // Allocate memory for image headers + // + size_t alignedHeadersSize = (DWORD)AlignValueUp(old_header->OptionalHeader.SizeOfHeaders + sizeof(MEMORYMODULE), sysInfo.dwPageSize); + if (!VirtualAlloc(base, alignedHeadersSize, MEM_COMMIT, PAGE_READWRITE)) { + VirtualFree(base, 0, MEM_RELEASE); + status = STATUS_NO_MEMORY; + return status; } -#ifdef _WIN64 - // Memory block may not span 4 GB boundaries. - while ((((uintptr_t)base) >> 32) < (((uintptr_t)(base + alignedImageSize)) >> 32)) { - POINTER_LIST* node = new POINTER_LIST; - if (!node) { - VirtualFree(base, 0, MEM_RELEASE); - FreePointerList(blockedMemory); - SetLastError(ERROR_OUTOFMEMORY); - return nullptr; - } + // + // Copy headers + // + PIMAGE_DOS_HEADER new_dos_header = (PIMAGE_DOS_HEADER)base; + PIMAGE_NT_HEADERS new_header = (PIMAGE_NT_HEADERS)(base + dos_header->e_lfanew); + RtlCopyMemory( + new_dos_header, + dos_header, + old_header->OptionalHeader.SizeOfHeaders + ); + new_header->OptionalHeader.ImageBase = (size_t)base; - node->next = blockedMemory; - node->address = base; - blockedMemory = node; - - if (!(base = (LPBYTE)VirtualAlloc(nullptr, alignedImageSize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE))) { - FreePointerList(blockedMemory); - SetLastError(ERROR_OUTOFMEMORY); - return nullptr; - } - } -#endif - - new_dos_header = (PIMAGE_DOS_HEADER)base; - new_header = (PIMAGE_NT_HEADERS)(base + dos_header->e_lfanew); - hMemoryModule = (PMEMORYMODULE)(base + old_header->OptionalHeader.SizeOfHeaders); + // + // Setup MemoryModule structure. + // + PMEMORYMODULE hMemoryModule = (PMEMORYMODULE)(base + old_header->OptionalHeader.SizeOfHeaders); RtlZeroMemory(hMemoryModule, sizeof(MEMORYMODULE)); hMemoryModule->codeBase = base; hMemoryModule->pageSize = sysInfo.dwPageSize; hMemoryModule->Signature = MEMORY_MODULE_SIGNATURE; hMemoryModule->SizeofHeaders = old_header->OptionalHeader.SizeOfHeaders; - hMemoryModule->headers_align = headers_align; + + do { + // + // Allocate and copy sections + // + PIMAGE_SECTION_HEADER section = IMAGE_FIRST_SECTION(new_header); + for (DWORD i = 0; i < new_header->FileHeader.NumberOfSections; ++i, ++section) { + + DWORD size = AlignValueUp( + section->Misc.VirtualSize, + new_header->OptionalHeader.SectionAlignment + ); + if (size < section->SizeOfRawData) { + status = STATUS_INVALID_IMAGE_FORMAT; + break; + } + + LPVOID dest = VirtualAlloc( + (LPSTR)new_header->OptionalHeader.ImageBase + section->VirtualAddress, + size, + MEM_COMMIT, + PAGE_READWRITE + ); + if (!dest) { + status = STATUS_NO_MEMORY; + break; + } + + if (section->SizeOfRawData) { + RtlCopyMemory( + dest, + LPBYTE(data) + section->PointerToRawData, + section->SizeOfRawData + ); + } + + } + if (!NT_SUCCESS(status))break; + + // + // Rebase image + // + auto locationDelta = new_header->OptionalHeader.ImageBase - old_header->OptionalHeader.ImageBase; + if (locationDelta) { + typedef struct _REBASE_INFO { + USHORT Offset : 12; + USHORT Type : 4; + }REBASE_INFO, * PREBASE_INFO; + typedef struct _IMAGE_BASE_RELOCATION_HEADER { + DWORD VirtualAddress; + DWORD SizeOfBlock; + REBASE_INFO TypeOffset[ANYSIZE_ARRAY]; + + DWORD TypeOffsetCount()const { + return (this->SizeOfBlock - 8) / sizeof(_REBASE_INFO); + } + }IMAGE_BASE_RELOCATION_HEADER, * PIMAGE_BASE_RELOCATION_HEADER; + + PIMAGE_DATA_DIRECTORY dir = GET_HEADER_DICTIONARY(new_header, IMAGE_DIRECTORY_ENTRY_BASERELOC); + PIMAGE_BASE_RELOCATION_HEADER relocation = (PIMAGE_BASE_RELOCATION_HEADER)(LPBYTE(base) + dir->VirtualAddress); + + if (dir->Size == 0 || dir->VirtualAddress == 0) { + if (!locationDelta) { + status = STATUS_INVALID_IMAGE_FORMAT; + } + } + else { + while (relocation->VirtualAddress > 0) { + auto relInfo = (_REBASE_INFO*)&relocation->TypeOffset; + for (DWORD i = 0; i < relocation->TypeOffsetCount(); ++i, ++relInfo) { + switch (relInfo->Type) { + case IMAGE_REL_BASED_HIGHLOW: *(DWORD*)(base + relocation->VirtualAddress + relInfo->Offset) += (DWORD)locationDelta; break; #ifdef _WIN64 - hMemoryModule->blockedMemory = blockedMemory; + case IMAGE_REL_BASED_DIR64: *(ULONGLONG*)(base + relocation->VirtualAddress + relInfo->Offset) += (ULONGLONG)locationDelta; break; #endif + case IMAGE_REL_BASED_ABSOLUTE: + default: break; + } + } - // copy PE header to code - memcpy(new_dos_header, dos_header, old_header->OptionalHeader.SizeOfHeaders); - new_header->OptionalHeader.SizeOfImage = (DWORD)(alignedImageSize); - new_header->OptionalHeader.ImageBase = (size_t)base; - new_header->OptionalHeader.BaseOfCode = headers_align; + // advance to next relocation block + //relocation->VirtualAddress += module->headers_align; + relocation = decltype(relocation)(OffsetPointer(relocation, relocation->SizeOfBlock)); + } + } - // copy sections from DLL file block to new memory location - if (!CopySections((LPBYTE)data, hMemoryModule)) goto error; + } + if (!NT_SUCCESS(status))break; - // adjust base address of imported data - locationDelta = (ptrdiff_t)(hMemoryModule->codeBase - old_header->OptionalHeader.ImageBase); - if (locationDelta && !PerformBaseRelocation(hMemoryModule, locationDelta))goto error; + // + // Build import table + // + PIMAGE_IMPORT_DESCRIPTOR importDesc = nullptr; + DWORD count = 0; - // load required dlls and adjust function table of imports - if (!BuildImportTable(hMemoryModule)) goto error; + __try { + PIMAGE_DATA_DIRECTORY dir = GET_HEADER_DICTIONARY(new_header, IMAGE_DIRECTORY_ENTRY_IMPORT); + PIMAGE_IMPORT_DESCRIPTOR iat = nullptr; + + status = STATUS_SUCCESS; + + if (dir && dir->Size) { + iat = importDesc = PIMAGE_IMPORT_DESCRIPTOR(new_header->OptionalHeader.ImageBase + dir->VirtualAddress); + } + + if (iat) { + while (iat->Name) { + ++count; + ++iat; + } + } + + if (importDesc && count) { + if (!(hMemoryModule->hModulesList = new HMODULE[count])) { + status = STATUS_NO_MEMORY; + break; + } + + RtlZeroMemory( + hMemoryModule->hModulesList, + sizeof(HMODULE) * count + ); + + for (DWORD i = 0; i < count; ++i, ++importDesc) { + uintptr_t* thunkRef; + FARPROC* funcRef; + HMODULE handle = LoadLibraryA((LPCSTR)(base + importDesc->Name)); + + if (!handle) { + status = STATUS_DLL_NOT_FOUND; + break; + } + + hMemoryModule->hModulesList[hMemoryModule->dwModulesCount++] = handle; + thunkRef = (uintptr_t*)(base + (importDesc->OriginalFirstThunk ? importDesc->OriginalFirstThunk : importDesc->FirstThunk)); + funcRef = (FARPROC*)(base + importDesc->FirstThunk); + while (*thunkRef) { + *funcRef = GetProcAddress( + handle, + IMAGE_SNAP_BY_ORDINAL(*thunkRef) ? (LPCSTR)IMAGE_ORDINAL(*thunkRef) : (LPCSTR)PIMAGE_IMPORT_BY_NAME(base + (*thunkRef))->Name + ); + if (!*funcRef) { + status = STATUS_ENTRYPOINT_NOT_FOUND; + break; + } + ++thunkRef; + ++funcRef; + } + + if (!NT_SUCCESS(status))break; + } + + } + } + __except (EXCEPTION_EXECUTE_HANDLER) { + status = GetExceptionCode(); + } + if (!NT_SUCCESS(status)) { + for (DWORD i = 0; i < hMemoryModule->dwModulesCount; ++i) + FreeLibrary(hMemoryModule->hModulesList[i]); + + delete[]hMemoryModule->hModulesList; + hMemoryModule->hModulesList = nullptr; + hMemoryModule->dwModulesCount = 0; + + break; + } + + // + // Set section memory protect + // + section = IMAGE_FIRST_SECTION(new_header); + for (DWORD i = 0; i < new_header->FileHeader.NumberOfSections; ++i, ++section) { + LPVOID address = LPBYTE(base) + section->VirtualAddress; + SIZE_T size = AlignValueUp(section->Misc.VirtualSize, new_header->OptionalHeader.SectionAlignment); + + if (section->Characteristics & IMAGE_SCN_MEM_DISCARDABLE) { +#pragma warning(disable:6250) + VirtualFree(address, size, MEM_DECOMMIT); +#pragma warning(default:6250) + } + else { + BOOL executable = (section->Characteristics & IMAGE_SCN_MEM_EXECUTE) != 0, + readable = (section->Characteristics & IMAGE_SCN_MEM_READ) != 0, + writeable = (section->Characteristics & IMAGE_SCN_MEM_WRITE) != 0; + DWORD protect = ProtectionFlags[executable][readable][writeable], oldProtect; + + if (section->Characteristics & IMAGE_SCN_MEM_NOT_CACHED) protect |= PAGE_NOCACHE; + + status = NtProtectVirtualMemory(NtCurrentProcess(), &address, &size, protect, &oldProtect); + if (!NT_SUCCESS(status))break; + } + } + if (!NT_SUCCESS(status))break; + + __try { + *MemoryModuleHandle = (HMEMORYMODULE)base; + } + __except (EXCEPTION_EXECUTE_HANDLER) { + status = GetExceptionCode(); + break; + } + + return status; + } while (false); - // mark memory pages depending on section headers and release - // sections that are marked as "discardable" - if (!FinalizeSections(hMemoryModule)) goto error; - - return (HMEMORYMODULE)base; -error: - // cleanup MemoryFreeLibrary((HMEMORYMODULE)base); - return nullptr; + return status; } bool MemoryFreeLibrary(HMEMORYMODULE mod) { @@ -494,7 +383,6 @@ bool MemoryFreeLibrary(HMEMORYMODULE mod) { if (!module) return false; if (module->loadFromNtLoadDllMemory && !module->underUnload)return false; - if (module->nameExportsTable)delete[] module->nameExportsTable; if (module->hModulesList) { for (DWORD i = 0; i < module->dwModulesCount; ++i) { if (module->hModulesList[i]) { @@ -503,337 +391,7 @@ bool MemoryFreeLibrary(HMEMORYMODULE mod) { } delete[] module->hModulesList; } -#ifdef _WIN64 - FreePointerList(module->blockedMemory); -#endif + if (module->codeBase) VirtualFree(mod, 0, MEM_RELEASE); return true; } - - - -/* - Deprecated API -*/ -static int _compare(const void* a, const void* b) { - const struct ExportNameEntry* p1 = (const struct ExportNameEntry*) a; - const struct ExportNameEntry* p2 = (const struct ExportNameEntry*) b; - return strcmp(p1->name, p2->name); -} -static int _find(const void* a, const void* b) { - LPCSTR* name = (LPCSTR*)a; - const struct ExportNameEntry* p = (const struct ExportNameEntry*) b; - return strcmp(*name, p->name); -} -FARPROC MemoryGetProcAddress(HMEMORYMODULE mod, LPCSTR name) { - PMEMORYMODULE module = MapMemoryModuleHandle(mod); - unsigned char* codeBase = module->codeBase; - DWORD idx = 0; - PIMAGE_EXPORT_DIRECTORY exports; - PIMAGE_NT_HEADERS headers = GetImageNtHeaders(module); - 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); - return nullptr; - } - - exports = (PIMAGE_EXPORT_DIRECTORY)(codeBase + directory->VirtualAddress); - if (exports->NumberOfNames == 0 || exports->NumberOfFunctions == 0) { - // DLL doesn't export anything - SetLastError(ERROR_PROC_NOT_FOUND); - return nullptr; - } - - if (HIWORD(name) == 0) { - // load function by ordinal value - if (LOWORD(name) < exports->Base) { - SetLastError(ERROR_PROC_NOT_FOUND); - return nullptr; - } - - idx = LOWORD(name) - exports->Base; - } - else if (!exports->NumberOfNames) { - SetLastError(ERROR_PROC_NOT_FOUND); - return nullptr; - } - else { - const struct ExportNameEntry* found; - - // Lazily build name table and sort it by names - if (!module->nameExportsTable) { - DWORD i; - DWORD* nameRef = (DWORD*)(codeBase + exports->AddressOfNames); - WORD* ordinal = (WORD*)(codeBase + exports->AddressOfNameOrdinals); - ExportNameEntry* entry = new ExportNameEntry[exports->NumberOfNames]; - module->nameExportsTable = entry; - if (!entry) { - SetLastError(ERROR_OUTOFMEMORY); - return nullptr; - } - for (i = 0; i < exports->NumberOfNames; i++, nameRef++, ordinal++, entry++) { - entry->name = (const char*)(codeBase + (*nameRef)); - entry->idx = *ordinal; - } - qsort(module->nameExportsTable, - exports->NumberOfNames, - sizeof(struct ExportNameEntry), _compare); - } - - // search function name in list of exported names with binary search - found = (const struct ExportNameEntry*) bsearch(&name, - module->nameExportsTable, - exports->NumberOfNames, - sizeof(struct ExportNameEntry), _find); - if (!found) { - // exported symbol not found - SetLastError(ERROR_PROC_NOT_FOUND); - return nullptr; - } - - idx = found->idx; - } - - if (idx > exports->NumberOfFunctions) { - // name <-> ordinal number don't match - SetLastError(ERROR_PROC_NOT_FOUND); - return nullptr; - } - - // AddressOfFunctions contains the RVAs to the "real" functions - return (FARPROC)(LPVOID)(codeBase + (*(DWORD*)(codeBase + exports->AddressOfFunctions + (static_cast(idx) * 4)))); -} -#define DEFAULT_LANGUAGE MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL) -HMEMORYRSRC MemoryFindResource(HMEMORYMODULE module, LPCTSTR name, LPCTSTR type) { - return MemoryFindResourceEx(module, name, type, DEFAULT_LANGUAGE); -} -static PIMAGE_RESOURCE_DIRECTORY_ENTRY _MemorySearchResourceEntry(void* root, PIMAGE_RESOURCE_DIRECTORY resources, LPCTSTR key) { - PIMAGE_RESOURCE_DIRECTORY_ENTRY entries = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(resources + 1); - PIMAGE_RESOURCE_DIRECTORY_ENTRY result = nullptr; - DWORD start; - DWORD end; - DWORD middle; - - if (!IS_INTRESOURCE(key) && key[0] == TEXT('#')) { - // special case: resource id given as string - TCHAR* endpos = nullptr; - long int tmpkey = (WORD)_tcstol((TCHAR*)&key[1], &endpos, 10); - if (tmpkey <= 0xffff && lstrlen(endpos) == 0) { - key = MAKEINTRESOURCE(tmpkey); - } - } - - // entries are stored as ordered list of named entries, - // followed by an ordered list of id entries - we can do - // a binary search to find faster... - if (IS_INTRESOURCE(key)) { - WORD check = (WORD)(uintptr_t)key; - start = resources->NumberOfNamedEntries; - end = start + resources->NumberOfIdEntries; - - while (end > start) { - WORD entryName; - middle = (start + end) >> 1; - entryName = (WORD)entries[middle].Name; - if (check < entryName) { - end = (end != middle ? middle : middle - 1); - } - else if (check > entryName) { - start = (start != middle ? middle : middle + 1); - } - else { - result = &entries[middle]; - break; - } - } - } - else { - LPCWSTR searchKey; - size_t searchKeyLen = _tcslen(key); - -#if defined(UNICODE) - searchKey = key; -#else - // Resource names are always stored using 16bit characters, need to - // convert string we search for. -#define MAX_LOCAL_KEY_LENGTH 2048 - // In most cases resource names are short, so optimize for that by - // using a pre-allocated array. - wchar_t _searchKeySpace[MAX_LOCAL_KEY_LENGTH + 1]; - LPWSTR _searchKey = nullptr; - if (searchKeyLen > MAX_LOCAL_KEY_LENGTH) { - if (!(_searchKey = new wchar_t[searchKeyLen + 1])) { - SetLastError(ERROR_OUTOFMEMORY); - return nullptr; - } - } - else { - _searchKey = &_searchKeySpace[0]; - } - - mbstowcs(_searchKey, key, searchKeyLen); - _searchKey[searchKeyLen] = 0; - searchKey = _searchKey; -#endif - start = 0; - end = resources->NumberOfNamedEntries; - while (end > start) { - int cmp; - PIMAGE_RESOURCE_DIR_STRING_U resourceString; - middle = (start + end) >> 1; - resourceString = (PIMAGE_RESOURCE_DIR_STRING_U)OffsetPointer(root, entries[middle].Name & 0x7FFFFFFF); - cmp = _wcsnicmp(searchKey, resourceString->NameString, resourceString->Length); - if (cmp == 0) { - // Handle partial match - if (searchKeyLen > resourceString->Length) { - cmp = 1; - } - else if (searchKeyLen < resourceString->Length) { - cmp = -1; - } - } - if (cmp < 0) { - end = (middle != end ? middle : middle - 1); - } - else if (cmp > 0) { - start = (middle != start ? middle : middle + 1); - } - else { - result = &entries[middle]; - break; - } - } -#if !defined(UNICODE) - if (searchKeyLen > MAX_LOCAL_KEY_LENGTH) { - delete[] _searchKey; - } -#undef MAX_LOCAL_KEY_LENGTH -#endif - } - - return result; -} -HMEMORYRSRC MemoryFindResourceEx(HMEMORYMODULE module, LPCTSTR name, LPCTSTR type, WORD language) { - PMEMORYMODULE mod = MapMemoryModuleHandle(module); - unsigned char* codeBase = mod->codeBase; - 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); - return nullptr; - } - - if (language == DEFAULT_LANGUAGE) { - // use language from current thread - language = LANGIDFROMLCID(GetThreadLocale()); - } - - // resources are stored as three-level tree - // - first node is the type - // - second node is the name - // - third node is the language - rootResources = (PIMAGE_RESOURCE_DIRECTORY)(codeBase + directory->VirtualAddress); - foundType = _MemorySearchResourceEntry(rootResources, rootResources, type); - if (foundType == nullptr) { - SetLastError(ERROR_RESOURCE_TYPE_NOT_FOUND); - return nullptr; - } - - typeResources = (PIMAGE_RESOURCE_DIRECTORY)(codeBase + directory->VirtualAddress + (foundType->OffsetToData & 0x7fffffff)); - foundName = _MemorySearchResourceEntry(rootResources, typeResources, name); - if (foundName == nullptr) { - SetLastError(ERROR_RESOURCE_NAME_NOT_FOUND); - return nullptr; - } - - nameResources = (PIMAGE_RESOURCE_DIRECTORY)(codeBase + directory->VirtualAddress + (foundName->OffsetToData & 0x7fffffff)); - foundLanguage = _MemorySearchResourceEntry(rootResources, nameResources, (LPCTSTR)(uintptr_t)language); - if (foundLanguage == nullptr) { - // requested language not found, use first available - if (nameResources->NumberOfIdEntries == 0) { - SetLastError(ERROR_RESOURCE_LANG_NOT_FOUND); - return nullptr; - } - - foundLanguage = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(nameResources + 1); - } - - return (codeBase + directory->VirtualAddress + (foundLanguage->OffsetToData & 0x7fffffff)); -} -DWORD MemorySizeofResource(HMEMORYMODULE module, HMEMORYRSRC resource) { - PIMAGE_RESOURCE_DATA_ENTRY entry; - UNREFERENCED_PARAMETER(module); - entry = (PIMAGE_RESOURCE_DATA_ENTRY)resource; - if (entry == nullptr) { - return 0; - } - - return entry->Size; -} -LPVOID MemoryLoadResource(HMEMORYMODULE module, HMEMORYRSRC resource) { - unsigned char* codeBase = MapMemoryModuleHandle(module)->codeBase; - PIMAGE_RESOURCE_DATA_ENTRY entry = (PIMAGE_RESOURCE_DATA_ENTRY)resource; - if (entry == nullptr) { - return nullptr; - } - - return codeBase + entry->OffsetToData; -} -int MemoryLoadString(HMEMORYMODULE module, UINT id, LPTSTR buffer, int maxsize) { - return MemoryLoadStringEx(module, id, buffer, maxsize, DEFAULT_LANGUAGE); -} -int MemoryLoadStringEx(HMEMORYMODULE module, UINT id, LPTSTR buffer, int maxsize, WORD language) { - HMEMORYRSRC resource; - PIMAGE_RESOURCE_DIR_STRING_U data; - DWORD size; - if (maxsize == 0) { - return 0; - } - - resource = MemoryFindResourceEx(module, MAKEINTRESOURCEW((static_cast(id) >> 4) + 1), RT_STRING, language); - if (resource == nullptr) { - buffer[0] = 0; - return 0; - } - - data = (PIMAGE_RESOURCE_DIR_STRING_U)MemoryLoadResource(module, resource); - id = id & 0x0f; - while (id--) { - data = (PIMAGE_RESOURCE_DIR_STRING_U)OffsetPointer(data, (static_cast(data->Length) + 1) * sizeof(WCHAR)); - } - if (data->Length == 0) { - SetLastError(ERROR_RESOURCE_NAME_NOT_FOUND); - buffer[0] = 0; - return 0; - } - - size = data->Length; - if (size >= (DWORD)maxsize) { - size = maxsize; - } - else { - buffer[size] = 0; - } -#if defined(UNICODE) - wcsncpy(buffer, data->NameString, size); -#else - wcstombs(buffer, data->NameString, size); -#endif - return size; -} diff --git a/MemoryModule/MemoryModule.h b/MemoryModule/MemoryModule.h index 471ddee..22716ff 100644 --- a/MemoryModule/MemoryModule.h +++ b/MemoryModule/MemoryModule.h @@ -1,29 +1,11 @@ #pragma once +#pragma warning(disable:4996) #ifndef __MEMORY_MODULE_HEADER #define __MEMORY_MODULE_HEADER -#pragma warning(disable:4996) -struct ExportNameEntry { - LPCSTR name; - WORD idx; -}; -typedef struct { - LPVOID address; - LPVOID alignedAddress; - SIZE_T size; - DWORD characteristics; - BOOL last; -} SECTIONFINALIZEDATA, * PSECTIONFINALIZEDATA; -typedef BOOL(WINAPI* DllEntryProc)(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved); -#ifdef _WIN64 -typedef struct POINTER_LIST { - struct POINTER_LIST* next; - void* address; -} POINTER_LIST; -#endif typedef HMODULE HMEMORYMODULE; -typedef void* HMEMORYRSRC; + typedef struct _MEMORYMODULE { /* --------------------------- @@ -40,51 +22,39 @@ typedef struct _MEMORYMODULE { codes */ ULONG64 Signature; - __declspec(align(sizeof(size_t))) struct { - DWORD SizeofHeaders; - union { - struct { - //Status Flags - BYTE initialized : 1; - BYTE loadFromNtLoadDllMemory : 1; - BYTE underUnload : 1; - BYTE reservedStatusFlags : 5; - BYTE cbFlagsReserved; + DWORD SizeofHeaders; + union { + struct { + //Status Flags + BYTE initialized : 1; + BYTE loadFromNtLoadDllMemory : 1; + BYTE underUnload : 1; + BYTE reservedStatusFlags : 5; - //Load Flags - WORD MappedDll : 1; - WORD InsertInvertedFunctionTableEntry : 1; - WORD TlsHandled : 1; - WORD UseReferenceCount : 1; - WORD reservedLoadFlags : 12; + BYTE cbFlagsReserved; + + //Load Flags + WORD MappedDll : 1; + WORD InsertInvertedFunctionTableEntry : 1; + WORD TlsHandled : 1; + WORD UseReferenceCount : 1; + WORD reservedLoadFlags : 12; - }; - DWORD dwFlags; }; + DWORD dwFlags; }; LPBYTE codeBase; //codeBase == ImageBase - __declspec(align(sizeof(size_t))) struct { - PVOID lpReserved; - }; + PVOID lpReserved; HMODULE* hModulesList; //Import module handles - __declspec(align(sizeof(size_t))) struct { - DWORD dwModulesCount; //number of module handles - DWORD dwReserved; - }; + DWORD dwModulesCount; //number of module handles + DWORD dwReserved; - ExportNameEntry* nameExportsTable; - __declspec(align(sizeof(size_t))) struct { - DWORD pageSize; //SYSTEM_INFO::dwPageSize - DWORD headers_align; //headers_align == OptionalHeaders.BaseOfCode; - }; + DWORD pageSize; //SYSTEM_INFO::dwPageSize + DWORD headers_align; //headers_align == OptionalHeaders.BaseOfCode; -#ifdef _WIN64 - POINTER_LIST* blockedMemory; - PVOID lpReserved2; -#endif } MEMORYMODULE, * PMEMORYMODULE; @@ -94,55 +64,13 @@ typedef struct _MEMORYMODULE { extern "C" { #endif - /** - * Load DLL from memory location with the given size. - * - * All dependencies are resolved using default LoadLibrary/GetProcAddress - * calls through the Windows API. - */ - HMEMORYMODULE MemoryLoadLibrary(const void*); + NTSTATUS MemoryLoadLibrary( + _Out_ HMEMORYMODULE* MemoryModuleHandle, + _In_ LPCVOID data + ); - /** - * Get address of exported method. Supports loading both by name and by - * ordinal value. - */ - FARPROC MemoryGetProcAddress(HMEMORYMODULE, LPCSTR); - - /** - * Free previously loaded DLL. - */ bool MemoryFreeLibrary(HMEMORYMODULE); - /** - * Find the location of a resource with the specified type and name. - */ - HMEMORYRSRC MemoryFindResource(HMEMORYMODULE, LPCTSTR, LPCTSTR); - - /** - * Find the location of a resource with the specified type, name and language. - */ - HMEMORYRSRC MemoryFindResourceEx(HMEMORYMODULE, LPCTSTR, LPCTSTR, WORD); - - /** - * Get the size of the resource in bytes. - */ - DWORD MemorySizeofResource(HMEMORYMODULE, HMEMORYRSRC); - - /** - * Get a pointer to the contents of the resource. - */ - LPVOID MemoryLoadResource(HMEMORYMODULE, HMEMORYRSRC); - - /** - * Load a string resource. - */ - int MemoryLoadString(HMEMORYMODULE, UINT, LPTSTR, int); - - /** - * Load a string resource with a given language. - */ - int MemoryLoadStringEx(HMEMORYMODULE, UINT, LPTSTR, int, WORD); - bool WINAPI IsValidMemoryModuleHandle(HMEMORYMODULE hModule); PMEMORYMODULE WINAPI MapMemoryModuleHandle(HMEMORYMODULE hModule); diff --git a/MemoryModule/MmpTls.cpp b/MemoryModule/MmpTls.cpp index a4ef78f..5bbb7ab 100644 --- a/MemoryModule/MmpTls.cpp +++ b/MemoryModule/MmpTls.cpp @@ -732,8 +732,6 @@ NTSTATUS NTAPI MmpAllocateTlsEntry( NTSTATUS NTAPI MmpReleaseTlsEntry(_In_ PLDR_DATA_TABLE_ENTRY lpModuleEntry) { - NTSTATUS status = STATUS_NOT_FOUND; - RtlAcquireSRWLockExclusive(&MmpTlsListLock); for (auto entry = MmpTlsList.Flink; entry != &MmpTlsList; entry = entry->Flink) { @@ -743,14 +741,13 @@ NTSTATUS NTAPI MmpReleaseTlsEntry(_In_ PLDR_DATA_TABLE_ENTRY lpModuleEntry) { RtlClearBit(&MmpTlsBitmap, p->TlsDirectory.Characteristics); RtlFreeHeap(RtlProcessHeap(), 0, p); - status = STATUS_SUCCESS; break; } } RtlReleaseSRWLockExclusive(&MmpTlsListLock); - return status; + return STATUS_SUCCESS; } NTSTATUS NTAPI MmpHandleTlsData(_In_ PLDR_DATA_TABLE_ENTRY lpModuleEntry) { diff --git a/MemoryModule/NativeFunctionsInternal.cpp b/MemoryModule/NativeFunctionsInternal.cpp index ceeae6d..c3b51e5 100644 --- a/MemoryModule/NativeFunctionsInternal.cpp +++ b/MemoryModule/NativeFunctionsInternal.cpp @@ -12,6 +12,8 @@ _EX_ListHead->Blink = (Entry);\ } +typedef BOOL(WINAPI* PDLL_STARTUP_ROUTINE)(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved); + static PRTL_RB_TREE NTAPI RtlFindLdrpModuleBaseAddressIndex() { static PRTL_RB_TREE LdrpModuleBaseAddressIndex = nullptr; if (LdrpModuleBaseAddressIndex)return LdrpModuleBaseAddressIndex; @@ -546,7 +548,7 @@ BOOL NTAPI LdrpCallInitializers(PMEMORYMODULE module, DWORD dwReason) { if (headers->OptionalHeader.AddressOfEntryPoint) { __try { // notify library about attaching to process - if (((DllEntryProc)(module->codeBase + headers->OptionalHeader.AddressOfEntryPoint))((HINSTANCE)module->codeBase, dwReason, 0)) { + if (((PDLL_STARTUP_ROUTINE)(module->codeBase + headers->OptionalHeader.AddressOfEntryPoint))((HINSTANCE)module->codeBase, dwReason, 0)) { module->initialized = TRUE; return TRUE; } @@ -626,18 +628,9 @@ NTSTATUS NTAPI LdrLoadDllMemoryExW( } } - if (!(*BaseAddress = MemoryLoadLibrary(BufferAddress))) { - switch (GetLastError()) { - case ERROR_BAD_EXE_FORMAT: - return STATUS_INVALID_IMAGE_FORMAT; - case ERROR_OUTOFMEMORY: - return STATUS_NO_MEMORY; - case ERROR_DLL_INIT_FAILED: - return STATUS_DLL_INIT_FAILED; - default: - return STATUS_UNSUCCESSFUL; - } - } + status = MemoryLoadLibrary(BaseAddress, BufferAddress); + if (!NT_SUCCESS(status))return status; + if (!(module = MapMemoryModuleHandle(*BaseAddress))) { __fastfail(FAST_FAIL_FATAL_APP_EXIT); DebugBreak(); @@ -766,8 +759,11 @@ NTSTATUS NTAPI LdrUnloadDllMemory(IN HMEMORYMODULE BaseAddress) { if (!(count & ~1)) { module->underUnload = true; if (module->initialized) { - DllEntryProc DllEntry = (DllEntryProc)(LPVOID)(module->codeBase + headers->OptionalHeader.AddressOfEntryPoint); - (*DllEntry)((HINSTANCE)module->codeBase, DLL_PROCESS_DETACH, 0); + PDLL_STARTUP_ROUTINE((LPVOID)(module->codeBase + headers->OptionalHeader.AddressOfEntryPoint))( + (HINSTANCE)module->codeBase, + DLL_PROCESS_DETACH, + 0 + ); } if (module->MappedDll) { if (module->InsertInvertedFunctionTableEntry) { diff --git a/a/a.vcxproj b/a/a.vcxproj index eca2992..87fd5fe 100644 --- a/a/a.vcxproj +++ b/a/a.vcxproj @@ -171,7 +171,6 @@ - diff --git a/a/a.vcxproj.filters b/a/a.vcxproj.filters index a959bc2..bf20d60 100644 --- a/a/a.vcxproj.filters +++ b/a/a.vcxproj.filters @@ -18,9 +18,6 @@ Source Files - - Source Files - diff --git a/a/dllmain.cpp b/a/dllmain.cpp index 871fd7e..b0a1f18 100644 --- a/a/dllmain.cpp +++ b/a/dllmain.cpp @@ -2,13 +2,26 @@ #include #include #include -#include "../MemoryModule/Native.h" + #pragma comment(lib,"ws2_32.lib") #pragma comment(lib,"wintrust.lib") #pragma comment(lib,"ntdll.lib") typedef NTSTATUS(NTAPI* PUSER_THREAD_START_ROUTINE)(_In_ PVOID ThreadParameter); +#define NtCurrentProcess() (HANDLE)-1 + +#ifdef _WIN64 +#define NtCurrentThreadLocalStoragePointer() *(LPVOID*)(LPBYTE(NtCurrentTeb()) + 0x58) +#else +#define NtCurrentThreadLocalStoragePointer() *(LPVOID*)(LPBYTE(NtCurrentTeb()) + 0x2C) +#endif + +typedef struct _CLIENT_ID { + VOID* UniqueProcess; + VOID* UniqueThread; +}CLIENT_ID, * PCLIENT_ID; + extern "C" NTSYSAPI NTSTATUS @@ -103,13 +116,13 @@ int __test__() { static thread_local int x = 0xffccffdd; NTSTATUS WINAPI Thread(PVOID) { - printf("[1] ThreadLocalStoragePointer = %p\n", NtCurrentTeb()->ThreadLocalStoragePointer); + printf("[1] ThreadLocalStoragePointer = %p\n", NtCurrentThreadLocalStoragePointer()); return x == 0xffccffdd ? 0 : 1; } int thread() { x = 2; - printf("[0] ThreadLocalStoragePointer = %p\n", NtCurrentTeb()->ThreadLocalStoragePointer); + printf("[0] ThreadLocalStoragePointer = %p\n", NtCurrentThreadLocalStoragePointer()); HANDLE hThread;// = CreateThread(nullptr, 0, Thread, nullptr, 0, nullptr); RtlCreateUserThread(NtCurrentProcess(), nullptr, FALSE, 0, 0, 0, Thread, nullptr, &hThread, nullptr); DWORD ret = -1;