14#define min(a,b) (((a) < (b)) ? (a) : (b))
18#define RTL_VERIFY_FLAGS_MAJOR_VERSION 0
19#define RTL_VERIFY_FLAGS_MINOR_VERSION 1
20#define RTL_VERIFY_FLAGS_BUILD_NUMBERS 2
21#define RTL_VERIFY_FLAGS_DEFAULT RTL_VERIFY_FLAGS_MAJOR_VERSION|RTL_VERIFY_FLAGS_MINOR_VERSION|RTL_VERIFY_FLAGS_BUILD_NUMBERS
161 static void NTAPI RtlCurrentVersion(_Out_
PNtVersion pVersion) {
162 RtlGetNtVersionNumbers(
163 &pVersion->MajorVersion,
164 &pVersion->MinorVersion,
165 &pVersion->BuildNumber
169 static BOOL NTAPI RtlIsWindowsVersionOrGreater(
170 _In_ ULONG MajorVersion,
171 _In_ ULONG MinorVersion,
172 _In_ ULONG BuildNumber
175 RtlCurrentVersion(&version);
176 if (version.MajorVersion == MajorVersion) {
177 if (version.MinorVersion == MinorVersion)
return version.BuildNumber >= BuildNumber;
178 else return (version.MinorVersion > MinorVersion);
180 else return version.MajorVersion > MajorVersion;
183 static BOOL NTAPI RtlVerifyVersion(
184 _In_ ULONG MajorVersion,
185 _In_ ULONG MinorVersion,
186 _In_ ULONG BuildNumber,
190 RtlCurrentVersion(&version);
191 if (version.MajorVersion == MajorVersion &&
197 static int NTAPI RtlCaptureImageExceptionValues(PVOID BaseAddress, PDWORD SEHandlerTable, PDWORD SEHandlerCount) {
198 PIMAGE_LOAD_CONFIG_DIRECTORY pLoadConfigDirectory =
nullptr;
199 PIMAGE_COR20_HEADER pCor20 =
nullptr;
202 auto hdrs =
reinterpret_cast<PIMAGE_NT_HEADERS
>(RtlImageNtHeader(BaseAddress));
204 if (hdrs->OptionalHeader.DllCharacteristics & IMAGE_DLLCHARACTERISTICS_NO_SEH) {
205 *SEHandlerTable = *SEHandlerCount = -1;
210 pLoadConfigDirectory = (
decltype(pLoadConfigDirectory))RtlImageDirectoryEntryToData(BaseAddress, TRUE, IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG, &Size);
211 if (pLoadConfigDirectory) {
212 if (Size == 0x40 && pLoadConfigDirectory->Size >= 0x48u) {
213 if (pLoadConfigDirectory->SEHandlerTable && pLoadConfigDirectory->SEHandlerCount) {
214 *SEHandlerTable = pLoadConfigDirectory->SEHandlerTable;
215 return *SEHandlerCount = pLoadConfigDirectory->SEHandlerCount;
221 pCor20 = (
decltype(pCor20))RtlImageDirectoryEntryToData(BaseAddress, TRUE, IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR, &Size);
222 *SEHandlerTable = *SEHandlerCount = ((pCor20 && pCor20->Flags & 1) ? -1 : 0);
228 if (RtlIsWindowsVersionOrGreater(6, 2, 0)) {
232 return entry->DllBase ==
nullptr;
236 static NTSTATUS NTAPI RtlFindMemoryBlockFromModuleSection(
237 _In_ HMODULE ModuleHandle,
238 _In_ LPCSTR SectionName,
241 NTSTATUS
status = STATUS_SUCCESS;
244#define RtlFindMemoryBlockFromModuleSection__leave __leave
246#define RtlFindMemoryBlockFromModuleSection__leave return status
250 std::cout <<
"Searching in section " << SectionName <<
" in module " << ModuleHandle << std::endl;
259 if (!SearchContext->SearchPattern || !SearchContext->PatternSize) {
260 SearchContext->Result =
nullptr;
261 SearchContext->MemoryBlockSize = 0;
262 status = STATUS_INVALID_PARAMETER;
266 if (SearchContext->Result) {
267 ++SearchContext->Result;
268 --SearchContext->MemoryBlockSize;
276 auto headers =
reinterpret_cast<PIMAGE_NT_HEADERS
>(RtlImageNtHeader(ModuleHandle));
277 PIMAGE_SECTION_HEADER section =
nullptr;
280 section = IMAGE_FIRST_SECTION(headers);
281 for (WORD i = 0; i < headers->FileHeader.NumberOfSections; ++i) {
282 if (!_strnicmp(SectionName,
reinterpret_cast<LPCSTR
>(section->Name), 8)) {
283 SearchContext->Result =
reinterpret_cast<LPBYTE
>(ModuleHandle) + section->VirtualAddress;
284 SearchContext->MemoryBlockSize = section->Misc.VirtualSize;
291 if (!SearchContext->Result || !SearchContext->MemoryBlockSize || SearchContext->MemoryBlockSize < SearchContext->PatternSize) {
292 SearchContext->Result =
nullptr;
293 SearchContext->MemoryBlockSize = 0;
294 status = STATUS_NOT_FOUND;
299 status = STATUS_INVALID_PARAMETER_1;
308 LPBYTE end = SearchContext->Result + SearchContext->MemoryBlockSize - SearchContext->PatternSize;
309 while (SearchContext->Result <= end) {
310 if (RtlCompareMemory(SearchContext->SearchPattern, SearchContext->Result, SearchContext->PatternSize) == SearchContext->PatternSize) {
314 ++SearchContext->Result;
315 --SearchContext->MemoryBlockSize;
322 SearchContext->Result =
nullptr;
323 SearchContext->MemoryBlockSize = 0;
324 status = STATUS_NOT_FOUND;
333 static NTSTATUS RtlProtectMrdata(_In_ ULONG Protect, PRTL_INVERTED_FUNCTION_TABLE mrdata) {
334 static PVOID MrdataBase =
nullptr;
335 static SIZE_T size = 0;
342 MEMORY_BASIC_INFORMATION mbi= { 0 };
343 status = NtQueryVirtualMemory(NtCurrentProcess(), mrdata, MemoryBasicInformation, &mbi,
sizeof(mbi),
nullptr);
345 MrdataBase = mbi.BaseAddress;
346 size = mbi.RegionSize;
351 return NtProtectVirtualMemory(NtCurrentProcess(), &tmp, &tmp_len, Protect, &old);
354 static PVOID RtlFindInvertedFunctionTable() {
368 HMODULE hModule =
nullptr, hNtdll = GetModuleHandleW(L
"ntdll.dll");
369 LPCSTR lpSectionName =
".data";
370 if (!hNtdll)
return nullptr;
371 auto NtdllHeaders =
reinterpret_cast<PIMAGE_NT_HEADERS
>(RtlImageNtHeader(hNtdll));
372 PIMAGE_NT_HEADERS ModuleHeaders =
nullptr;
373 _RTL_INVERTED_FUNCTION_TABLE_ENTRY_64 entry = { 0 };
374 PIMAGE_DATA_DIRECTORY dir =
nullptr;
376 SearchContext.
SearchPattern =
reinterpret_cast<LPBYTE
>(&entry);
377 SearchContext.PatternSize =
sizeof(entry);
378 RtlSecureZeroMemory(&entry,
sizeof(entry));
383 ModuleHeaders = NtdllHeaders;
387 else if (RtlIsWindowsVersionOrGreater(6, 3, 0)) {
389 ModuleHeaders = NtdllHeaders;
390 lpSectionName =
".mrdata";
393 PLIST_ENTRY ListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList,
394 ListEntry = ListHead->Flink;
395 PLDR_DATA_TABLE_ENTRY CurEntry =
nullptr;
396 while (ListEntry != ListHead) {
397 CurEntry = CONTAINING_RECORD(ListEntry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
398 ListEntry = ListEntry->Flink;
399 hModule =
reinterpret_cast<HMODULE
>(
400 hModule ?
reinterpret_cast<HMODULE
>(
min(
401 reinterpret_cast<uintptr_t
>(hModule),
402 reinterpret_cast<uintptr_t
>(CurEntry->DllBase)
403 )) : CurEntry->DllBase
406 if (hModule) ModuleHeaders =
reinterpret_cast<PIMAGE_NT_HEADERS
>(RtlImageNtHeader(hModule));
408 if (!hModule || !ModuleHeaders || !hNtdll || !NtdllHeaders)
return nullptr;
409 dir = &ModuleHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXCEPTION];
411 entry.ExceptionDirectory = dir->Size ?
412 reinterpret_cast<PIMAGE_RUNTIME_FUNCTION_ENTRY
>(
413 reinterpret_cast<size_t>(hModule) + dir->VirtualAddress
415 entry.ImageBase =
reinterpret_cast<PVOID
>(hModule);
416 entry.ImageSize = ModuleHeaders->OptionalHeader.SizeOfImage;
417 entry.ExceptionDirectorySize = dir->Size;
419 while (NT_SUCCESS(RtlFindMemoryBlockFromModuleSection(hNtdll, lpSectionName, &SearchContext))) {
421 if (RtlIsWindowsVersionOrGreater(6, 2, 0) && tab->MaxCount == 0x200 && !tab->Overflow)
return tab;
422 else if (tab->MaxCount == 0x200 && !tab->Epoch)
return tab;
439 HMODULE hModule =
nullptr, hNtdll = GetModuleHandleW(L
"ntdll.dll");
440 auto NtdllHeaders =
reinterpret_cast<PIMAGE_NT_HEADERS
>(RtlImageNtHeader(hNtdll));
441 PIMAGE_NT_HEADERS ModuleHeaders =
nullptr;
442 _RTL_INVERTED_FUNCTION_TABLE_ENTRY_WIN7_32 entry = { 0 };
443 RtlSecureZeroMemory(&entry,
sizeof(entry));
444 LPCSTR lpSectionName =
".data";
446 SearchContext.
SearchPattern =
reinterpret_cast<LPBYTE
>(&entry);
447 SearchContext.PatternSize =
sizeof(entry);
448 PLIST_ENTRY ListHead = &NtCurrentPeb()->Ldr->InMemoryOrderModuleList,
449 ListEntry = ListHead->Flink;
450 PLDR_DATA_TABLE_ENTRY CurEntry =
nullptr;
451 DWORD SEHTable, SEHCount;
454 if (RtlIsWindowsVersionOrGreater(6, 3, 0)) lpSectionName =
".mrdata";
455 else if (!RtlIsWindowsVersionOrGreater(6, 2, 0)) Offset = 0xC;
457 while (ListEntry != ListHead) {
458 CurEntry = CONTAINING_RECORD(ListEntry, LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks);
459 ListEntry = ListEntry->Flink;
460 if (IsModuleUnloaded(CurEntry))
462 if (CurEntry->DllBase == hNtdll && Offset == 0x20)
465 hModule =
reinterpret_cast<HMODULE
>(
466 hModule ?
reinterpret_cast<HMODULE
>(
min(
467 reinterpret_cast<uintptr_t
>(hModule),
468 reinterpret_cast<uintptr_t
>(CurEntry->DllBase)
469 )) : CurEntry->DllBase
472 ModuleHeaders =
reinterpret_cast<PIMAGE_NT_HEADERS
>(RtlImageNtHeader(hModule));
473 if (!hModule || !ModuleHeaders || !hNtdll || !NtdllHeaders)
return nullptr;
475 RtlCaptureImageExceptionValues(hModule, &SEHTable, &SEHCount);
477 if (RtlIsWindowsVersionOrGreater(6, 2, 0)) {
481 entry2->ImageBase =
reinterpret_cast<PVOID
>(hModule);
482 entry2->ImageSize = ModuleHeaders->OptionalHeader.SizeOfImage;
483 entry2->SEHandlerCount = SEHCount;
486 entry.EntrySEHandlerTableEncoded = RtlEncodeSystemPointer(
reinterpret_cast<PVOID
>(SEHTable));
487 entry.ImageBase =
reinterpret_cast<PVOID
>(hModule);
488 entry.ImageSize = ModuleHeaders->OptionalHeader.SizeOfImage;
489 entry.SEHandlerCount = SEHCount;
492 while (NT_SUCCESS(RtlFindMemoryBlockFromModuleSection(hNtdll, lpSectionName, &SearchContext))) {
496 if (RtlIsWindowsVersionOrGreater(6, 2, 0) && tab->MaxCount == 0x200 && !tab->NextEntrySEHandlerTableEncoded)
return tab;
497 else if (tab->MaxCount == 0x200 && !tab->Overflow)
return tab;
503 static VOID RtlpInsertInvertedFunctionTable(
504 _In_ PRTL_INVERTED_FUNCTION_TABLE InvertedTable,
505 _In_ PVOID ImageBase,
506 _In_ ULONG SizeOfImage) {
508 ULONG CurrentSize = InvertedTable->Count;
509 PIMAGE_RUNTIME_FUNCTION_ENTRY FunctionTable =
nullptr;
510 ULONG SizeOfTable = 0;
511 BOOL IsWin8OrGreater = RtlIsWindowsVersionOrGreater(6, 2, 0);
512 ULONG Index =
static_cast<ULONG
>(IsWin8OrGreater);
514 if (CurrentSize != InvertedTable->MaxCount) {
515 if (CurrentSize != 0) {
516 while (Index < CurrentSize) {
517 if (ImageBase < InvertedTable->Entries[Index].ImageBase)
break;
522 if (Index != CurrentSize) {
523 RtlMoveMemory(&InvertedTable->Entries[Index + 1],
524 &InvertedTable->Entries[Index],
525 (CurrentSize - Index) *
sizeof(RTL_INVERTED_FUNCTION_TABLE_ENTRY));
529 FunctionTable =
reinterpret_cast<decltype(FunctionTable)
>(RtlImageDirectoryEntryToData(ImageBase, TRUE, IMAGE_DIRECTORY_ENTRY_EXCEPTION, &SizeOfTable));
530 InvertedTable->Entries[Index].ExceptionDirectory = FunctionTable;
531 InvertedTable->Entries[Index].ImageBase = ImageBase;
532 InvertedTable->Entries[Index].ImageSize = SizeOfImage;
533 InvertedTable->Entries[Index].ExceptionDirectorySize = SizeOfTable;
534 InvertedTable->Count++;
536 std::cout <<
"Exception table was set! " << std::endl;
540 IsWin8OrGreater ? (InvertedTable->Overflow = TRUE) : (InvertedTable->Epoch = TRUE);
544 DWORD ptr = 0, count = 0;
545 BOOL IsWin8OrGreater = RtlIsWindowsVersionOrGreater(6, 2, 0);
546 ULONG Index = IsWin8OrGreater ? 1 : 0;
548 if (InvertedTable->Count == InvertedTable->MaxCount) {
549 if (IsWin8OrGreater)InvertedTable->NextEntrySEHandlerTableEncoded = TRUE;
550 else InvertedTable->Overflow = TRUE;
553 while (Index < InvertedTable->Count) {
554 if (ImageBase < (IsWin8OrGreater ?
556 InvertedTable->Entries[Index].ImageBase))
560 if (Index != InvertedTable->Count) {
561 if (IsWin8OrGreater) {
562 RtlMoveMemory(&InvertedTable->Entries[Index + 1], &InvertedTable->Entries[Index],
563 (InvertedTable->Count - Index) *
sizeof(RTL_INVERTED_FUNCTION_TABLE_ENTRY));
566 RtlMoveMemory(&InvertedTable->Entries[Index].EntrySEHandlerTableEncoded,
567 Index ? &InvertedTable->Entries[Index - 1].EntrySEHandlerTableEncoded : (PVOID)&InvertedTable->NextEntrySEHandlerTableEncoded,
568 (InvertedTable->Count - Index) *
sizeof(RTL_INVERTED_FUNCTION_TABLE_ENTRY));
572 RtlCaptureImageExceptionValues(ImageBase, &ptr, &count);
573 if (IsWin8OrGreater) {
577 entry->SEHandlerCount = count;
578 entry->ImageBase = ImageBase;
579 entry->ImageSize = SizeOfImage;
582 if (Index) InvertedTable->Entries[Index - 1].EntrySEHandlerTableEncoded = RtlEncodeSystemPointer(
reinterpret_cast<PVOID
>(ptr));
583 else InvertedTable->NextEntrySEHandlerTableEncoded =
reinterpret_cast<ULONG
>(RtlEncodeSystemPointer(
reinterpret_cast<PVOID
>(ptr)));
584 InvertedTable->Entries[Index].ImageBase = ImageBase;
585 InvertedTable->Entries[Index].ImageSize = SizeOfImage;
586 InvertedTable->Entries[Index].SEHandlerCount = count;
589 std::cout <<
"Exception table was set! " << std::endl;
591 ++InvertedTable->Count;
596 static NTSTATUS NTAPI RtlInsertInvertedFunctionTable(
597 _In_ PVOID BaseAddress,
603 std::cout <<
"Exception table not found! " << std::endl;
605 return STATUS_NOT_SUPPORTED;
608 std::cout <<
"Found exception table: " << std::hex << table << std::endl;
610 BOOL need_virtual_protect = RtlIsWindowsVersionOrGreater(6, 3, 0);
613 std::cout <<
"Need virtual protect: " << std::boolalpha << need_virtual_protect << std::endl;
617 if (need_virtual_protect) {
618 status = RtlProtectMrdata(PAGE_READWRITE, table);
621 RtlpInsertInvertedFunctionTable(table, BaseAddress, ImageSize);
622 if (need_virtual_protect) {
623 status = RtlProtectMrdata(PAGE_READONLY, table);
628 STATUS_NO_MEMORY : STATUS_SUCCESS;
634 if (moduleSize == 0) {
635 const DWORD img_size =
get_image_size(
reinterpret_cast<BYTE*
>(modulePtr));
639 moduleSize = img_size;
641 return NT_SUCCESS(details::RtlInsertInvertedFunctionTable(modulePtr, (ULONG)moduleSize)) ? true :
false;
#define RTL_VERIFY_FLAGS_MAJOR_VERSION
#define RTL_VERIFY_FLAGS_BUILD_NUMBERS
#define RTL_VERIFY_FLAGS_MINOR_VERSION
#define RtlFindMemoryBlockFromModuleSection__leave
Functions related to Exceptions Table.
struct details::_NtVersion * PNtVersion
RTL_INVERTED_FUNCTION_TABLE_WIN7_32 RTL_INVERTED_FUNCTION_TABLE
struct details::_LDR_DATA_TABLE_ENTRY_WIN8 LDR_DATA_TABLE_ENTRY_WIN8
struct details::_LDR_DDAG_NODE_WIN8 LDR_DDAG_NODE_WIN8
_RTL_INVERTED_FUNCTION_TABLE_ENTRY_WIN7_32 RTL_INVERTED_FUNCTION_TABLE_ENTRY
struct details::_RTL_INVERTED_FUNCTION_TABLE_WIN7_32 RTL_INVERTED_FUNCTION_TABLE_WIN7_32
RTL_INVERTED_FUNCTION_TABLE_WIN7_32 * PRTL_INVERTED_FUNCTION_TABLE
struct details::_SEARCH_CONTEXT * PSEARCH_CONTEXT
struct details::_RTL_INVERTED_FUNCTION_TABLE_ENTRY_WIN7_32 * PRTL_INVERTED_FUNCTION_TABLE_ENTRY_WIN7_32
PECONV_TRY_EXCEPT_BLOCK_END status
struct details::_RTL_INVERTED_FUNCTION_TABLE_ENTRY_WIN8_PLUS_32 RTL_INVERTED_FUNCTION_TABLE_ENTRY_WIN8_PLUS_32
struct details::_RTL_INVERTED_FUNCTION_TABLE_ENTRY_WIN7_32 RTL_INVERTED_FUNCTION_TABLE_ENTRY_WIN7_32
struct details::_RTL_INVERTED_FUNCTION_TABLE_ENTRY_WIN8_PLUS_32 * PRTL_INVERTED_FUNCTION_TABLE_ENTRY_WIN8_PLUS_32
struct details::_RTL_INVERTED_FUNCTION_TABLE_64 RTL_INVERTED_FUNCTION_TABLE_64
RTL_INVERTED_FUNCTION_TABLE_WIN7_32 _RTL_INVERTED_FUNCTION_TABLE
struct details::_RTL_INVERTED_FUNCTION_TABLE_ENTRY_64 * PRTL_INVERTED_FUNCTION_TABLE_ENTRY_64
struct details::_RTL_INVERTED_FUNCTION_TABLE_64 * PRTL_INVERTED_FUNCTION_TABLE_64
struct details::_LDR_DATA_TABLE_ENTRY_WIN8 * PLDR_DATA_TABLE_ENTRY_WIN8
struct details::_RTL_INVERTED_FUNCTION_TABLE_ENTRY_64 RTL_INVERTED_FUNCTION_TABLE_ENTRY_64
_RTL_INVERTED_FUNCTION_TABLE_ENTRY_WIN7_32 _RTL_INVERTED_FUNCTION_TABLE_ENTRY
struct details::_RTL_INVERTED_FUNCTION_TABLE_WIN7_32 * PRTL_INVERTED_FUNCTION_TABLE_WIN7_32
struct details::_LDR_DDAG_NODE_WIN8 * PLDR_DDAG_NODE_WIN8
struct details::_NtVersion NtVersion
struct details::_SEARCH_CONTEXT SEARCH_CONTEXT
_RTL_INVERTED_FUNCTION_TABLE_ENTRY_WIN7_32 * PRTL_INVERTED_FUNCTION_TABLE_ENTRY
DWORD get_image_size(IN const BYTE *payload)
bool setup_exceptions(IN BYTE *modulePtr, IN size_t moduleSize)
Wrappers over various fields in the PE header. Read, write, parse PE headers.
LIST_ENTRY InInitializationOrderLinks
ULONG ProcessAttachFailed
RTL_BALANCED_NODE MappingInfoIndexNode
UNICODE_STRING BaseDllName
ULONG CompatDatabaseProcessed
ULONG ProcessAttachCalled
PLDR_DDAG_NODE_WIN8 DdagNode
ULONG TelemetryEntryProcessed
PACTIVATION_CONTEXT EntryPointActivationContext
ULONG ProcessStaticImport
LIST_ENTRY InLoadOrderLinks
RTL_BALANCED_NODE BaseAddressIndexNode
LIST_ENTRY NodeModuleLink
ULONG LoadNotificationsSent
ULONG CorDeferredValidate
LDR_DLL_LOAD_REASON LoadReason
LIST_ENTRY InProgressLinks
UNICODE_STRING FullDllName
LIST_ENTRY InMemoryOrderLinks
PLDRP_CSLIST_DEPENDENT Dependencies
PLDRP_CSLIST_INCOMMING IncomingDependencies
PLDR_SERVICE_TAG_RECORD ServiceTagList
SINGLE_LIST_ENTRY CondenseLink
RTL_INVERTED_FUNCTION_TABLE_ENTRY_64 Entries[0x200]
ULONG ExceptionDirectorySize
PIMAGE_RUNTIME_FUNCTION_ENTRY ExceptionDirectory
PVOID EntrySEHandlerTableEncoded
PVOID EntrySEHandlerTableEncoded
ULONG NextEntrySEHandlerTableEncoded
RTL_INVERTED_FUNCTION_TABLE_ENTRY_WIN7_32 Entries[0x200]
Miscellaneous utility functions.
#define PECONV_FORCEINLINE
#define PECONV_TRY_EXCEPT_BLOCK_END
#define PECONV_TRY_EXCEPT_BLOCK_START