libPeConv
A library to load, manipulate, dump PE files.
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
exceptions_parser.cpp
Go to the documentation of this file.
1// Original RtlInsertInvertedFunctionTable implementation: https://github.com/bb107/MemoryModulePP
2
4
6#include "peconv/util.h"
7#include "ntddk.h"
8
9#ifdef _DEBUG
10#include <iostream>
11#endif
12
13#ifndef min
14#define min(a,b) (((a) < (b)) ? (a) : (b))
15#endif
16
17namespace details {
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
22 typedef struct _SEARCH_CONTEXT {
23
24 IN LPBYTE SearchPattern;
25 IN SIZE_T PatternSize;
26
27 OUT LPBYTE Result;
29
31
37
51
52 /* The correct data structure for Win8+ 32 should be this.*/
59
66
74
75#ifdef _WIN64
78#else
81#endif
82
83 typedef struct _LDR_DDAG_NODE_WIN8 {
84 LIST_ENTRY Modules; //0x0
85 PLDR_SERVICE_TAG_RECORD ServiceTagList; //0x10
86 ULONG LoadCount; //0x18
87 ULONG ReferenceCount; //0x1c
88 ULONG DependencyCount; //0x20
89 PLDRP_CSLIST_DEPENDENT Dependencies; //0x28
90 PLDRP_CSLIST_INCOMMING IncomingDependencies; //0x30
91 LDR_DDAG_STATE State; //0x38
92 SINGLE_LIST_ENTRY CondenseLink; //0x40
93 ULONG PreorderNumber; //0x48
94 ULONG LowestLink; //0x4c
96
97 //6.2.9200 Windows 8 | 2012 RTM
99 LIST_ENTRY InLoadOrderLinks; //0x0
100 LIST_ENTRY InMemoryOrderLinks; //0x10
101 union {
102 LIST_ENTRY InInitializationOrderLinks; //0x20
103 LIST_ENTRY InProgressLinks; //0x20
104 };
105 PVOID DllBase; //0x30
106 PVOID EntryPoint; //0x38
107 ULONG SizeOfImage; //0x40
108 UNICODE_STRING FullDllName; //0x48
109 UNICODE_STRING BaseDllName; //0x58
110 union {
111 UCHAR FlagGroup[4]; //0x68
112 ULONG Flags; //0x68
113 struct {
114 ULONG PackagedBinary : 1; //0x68
115 ULONG MarkedForRemoval : 1; //0x68
116 ULONG ImageDll : 1; //0x68
117 ULONG LoadNotificationsSent : 1; //0x68
118 ULONG TelemetryEntryProcessed : 1; //0x68
119 ULONG ProcessStaticImport : 1; //0x68
120 ULONG InLegacyLists : 1; //0x68
121 ULONG InIndexes : 1; //0x68
122 ULONG ShimDll : 1; //0x68
123 ULONG InExceptionTable : 1; //0x68
124 ULONG ReservedFlags1 : 2; //0x68
125 ULONG LoadInProgress : 1; //0x68
126 ULONG ReservedFlags2 : 1; //0x68
127 ULONG EntryProcessed : 1; //0x68
128 ULONG ReservedFlags3 : 3; //0x68
129 ULONG DontCallForThreads : 1; //0x68
130 ULONG ProcessAttachCalled : 1; //0x68
131 ULONG ProcessAttachFailed : 1; //0x68
132 ULONG CorDeferredValidate : 1; //0x68
133 ULONG CorImage : 1; //0x68
134 ULONG DontRelocate : 1; //0x68
135 ULONG CorILOnly : 1; //0x68
136 ULONG ReservedFlags5 : 3; //0x68
137 ULONG Redirected : 1; //0x68
138 ULONG ReservedFlags6 : 2; //0x68
139 ULONG CompatDatabaseProcessed : 1; //0x68
140 };
141 };
142 USHORT ObsoleteLoadCount; //0x6c
143 USHORT TlsIndex; //0x6e
144 LIST_ENTRY HashLinks; //0x70
145 ULONG TimeDateStamp; //0x80
146 PACTIVATION_CONTEXT EntryPointActivationContext; //0x88
147 PVOID PatchInformation; //0x90
149 LIST_ENTRY NodeModuleLink; //0xa0
150 PVOID SnapContext; //0xb0
151 PVOID ParentDllBase; //0xb8
152 PVOID SwitchBackContext; //0xc0
153 RTL_BALANCED_NODE BaseAddressIndexNode; //0xc8
154 RTL_BALANCED_NODE MappingInfoIndexNode; //0xe0
155 ULONGLONG OriginalBase; //0xf8
156 LARGE_INTEGER LoadTime; //0x100
157 ULONG BaseNameHashValue; //0x108
158 LDR_DLL_LOAD_REASON LoadReason; //0x10c
160
161 static void NTAPI RtlCurrentVersion(_Out_ PNtVersion pVersion) {
162 RtlGetNtVersionNumbers(
163 &pVersion->MajorVersion,
164 &pVersion->MinorVersion,
165 &pVersion->BuildNumber
166 );
167 }
168
169 static BOOL NTAPI RtlIsWindowsVersionOrGreater(
170 _In_ ULONG MajorVersion,
171 _In_ ULONG MinorVersion,
172 _In_ ULONG BuildNumber
173 ) {
174 NtVersion version = { 0 };
175 RtlCurrentVersion(&version);
176 if (version.MajorVersion == MajorVersion) {
177 if (version.MinorVersion == MinorVersion) return version.BuildNumber >= BuildNumber;
178 else return (version.MinorVersion > MinorVersion);
179 }
180 else return version.MajorVersion > MajorVersion;
181 }
182
183 static BOOL NTAPI RtlVerifyVersion(
184 _In_ ULONG MajorVersion,
185 _In_ ULONG MinorVersion,
186 _In_ ULONG BuildNumber,
187 _In_ BYTE Flags
188 ) {
189 NtVersion version = { 0 };
190 RtlCurrentVersion(&version);
191 if (version.MajorVersion == MajorVersion &&
192 ((Flags & RTL_VERIFY_FLAGS_MINOR_VERSION) ? version.MinorVersion == MinorVersion : true) &&
193 ((Flags & RTL_VERIFY_FLAGS_BUILD_NUMBERS) ? version.BuildNumber == BuildNumber : true))return TRUE;
194 return FALSE;
195 }
196#ifndef _WIN64
197 static int NTAPI RtlCaptureImageExceptionValues(PVOID BaseAddress, PDWORD SEHandlerTable, PDWORD SEHandlerCount) {
198 PIMAGE_LOAD_CONFIG_DIRECTORY pLoadConfigDirectory = nullptr;
199 PIMAGE_COR20_HEADER pCor20 = nullptr;
200 ULONG Size = 0;
201
202 auto hdrs = reinterpret_cast<PIMAGE_NT_HEADERS>(RtlImageNtHeader(BaseAddress));
203 //check if no seh
204 if (hdrs->OptionalHeader.DllCharacteristics & IMAGE_DLLCHARACTERISTICS_NO_SEH) {
205 *SEHandlerTable = *SEHandlerCount = -1;
206 return 0;
207 }
208
209 //get seh table and count
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;
216 }
217 }
218 }
219
220 //is .net core ?
221 pCor20 = (decltype(pCor20))RtlImageDirectoryEntryToData(BaseAddress, TRUE, IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR, &Size);
222 *SEHandlerTable = *SEHandlerCount = ((pCor20 && pCor20->Flags & 1) ? -1 : 0);
223 return 0;
224 }
225#endif
226
227 static PECONV_FORCEINLINE bool IsModuleUnloaded(PLDR_DATA_TABLE_ENTRY entry) {
228 if (RtlIsWindowsVersionOrGreater(6, 2, 0)) { // Windows 8+
229 return PLDR_DATA_TABLE_ENTRY_WIN8(entry)->DdagNode->State == LdrModulesUnloaded;
230 }
231 else {
232 return entry->DllBase == nullptr;
233 }
234 }
235
236 static NTSTATUS NTAPI RtlFindMemoryBlockFromModuleSection(
237 _In_ HMODULE ModuleHandle,
238 _In_ LPCSTR SectionName,
239 _Inout_ PSEARCH_CONTEXT SearchContext) {
240
241 NTSTATUS status = STATUS_SUCCESS;
242
243#ifdef _MSC_VER
244#define RtlFindMemoryBlockFromModuleSection__leave __leave
245#else
246#define RtlFindMemoryBlockFromModuleSection__leave return status
247#endif
248
249#ifdef _DEBUG
250 std::cout << "Searching in section " << SectionName << " in module " << ModuleHandle << std::endl;
251#endif
252
254
255 //
256 // checks if no search pattern and length are provided
257 //
258
259 if (!SearchContext->SearchPattern || !SearchContext->PatternSize) {
260 SearchContext->Result = nullptr;
261 SearchContext->MemoryBlockSize = 0;
262 status = STATUS_INVALID_PARAMETER;
264 }
265
266 if (SearchContext->Result) {
267 ++SearchContext->Result;
268 --SearchContext->MemoryBlockSize;
269 }
270 else {
271
272 //
273 // if it is the first search, find the length and start address of the specified section
274 //
275
276 auto headers = reinterpret_cast<PIMAGE_NT_HEADERS>(RtlImageNtHeader(ModuleHandle));
277 PIMAGE_SECTION_HEADER section = nullptr;
278
279 if (headers) {
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;
285 break;
286 }
287
288 ++section;
289 }
290
291 if (!SearchContext->Result || !SearchContext->MemoryBlockSize || SearchContext->MemoryBlockSize < SearchContext->PatternSize) {
292 SearchContext->Result = nullptr;
293 SearchContext->MemoryBlockSize = 0;
294 status = STATUS_NOT_FOUND;
296 }
297 }
298 else {
299 status = STATUS_INVALID_PARAMETER_1;
301 }
302 }
303
304 //
305 // perform a linear search on the pattern
306 //
307
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) {
312 }
313
314 ++SearchContext->Result;
315 --SearchContext->MemoryBlockSize;
316 }
317
318 //
319 // if the search fails, clear the output parameters
320 //
321
322 SearchContext->Result = nullptr;
323 SearchContext->MemoryBlockSize = 0;
324 status = STATUS_NOT_FOUND;
325 }
327 status = GetExceptionCode();
328 }
329
330 return status;
331 }
332
333 static NTSTATUS RtlProtectMrdata(_In_ ULONG Protect, PRTL_INVERTED_FUNCTION_TABLE mrdata) {
334 static PVOID MrdataBase = nullptr;
335 static SIZE_T size = 0;
336 NTSTATUS status;
337 PVOID tmp;
338 SIZE_T tmp_len;
339 ULONG old;
340
341 if (!MrdataBase) {
342 MEMORY_BASIC_INFORMATION mbi= { 0 };
343 status = NtQueryVirtualMemory(NtCurrentProcess(), mrdata, MemoryBasicInformation, &mbi, sizeof(mbi), nullptr);
344 if (!NT_SUCCESS(status))return status;
345 MrdataBase = mbi.BaseAddress;
346 size = mbi.RegionSize;
347 }
348
349 tmp = MrdataBase;
350 tmp_len = size;
351 return NtProtectVirtualMemory(NtCurrentProcess(), &tmp, &tmp_len, Protect, &old);
352 }
353
354 static PVOID RtlFindInvertedFunctionTable() {
355#ifdef _WIN64
356 // _RTL_INVERTED_FUNCTION_TABLE x64
357// Count +0x0 ????????
358// MaxCount +0x4 0x00000200
359// Epoch +0x8 ????????
360// OverFlow +0xc 0x00000000
361// _RTL_INVERTED_FUNCTION_TABLE_ENTRY[0] +0x10 ntdll.dll(win10) or The smallest base module
362// ExceptionDirectory +0x10 ++++++++
363// ImageBase +0x18 ++++++++
364// ImageSize +0x20 ++++++++
365// ExceptionDirectorySize +0x24 ++++++++
366// _RTL_INVERTED_FUNCTION_TABLE_ENTRY[1] ... ...
367// ......
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;
375 SEARCH_CONTEXT SearchContext= { 0 };
376 SearchContext.SearchPattern = reinterpret_cast<LPBYTE>(&entry);
377 SearchContext.PatternSize = sizeof(entry);
378 RtlSecureZeroMemory(&entry, sizeof(entry));
379
380 // Windows 8
381 if (RtlVerifyVersion(6, 2, 0, RTL_VERIFY_FLAGS_MAJOR_VERSION | RTL_VERIFY_FLAGS_MINOR_VERSION)) {
382 hModule = hNtdll;
383 ModuleHeaders = NtdllHeaders;
384 //lpSectionName = ".data";
385 }
386 //Windows 8.1 ~ Windows 10 (11)
387 else if (RtlIsWindowsVersionOrGreater(6, 3, 0)) {
388 hModule = hNtdll;
389 ModuleHeaders = NtdllHeaders;
390 lpSectionName = ".mrdata";
391 }
392 else { //Windows 7 and below
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
404 );
405 }
406 if (hModule) ModuleHeaders = reinterpret_cast<PIMAGE_NT_HEADERS>(RtlImageNtHeader(hModule));
407 }
408 if (!hModule || !ModuleHeaders || !hNtdll || !NtdllHeaders) return nullptr;
409 dir = &ModuleHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXCEPTION];
410
411 entry.ExceptionDirectory = dir->Size ?
412 reinterpret_cast<PIMAGE_RUNTIME_FUNCTION_ENTRY>(
413 reinterpret_cast<size_t>(hModule) + dir->VirtualAddress
414 ) : nullptr;
415 entry.ImageBase = reinterpret_cast<PVOID>(hModule);
416 entry.ImageSize = ModuleHeaders->OptionalHeader.SizeOfImage;
417 entry.ExceptionDirectorySize = dir->Size;
418
419 while (NT_SUCCESS(RtlFindMemoryBlockFromModuleSection(hNtdll, lpSectionName, &SearchContext))) {
420 auto tab = reinterpret_cast<PRTL_INVERTED_FUNCTION_TABLE_64>(SearchContext.Result - 0x10);
421 if (RtlIsWindowsVersionOrGreater(6, 2, 0) && tab->MaxCount == 0x200 && !tab->Overflow) return tab;
422 else if (tab->MaxCount == 0x200 && !tab->Epoch) return tab;
423 }
424
425 return nullptr;
426#else
427 // _RTL_INVERTED_FUNCTION_TABLE x86
428// Count +0x0 ????????
429// MaxCount +0x4 0x00000200
430// Overflow +0x8 0x00000000(Win7) ????????(Win10)
431// NextEntrySEHandlerTableEncoded +0xc 0x00000000(Win10) ++++++++(Win7)
432// _RTL_INVERTED_FUNCTION_TABLE_ENTRY[0] +0x10 ntdll.dll(win10) or The smallest base module
433// ImageBase +0x10 ++++++++
434// ImageSize +0x14 ++++++++
435// SEHandlerCount +0x18 ++++++++
436// NextEntrySEHandlerTableEncoded +0x1c ++++++++(Win10) ????????(Win7)
437// _RTL_INVERTED_FUNCTION_TABLE_ENTRY[1] ... ...
438// ......
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";
445 SEARCH_CONTEXT SearchContext = { 0 };
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;
452 BYTE Offset = 0x20; //sizeof(_RTL_INVERTED_FUNCTION_TABLE_ENTRY)*2
453
454 if (RtlIsWindowsVersionOrGreater(6, 3, 0)) lpSectionName = ".mrdata";
455 else if (!RtlIsWindowsVersionOrGreater(6, 2, 0)) Offset = 0xC;
456
457 while (ListEntry != ListHead) {
458 CurEntry = CONTAINING_RECORD(ListEntry, LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks);
459 ListEntry = ListEntry->Flink;
460 if (IsModuleUnloaded(CurEntry))
461 continue; //skip unloaded module
462 if (CurEntry->DllBase == hNtdll && Offset == 0x20)
463 continue; //Win10 skip first entry, if the base of ntdll is smallest.
464
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
470 );
471 }
472 ModuleHeaders = reinterpret_cast<PIMAGE_NT_HEADERS>(RtlImageNtHeader(hModule));
473 if (!hModule || !ModuleHeaders || !hNtdll || !NtdllHeaders) return nullptr;
474
475 RtlCaptureImageExceptionValues(hModule, &SEHTable, &SEHCount);
476
477 if (RtlIsWindowsVersionOrGreater(6, 2, 0)) {
478 //memory layout is same as x64
479 auto entry2 = reinterpret_cast<PRTL_INVERTED_FUNCTION_TABLE_ENTRY_WIN8_PLUS_32>(&entry);
480 entry2->EntrySEHandlerTableEncoded = RtlEncodeSystemPointer(reinterpret_cast<PVOID>(SEHTable));
481 entry2->ImageBase = reinterpret_cast<PVOID>(hModule);
482 entry2->ImageSize = ModuleHeaders->OptionalHeader.SizeOfImage;
483 entry2->SEHandlerCount = SEHCount;
484 }
485 else {
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;
490 }
491
492 while (NT_SUCCESS(RtlFindMemoryBlockFromModuleSection(hNtdll, lpSectionName, &SearchContext))) {
493 PRTL_INVERTED_FUNCTION_TABLE_WIN7_32 tab = reinterpret_cast<decltype(tab)>(SearchContext.Result - Offset);
494
495 //Note: Same memory layout for RTL_INVERTED_FUNCTION_TABLE_ENTRY in Windows 8 x86 and x64.
496 if (RtlIsWindowsVersionOrGreater(6, 2, 0) && tab->MaxCount == 0x200 && !tab->NextEntrySEHandlerTableEncoded) return tab;
497 else if (tab->MaxCount == 0x200 && !tab->Overflow) return tab;
498 }
499 return nullptr;
500#endif
501 }
502
503 static VOID RtlpInsertInvertedFunctionTable(
504 _In_ PRTL_INVERTED_FUNCTION_TABLE InvertedTable,
505 _In_ PVOID ImageBase,
506 _In_ ULONG SizeOfImage) {
507#ifdef _WIN64
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);
513
514 if (CurrentSize != InvertedTable->MaxCount) {
515 if (CurrentSize != 0) {
516 while (Index < CurrentSize) {
517 if (ImageBase < InvertedTable->Entries[Index].ImageBase) break;
518 ++Index;
519 }
520
521
522 if (Index != CurrentSize) {
523 RtlMoveMemory(&InvertedTable->Entries[Index + 1],
524 &InvertedTable->Entries[Index],
525 (CurrentSize - Index) * sizeof(RTL_INVERTED_FUNCTION_TABLE_ENTRY));
526 }
527 }
528
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++;
535#ifdef _DEBUG
536 std::cout << "Exception table was set! " << std::endl;
537#endif
538 }
539 else {
540 IsWin8OrGreater ? (InvertedTable->Overflow = TRUE) : (InvertedTable->Epoch = TRUE);
541 }
542
543#else
544 DWORD ptr = 0, count = 0;
545 BOOL IsWin8OrGreater = RtlIsWindowsVersionOrGreater(6, 2, 0);
546 ULONG Index = IsWin8OrGreater ? 1 : 0;
547
548 if (InvertedTable->Count == InvertedTable->MaxCount) {
549 if (IsWin8OrGreater)InvertedTable->NextEntrySEHandlerTableEncoded = TRUE;
550 else InvertedTable->Overflow = TRUE;
551 return;
552 }
553 while (Index < InvertedTable->Count) {
554 if (ImageBase < (IsWin8OrGreater ?
555 (reinterpret_cast<PRTL_INVERTED_FUNCTION_TABLE_ENTRY_64>(&InvertedTable->Entries[Index]))->ImageBase :
556 InvertedTable->Entries[Index].ImageBase))
557 break;
558 Index++;
559 }
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));
564 }
565 else {
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));
569 }
570 }
571
572 RtlCaptureImageExceptionValues(ImageBase, &ptr, &count);
573 if (IsWin8OrGreater) {
574 //memory layout is same as x64
575 auto entry = reinterpret_cast<PRTL_INVERTED_FUNCTION_TABLE_ENTRY_WIN8_PLUS_32>(&InvertedTable->Entries[Index]);
576 entry->EntrySEHandlerTableEncoded = RtlEncodeSystemPointer(reinterpret_cast<PVOID>(ptr));
577 entry->SEHandlerCount = count;
578 entry->ImageBase = ImageBase;
579 entry->ImageSize = SizeOfImage;
580 }
581 else {
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;
587 }
588#ifdef _DEBUG
589 std::cout << "Exception table was set! " << std::endl;
590#endif
591 ++InvertedTable->Count;
592#endif
593 return;
594 }
595
596 static NTSTATUS NTAPI RtlInsertInvertedFunctionTable(
597 _In_ PVOID BaseAddress,
598 _In_ ULONG ImageSize
599 ) {
600 auto table = reinterpret_cast<PRTL_INVERTED_FUNCTION_TABLE>(RtlFindInvertedFunctionTable());
601 if (!table) {
602#ifdef _DEBUG
603 std::cout << "Exception table not found! " << std::endl;
604#endif
605 return STATUS_NOT_SUPPORTED;
606 }
607#ifdef _DEBUG
608 std::cout << "Found exception table: " << std::hex << table << std::endl;
609#endif
610 BOOL need_virtual_protect = RtlIsWindowsVersionOrGreater(6, 3, 0);
611 // Windows 8.1 and above require to set PAGE_READWRITE protection
612#ifdef _DEBUG
613 std::cout << "Need virtual protect: " << std::boolalpha << need_virtual_protect << std::endl;
614#endif
615 NTSTATUS status;
616
617 if (need_virtual_protect) {
618 status = RtlProtectMrdata(PAGE_READWRITE, table);
619 if (!NT_SUCCESS(status))return status;
620 }
621 RtlpInsertInvertedFunctionTable(table, BaseAddress, ImageSize);
622 if (need_virtual_protect) {
623 status = RtlProtectMrdata(PAGE_READONLY, table);
624 if (!NT_SUCCESS(status))return status;
625 }
626 // Windows 8+ versons have different structure than Windows 7 and below
627 return (RtlIsWindowsVersionOrGreater(6, 2, 0) ? PRTL_INVERTED_FUNCTION_TABLE_64(table)->Overflow : PRTL_INVERTED_FUNCTION_TABLE_WIN7_32(table)->Overflow) ?
628 STATUS_NO_MEMORY : STATUS_SUCCESS;
629 }
630}
631
632bool peconv::setup_exceptions(IN BYTE* modulePtr, IN size_t moduleSize)
633{
634 if (moduleSize == 0) {
635 const DWORD img_size = get_image_size(reinterpret_cast<BYTE*>(modulePtr));
636 if (!img_size) {
637 return false; // invalid image
638 }
639 moduleSize = img_size;
640 }
641 return NT_SUCCESS(details::RtlInsertInvertedFunctionTable(modulePtr, (ULONG)moduleSize)) ? true : false;
642}
#define RTL_VERIFY_FLAGS_MAJOR_VERSION
#define RTL_VERIFY_FLAGS_BUILD_NUMBERS
#define RTL_VERIFY_FLAGS_MINOR_VERSION
return status
#define min(a, b)
#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.
PLDRP_CSLIST_DEPENDENT Dependencies
PLDRP_CSLIST_INCOMMING IncomingDependencies
PLDR_SERVICE_TAG_RECORD ServiceTagList
RTL_INVERTED_FUNCTION_TABLE_ENTRY_64 Entries[0x200]
RTL_INVERTED_FUNCTION_TABLE_ENTRY_WIN7_32 Entries[0x200]
Miscellaneous utility functions.
#define PECONV_FORCEINLINE
Definition util.h:16
#define PECONV_TRY_EXCEPT_BLOCK_END
Definition util.h:18
#define PECONV_TRY_EXCEPT_BLOCK_START
Definition util.h:17