#include "stdafx.h" static VOID NTAPI RtlpInsertInvertedFunctionTable(IN PRTL_INVERTED_FUNCTION_TABLE InvertedTable, IN PVOID ImageBase, IN ULONG SizeOfImage) { #ifdef _WIN64 ULONG CurrentSize; PIMAGE_RUNTIME_FUNCTION_ENTRY FunctionTable; ULONG Index; ULONG SizeOfTable = 0; bool IsWin8OrGreater = RtlIsWindowsVersionOrGreater(6, 2, 0); Index = (ULONG)IsWin8OrGreater; CurrentSize = InvertedTable->Count; if (CurrentSize != InvertedTable->MaxCount) { if (CurrentSize != 0) { while (Index < CurrentSize) { if (ImageBase < InvertedTable->Entries[Index].ImageBase)break; ++Index; } if (Index != CurrentSize) { RtlMoveMemory(&InvertedTable->Entries[Index + 1], &InvertedTable->Entries[Index], (CurrentSize - Index) * sizeof(RTL_INVERTED_FUNCTION_TABLE_ENTRY)); } } 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++; } else { IsWin8OrGreater ? (InvertedTable->Overflow = TRUE) : (InvertedTable->Epoch = TRUE); } #else DWORD ptr, count; bool IsWin8OrGreater = RtlIsWindowsVersionOrGreater(6, 2, 0); ULONG Index = IsWin8OrGreater ? 1 : 0; if (InvertedTable->Count == InvertedTable->MaxCount) { if (IsWin8OrGreater)InvertedTable->NextEntrySEHandlerTableEncoded = TRUE; else InvertedTable->Overflow = TRUE; return; } while (Index < InvertedTable->Count) { if (ImageBase < (IsWin8OrGreater ? ((PRTL_INVERTED_FUNCTION_TABLE_ENTRY_64)&InvertedTable->Entries[Index])->ImageBase : InvertedTable->Entries[Index].ImageBase)) break; Index++; } if (Index != InvertedTable->Count) { if (IsWin8OrGreater) { RtlMoveMemory(&InvertedTable->Entries[Index + 1], &InvertedTable->Entries[Index], (InvertedTable->Count - Index) * sizeof(RTL_INVERTED_FUNCTION_TABLE_ENTRY)); } else { RtlMoveMemory(&InvertedTable->Entries[Index].NextEntrySEHandlerTableEncoded, Index ? &InvertedTable->Entries[Index - 1].NextEntrySEHandlerTableEncoded : (PVOID)&InvertedTable->NextEntrySEHandlerTableEncoded, (InvertedTable->Count - Index) * sizeof(RTL_INVERTED_FUNCTION_TABLE_ENTRY)); } } RtlCaptureImageExceptionValues(ImageBase, &ptr, &count); if (IsWin8OrGreater) { //memory layout is same as x64 PRTL_INVERTED_FUNCTION_TABLE_ENTRY_64 entry = (decltype(entry))&InvertedTable->Entries[Index]; entry->ExceptionDirectory = (PIMAGE_RUNTIME_FUNCTION_ENTRY)RtlEncodeSystemPointer((PVOID)ptr); entry->ExceptionDirectorySize = count; entry->ImageBase = ImageBase; entry->ImageSize = SizeOfImage; } else { if (Index) InvertedTable->Entries[Index - 1].NextEntrySEHandlerTableEncoded = RtlEncodeSystemPointer((PVOID)ptr); else InvertedTable->NextEntrySEHandlerTableEncoded = (DWORD)RtlEncodeSystemPointer((PVOID)ptr); InvertedTable->Entries[Index].ImageBase = ImageBase; InvertedTable->Entries[Index].ImageSize = SizeOfImage; InvertedTable->Entries[Index].SEHandlerCount = count; } ++InvertedTable->Count; #endif return; } static VOID NTAPI RtlpRemoveInvertedFunctionTable(IN PRTL_INVERTED_FUNCTION_TABLE InvertedTable, IN PVOID ImageBase) { ULONG CurrentSize; ULONG Index; //bool need = RtlIsWindowsVersionOrGreater(6, 2, 0); bool IsWin8OrGreater = RtlIsWindowsVersionOrGreater(6, 2, 0); CurrentSize = InvertedTable->Count; for (Index = 0; Index < CurrentSize; Index += 1) { if (ImageBase == (IsWin8OrGreater ? ((PRTL_INVERTED_FUNCTION_TABLE_ENTRY_64)&InvertedTable->Entries[Index])->ImageBase : InvertedTable->Entries[Index].ImageBase)) break; } if (Index != CurrentSize) { //if (need)_InterlockedIncrement(&InvertedTable->Epoch); if (CurrentSize != 1) { #ifdef _WIN64 RtlMoveMemory(&InvertedTable->Entries[Index], &InvertedTable->Entries[Index + 1], (CurrentSize - Index - 1) * sizeof(RTL_INVERTED_FUNCTION_TABLE_ENTRY)); #else if (IsWin8OrGreater) { RtlMoveMemory(&InvertedTable->Entries[Index], &InvertedTable->Entries[Index + 1], (CurrentSize - Index) * sizeof(RTL_INVERTED_FUNCTION_TABLE_ENTRY)); } else { RtlMoveMemory( Index ? &InvertedTable->Entries[Index - 1].NextEntrySEHandlerTableEncoded : (PVOID)&InvertedTable->NextEntrySEHandlerTableEncoded, &InvertedTable->Entries[Index].NextEntrySEHandlerTableEncoded, (CurrentSize - Index) * sizeof(RTL_INVERTED_FUNCTION_TABLE_ENTRY)); } #endif } InvertedTable->Count--; //if (need)_InterlockedIncrement(&InvertedTable->Epoch); } if (InvertedTable->Count != InvertedTable->MaxCount) { if (IsWin8OrGreater) { PRTL_INVERTED_FUNCTION_TABLE_64(InvertedTable)->Overflow = FALSE; } else { PRTL_INVERTED_FUNCTION_TABLE_WIN7_32(InvertedTable)->Overflow = FALSE; } } return; } static NTSTATUS NTAPI RtlProtectMrdata(IN SIZE_T Protect) { static PVOID MrdataBase = nullptr; static SIZE_T size = 0; NTSTATUS status; PVOID tmp; SIZE_T tmp_len; ULONG old; if (!MrdataBase) { MEMORY_BASIC_INFORMATION mbi{}; status = NtQueryVirtualMemory(GetCurrentProcess(), MmpGlobalDataPtr->LdrpInvertedFunctionTable, MemoryBasicInformation, &mbi, sizeof(mbi), nullptr); if (!NT_SUCCESS(status))return status; MrdataBase = mbi.BaseAddress; size = mbi.RegionSize; } tmp = MrdataBase; tmp_len = size; return NtProtectVirtualMemory(GetCurrentProcess(), &tmp, &tmp_len, Protect, &old); } NTSTATUS NTAPI RtlInsertInvertedFunctionTable(IN PVOID BaseAddress, IN size_t ImageSize) { auto table = PRTL_INVERTED_FUNCTION_TABLE(MmpGlobalDataPtr->LdrpInvertedFunctionTable); if (!table)return STATUS_NOT_SUPPORTED; bool need_virtual_protect = RtlIsWindowsVersionOrGreater(6, 3, 0); NTSTATUS status; if (need_virtual_protect) { status = RtlProtectMrdata(PAGE_READWRITE); if (!NT_SUCCESS(status))return status; } RtlpInsertInvertedFunctionTable(table, BaseAddress, ImageSize); if (need_virtual_protect) { status = RtlProtectMrdata(PAGE_READONLY); if (!NT_SUCCESS(status))return status; } 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) { auto table = PRTL_INVERTED_FUNCTION_TABLE(MmpGlobalDataPtr->LdrpInvertedFunctionTable); bool need_virtual_protect = RtlIsWindowsVersionOrGreater(6, 3, 0); NTSTATUS status; if (need_virtual_protect) { status = RtlProtectMrdata(PAGE_READWRITE); if (!NT_SUCCESS(status))return status; } RtlpRemoveInvertedFunctionTable(table, ImageBase); if (need_virtual_protect) { status = RtlProtectMrdata(PAGE_READONLY); if (!NT_SUCCESS(status))return status; } return STATUS_SUCCESS; }