libPeConv
A library to load, manipulate, dump PE files.
Loading...
Searching...
No Matches
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#include "peconv/logger.h"
10
11#ifndef min
12#define min(a,b) (((a) < (b)) ? (a) : (b))
13#endif
14
15namespace peconv {
16
17 #define RTL_VERIFY_FLAGS_MAJOR_VERSION 0
18 #define RTL_VERIFY_FLAGS_MINOR_VERSION 1
19 #define RTL_VERIFY_FLAGS_BUILD_NUMBERS 2
20 #define RTL_VERIFY_FLAGS_DEFAULT RTL_VERIFY_FLAGS_MAJOR_VERSION|RTL_VERIFY_FLAGS_MINOR_VERSION|RTL_VERIFY_FLAGS_BUILD_NUMBERS
21
22 typedef struct _SEARCH_CONTEXT {
23
24 IN LPBYTE SearchPattern;
25 IN SIZE_T PatternSize;
26
27 OUT LPBYTE Result;
29
31
32 typedef struct _NtVersion {
37
39 PIMAGE_RUNTIME_FUNCTION_ENTRY ExceptionDirectory;
40 PVOID ImageBase;
41 ULONG ImageSize;
45 ULONG Count;
46 ULONG MaxCount;
47 ULONG Epoch;
48 ULONG Overflow;
51
52 /* The correct data structure for Win8+ 32 should be this.*/
55 PVOID ImageBase;
56 ULONG ImageSize;
59
61 PVOID ImageBase;
62 ULONG ImageSize;
66
68 ULONG Count;
69 ULONG MaxCount;
70 ULONG Overflow;
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 LOG_DEBUG("Searching in section %s in module %p.", SectionName, ModuleHandle);
250
252
253 //
254 // checks if no search pattern and length are provided
255 //
256
257 if (!SearchContext->SearchPattern || !SearchContext->PatternSize) {
258 SearchContext->Result = nullptr;
259 SearchContext->MemoryBlockSize = 0;
260 status = STATUS_INVALID_PARAMETER;
262 }
263
264 if (SearchContext->Result) {
265 ++SearchContext->Result;
266 --SearchContext->MemoryBlockSize;
267 }
268 else {
269
270 //
271 // if it is the first search, find the length and start address of the specified section
272 //
273
274 auto headers = reinterpret_cast<PIMAGE_NT_HEADERS>(RtlImageNtHeader(ModuleHandle));
275 PIMAGE_SECTION_HEADER section = nullptr;
276
277 if (headers) {
278 section = IMAGE_FIRST_SECTION(headers);
279 for (WORD i = 0; i < headers->FileHeader.NumberOfSections; ++i) {
280 if (!_strnicmp(SectionName, reinterpret_cast<LPCSTR>(section->Name), 8)) {
281 SearchContext->Result = reinterpret_cast<LPBYTE>(ModuleHandle) + section->VirtualAddress;
282 SearchContext->MemoryBlockSize = section->Misc.VirtualSize;
283 break;
284 }
285
286 ++section;
287 }
288
289 if (!SearchContext->Result || !SearchContext->MemoryBlockSize || SearchContext->MemoryBlockSize < SearchContext->PatternSize) {
290 SearchContext->Result = nullptr;
291 SearchContext->MemoryBlockSize = 0;
292 status = STATUS_NOT_FOUND;
294 }
295 }
296 else {
297 status = STATUS_INVALID_PARAMETER_1;
299 }
300 }
301
302 //
303 // perform a linear search on the pattern
304 //
305
306 LPBYTE end = SearchContext->Result + SearchContext->MemoryBlockSize - SearchContext->PatternSize;
307 while (SearchContext->Result <= end) {
308 if (RtlCompareMemory(SearchContext->SearchPattern, SearchContext->Result, SearchContext->PatternSize) == SearchContext->PatternSize) {
310 }
311
312 ++SearchContext->Result;
313 --SearchContext->MemoryBlockSize;
314 }
315
316 //
317 // if the search fails, clear the output parameters
318 //
319
320 SearchContext->Result = nullptr;
321 SearchContext->MemoryBlockSize = 0;
322 status = STATUS_NOT_FOUND;
323 }
325 status = GetExceptionCode();
326 }
327
328 return status;
329 }
330
331 static NTSTATUS RtlProtectMrdata(_In_ ULONG Protect, PRTL_INVERTED_FUNCTION_TABLE mrdata) {
332 static PVOID MrdataBase = nullptr;
333 static SIZE_T size = 0;
334 NTSTATUS status;
335 PVOID tmp;
336 SIZE_T tmp_len;
337 ULONG old;
338
339 if (!MrdataBase) {
340 MEMORY_BASIC_INFORMATION mbi= { 0 };
341 status = NtQueryVirtualMemory(NtCurrentProcess(), mrdata, MemoryBasicInformation, &mbi, sizeof(mbi), nullptr);
342 if (!NT_SUCCESS(status))return status;
343 MrdataBase = mbi.BaseAddress;
344 size = mbi.RegionSize;
345 }
346
347 tmp = MrdataBase;
348 tmp_len = size;
349 return NtProtectVirtualMemory(NtCurrentProcess(), &tmp, &tmp_len, Protect, &old);
350 }
351
352 static PVOID RtlFindInvertedFunctionTable() {
353#ifdef _WIN64
354 // _RTL_INVERTED_FUNCTION_TABLE x64
355// Count +0x0 ????????
356// MaxCount +0x4 0x00000200
357// Epoch +0x8 ????????
358// OverFlow +0xc 0x00000000
359// _RTL_INVERTED_FUNCTION_TABLE_ENTRY[0] +0x10 ntdll.dll(win10) or The smallest base module
360// ExceptionDirectory +0x10 ++++++++
361// ImageBase +0x18 ++++++++
362// ImageSize +0x20 ++++++++
363// ExceptionDirectorySize +0x24 ++++++++
364// _RTL_INVERTED_FUNCTION_TABLE_ENTRY[1] ... ...
365// ......
366 HMODULE hModule = nullptr, hNtdll = GetModuleHandleW(L"ntdll.dll");
367 LPCSTR lpSectionName = ".data";
368 if (!hNtdll) return nullptr;
369 auto NtdllHeaders = reinterpret_cast<PIMAGE_NT_HEADERS>(RtlImageNtHeader(hNtdll));
370 PIMAGE_NT_HEADERS ModuleHeaders = nullptr;
371 _RTL_INVERTED_FUNCTION_TABLE_ENTRY_64 entry = { 0 };
372 PIMAGE_DATA_DIRECTORY dir = nullptr;
373 SEARCH_CONTEXT SearchContext= { 0 };
374 SearchContext.SearchPattern = reinterpret_cast<LPBYTE>(&entry);
375 SearchContext.PatternSize = sizeof(entry);
376 RtlSecureZeroMemory(&entry, sizeof(entry));
377
378 // Windows 8
379 if (RtlVerifyVersion(6, 2, 0, RTL_VERIFY_FLAGS_MAJOR_VERSION | RTL_VERIFY_FLAGS_MINOR_VERSION)) {
380 hModule = hNtdll;
381 ModuleHeaders = NtdllHeaders;
382 //lpSectionName = ".data";
383 }
384 //Windows 8.1 ~ Windows 10 (11)
385 else if (RtlIsWindowsVersionOrGreater(6, 3, 0)) {
386 hModule = hNtdll;
387 ModuleHeaders = NtdllHeaders;
388 lpSectionName = ".mrdata";
389 }
390 else { //Windows 7 and below
391 PLIST_ENTRY ListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList,
392 ListEntry = ListHead->Flink;
393 PLDR_DATA_TABLE_ENTRY CurEntry = nullptr;
394 while (ListEntry != ListHead) {
395 CurEntry = CONTAINING_RECORD(ListEntry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
396 ListEntry = ListEntry->Flink;
397 hModule = reinterpret_cast<HMODULE>(
398 hModule ? reinterpret_cast<HMODULE>(min(
399 reinterpret_cast<uintptr_t>(hModule),
400 reinterpret_cast<uintptr_t>(CurEntry->DllBase)
401 )) : CurEntry->DllBase
402 );
403 }
404 if (hModule) ModuleHeaders = reinterpret_cast<PIMAGE_NT_HEADERS>(RtlImageNtHeader(hModule));
405 }
406 if (!hModule || !ModuleHeaders || !hNtdll || !NtdllHeaders) return nullptr;
407 dir = &ModuleHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXCEPTION];
408
409 entry.ExceptionDirectory = dir->Size ?
410 reinterpret_cast<PIMAGE_RUNTIME_FUNCTION_ENTRY>(
411 reinterpret_cast<size_t>(hModule) + dir->VirtualAddress
412 ) : nullptr;
413 entry.ImageBase = reinterpret_cast<PVOID>(hModule);
414 entry.ImageSize = ModuleHeaders->OptionalHeader.SizeOfImage;
415 entry.ExceptionDirectorySize = dir->Size;
416
417 while (NT_SUCCESS(RtlFindMemoryBlockFromModuleSection(hNtdll, lpSectionName, &SearchContext))) {
418 auto tab = reinterpret_cast<PRTL_INVERTED_FUNCTION_TABLE_64>(SearchContext.Result - 0x10);
419 if (RtlIsWindowsVersionOrGreater(6, 2, 0) && tab->MaxCount == 0x200 && !tab->Overflow) return tab;
420 else if (tab->MaxCount == 0x200 && !tab->Epoch) return tab;
421 }
422
423 return nullptr;
424#else
425// _RTL_INVERTED_FUNCTION_TABLE x86
426// Count +0x0 ????????
427// MaxCount +0x4 0x00000200
428// Overflow +0x8 0x00000000(Win7) ????????(Win10)
429// NextEntrySEHandlerTableEncoded +0xc 0x00000000(Win10) ++++++++(Win7)
430// _RTL_INVERTED_FUNCTION_TABLE_ENTRY[0] +0x10 ntdll.dll(win10) or The smallest base module
431// ImageBase +0x10 ++++++++
432// ImageSize +0x14 ++++++++
433// SEHandlerCount +0x18 ++++++++
434// NextEntrySEHandlerTableEncoded +0x1c ++++++++(Win10) ????????(Win7)
435// _RTL_INVERTED_FUNCTION_TABLE_ENTRY[1] ... ...
436// ......
437 HMODULE hModule = nullptr, hNtdll = GetModuleHandleW(L"ntdll.dll");
438 auto NtdllHeaders = reinterpret_cast<PIMAGE_NT_HEADERS>(RtlImageNtHeader(hNtdll));
439 PIMAGE_NT_HEADERS ModuleHeaders = nullptr;
440 _RTL_INVERTED_FUNCTION_TABLE_ENTRY_WIN7_32 entry = { 0 };
441 RtlSecureZeroMemory(&entry, sizeof(entry));
442 LPCSTR lpSectionName = ".data";
443 SEARCH_CONTEXT SearchContext = { 0 };
444 SearchContext.SearchPattern = reinterpret_cast<LPBYTE>(&entry);
445 SearchContext.PatternSize = sizeof(entry);
446 PLIST_ENTRY ListHead = &NtCurrentPeb()->Ldr->InMemoryOrderModuleList,
447 ListEntry = ListHead->Flink;
448 PLDR_DATA_TABLE_ENTRY CurEntry = nullptr;
449 DWORD SEHTable, SEHCount;
450 BYTE Offset = 0x20; //sizeof(_RTL_INVERTED_FUNCTION_TABLE_ENTRY)*2
451
452 if (RtlIsWindowsVersionOrGreater(6, 3, 0)) lpSectionName = ".mrdata";
453 else if (!RtlIsWindowsVersionOrGreater(6, 2, 0)) Offset = 0xC;
454
455 while (ListEntry != ListHead) {
456 CurEntry = CONTAINING_RECORD(ListEntry, LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks);
457 ListEntry = ListEntry->Flink;
458 if (IsModuleUnloaded(CurEntry))
459 continue; //skip unloaded module
460 if (CurEntry->DllBase == hNtdll && Offset == 0x20)
461 continue; //Win10 skip first entry, if the base of ntdll is smallest.
462
463 hModule = reinterpret_cast<HMODULE>(
464 hModule ? reinterpret_cast<HMODULE>(min(
465 reinterpret_cast<uintptr_t>(hModule),
466 reinterpret_cast<uintptr_t>(CurEntry->DllBase)
467 )) : CurEntry->DllBase
468 );
469 }
470 ModuleHeaders = reinterpret_cast<PIMAGE_NT_HEADERS>(RtlImageNtHeader(hModule));
471 if (!hModule || !ModuleHeaders || !hNtdll || !NtdllHeaders) return nullptr;
472
473 RtlCaptureImageExceptionValues(hModule, &SEHTable, &SEHCount);
474
475 if (RtlIsWindowsVersionOrGreater(6, 2, 0)) {
476 //memory layout is same as x64
477 auto entry2 = reinterpret_cast<PRTL_INVERTED_FUNCTION_TABLE_ENTRY_WIN8_PLUS_32>(&entry);
478 entry2->EntrySEHandlerTableEncoded = RtlEncodeSystemPointer(reinterpret_cast<PVOID>(SEHTable));
479 entry2->ImageBase = reinterpret_cast<PVOID>(hModule);
480 entry2->ImageSize = ModuleHeaders->OptionalHeader.SizeOfImage;
481 entry2->SEHandlerCount = SEHCount;
482 }
483 else {
484 entry.EntrySEHandlerTableEncoded = RtlEncodeSystemPointer(reinterpret_cast<PVOID>(SEHTable));
485 entry.ImageBase = reinterpret_cast<PVOID>(hModule);
486 entry.ImageSize = ModuleHeaders->OptionalHeader.SizeOfImage;
487 entry.SEHandlerCount = SEHCount;
488 }
489
490 while (NT_SUCCESS(RtlFindMemoryBlockFromModuleSection(hNtdll, lpSectionName, &SearchContext))) {
491 PRTL_INVERTED_FUNCTION_TABLE_WIN7_32 tab = reinterpret_cast<decltype(tab)>(SearchContext.Result - Offset);
492
493 //Note: Same memory layout for RTL_INVERTED_FUNCTION_TABLE_ENTRY in Windows 8 x86 and x64.
494 if (RtlIsWindowsVersionOrGreater(6, 2, 0) && tab->MaxCount == 0x200 && !tab->NextEntrySEHandlerTableEncoded) return tab;
495 else if (tab->MaxCount == 0x200 && !tab->Overflow) return tab;
496 }
497 return nullptr;
498#endif
499 }
500
501 static VOID RtlpInsertInvertedFunctionTable(
502 _In_ PRTL_INVERTED_FUNCTION_TABLE InvertedTable,
503 _In_ PVOID ImageBase,
504 _In_ ULONG SizeOfImage) {
505#ifdef _WIN64
506 ULONG CurrentSize = InvertedTable->Count;
507 PIMAGE_RUNTIME_FUNCTION_ENTRY FunctionTable = nullptr;
508 ULONG SizeOfTable = 0;
509 BOOL IsWin8OrGreater = RtlIsWindowsVersionOrGreater(6, 2, 0);
510 ULONG Index = static_cast<ULONG>(IsWin8OrGreater);
511
512 if (CurrentSize != InvertedTable->MaxCount) {
513 if (CurrentSize != 0) {
514 while (Index < CurrentSize) {
515 if (ImageBase < InvertedTable->Entries[Index].ImageBase) break;
516 ++Index;
517 }
518
519
520 if (Index != CurrentSize) {
521 RtlMoveMemory(&InvertedTable->Entries[Index + 1],
522 &InvertedTable->Entries[Index],
523 (CurrentSize - Index) * sizeof(RTL_INVERTED_FUNCTION_TABLE_ENTRY));
524 }
525 }
526
527 FunctionTable = reinterpret_cast<decltype(FunctionTable)>(RtlImageDirectoryEntryToData(ImageBase, TRUE, IMAGE_DIRECTORY_ENTRY_EXCEPTION, &SizeOfTable));
528 InvertedTable->Entries[Index].ExceptionDirectory = FunctionTable;
529 InvertedTable->Entries[Index].ImageBase = ImageBase;
530 InvertedTable->Entries[Index].ImageSize = SizeOfImage;
531 InvertedTable->Entries[Index].ExceptionDirectorySize = SizeOfTable;
532 InvertedTable->Count++;
533 LOG_INFO("Exception table was set.");
534 }
535 else {
536 IsWin8OrGreater ? (InvertedTable->Overflow = TRUE) : (InvertedTable->Epoch = TRUE);
537 }
538
539#else
540 DWORD ptr = 0, count = 0;
541 BOOL IsWin8OrGreater = RtlIsWindowsVersionOrGreater(6, 2, 0);
542 ULONG Index = IsWin8OrGreater ? 1 : 0;
543
544 if (InvertedTable->Count == InvertedTable->MaxCount) {
545 if (IsWin8OrGreater)InvertedTable->NextEntrySEHandlerTableEncoded = TRUE;
546 else InvertedTable->Overflow = TRUE;
547 return;
548 }
549 while (Index < InvertedTable->Count) {
550 if (ImageBase < (IsWin8OrGreater ?
551 (reinterpret_cast<PRTL_INVERTED_FUNCTION_TABLE_ENTRY_64>(&InvertedTable->Entries[Index]))->ImageBase :
552 InvertedTable->Entries[Index].ImageBase))
553 break;
554 Index++;
555 }
556 if (Index != InvertedTable->Count) {
557 if (IsWin8OrGreater) {
558 RtlMoveMemory(&InvertedTable->Entries[Index + 1], &InvertedTable->Entries[Index],
559 (InvertedTable->Count - Index) * sizeof(RTL_INVERTED_FUNCTION_TABLE_ENTRY));
560 }
561 else {
562 RtlMoveMemory(&InvertedTable->Entries[Index].EntrySEHandlerTableEncoded,
563 Index ? &InvertedTable->Entries[Index - 1].EntrySEHandlerTableEncoded : (PVOID)&InvertedTable->NextEntrySEHandlerTableEncoded,
564 (InvertedTable->Count - Index) * sizeof(RTL_INVERTED_FUNCTION_TABLE_ENTRY));
565 }
566 }
567
568 RtlCaptureImageExceptionValues(ImageBase, &ptr, &count);
569 if (IsWin8OrGreater) {
570 //memory layout is same as x64
571 auto entry = reinterpret_cast<PRTL_INVERTED_FUNCTION_TABLE_ENTRY_WIN8_PLUS_32>(&InvertedTable->Entries[Index]);
572 entry->EntrySEHandlerTableEncoded = RtlEncodeSystemPointer(reinterpret_cast<PVOID>(ptr));
573 entry->SEHandlerCount = count;
574 entry->ImageBase = ImageBase;
575 entry->ImageSize = SizeOfImage;
576 }
577 else {
578 if (Index) InvertedTable->Entries[Index - 1].EntrySEHandlerTableEncoded = RtlEncodeSystemPointer(reinterpret_cast<PVOID>(ptr));
579 else InvertedTable->NextEntrySEHandlerTableEncoded = reinterpret_cast<ULONG>(RtlEncodeSystemPointer(reinterpret_cast<PVOID>(ptr)));
580 InvertedTable->Entries[Index].ImageBase = ImageBase;
581 InvertedTable->Entries[Index].ImageSize = SizeOfImage;
582 InvertedTable->Entries[Index].SEHandlerCount = count;
583 }
584 LOG_DEBUG("Exception table was set.");
585 ++InvertedTable->Count;
586#endif
587 return;
588 }
589
590 static NTSTATUS NTAPI RtlInsertInvertedFunctionTable(
591 _In_ PVOID BaseAddress,
592 _In_ ULONG ImageSize
593 ) {
594 auto table = reinterpret_cast<PRTL_INVERTED_FUNCTION_TABLE>(RtlFindInvertedFunctionTable());
595 if (!table) {
596 LOG_INFO("Exception table not found.");
597 return STATUS_NOT_SUPPORTED;
598 }
599 LOG_INFO("Found exception table: %p.", table);
600 BOOL need_virtual_protect = RtlIsWindowsVersionOrGreater(6, 3, 0);
601 // Windows 8.1 and above require to set PAGE_READWRITE protection
602 LOG_DEBUG("Need virtual protect: %s.", need_virtual_protect ? "true" : "false");
603 NTSTATUS status;
604
605 if (need_virtual_protect) {
606 status = RtlProtectMrdata(PAGE_READWRITE, table);
607 if (!NT_SUCCESS(status))return status;
608 }
609 RtlpInsertInvertedFunctionTable(table, BaseAddress, ImageSize);
610 if (need_virtual_protect) {
611 status = RtlProtectMrdata(PAGE_READONLY, table);
612 if (!NT_SUCCESS(status))return status;
613 }
614 // Windows 8+ versons have different structure than Windows 7 and below
615 return (RtlIsWindowsVersionOrGreater(6, 2, 0) ? PRTL_INVERTED_FUNCTION_TABLE_64(table)->Overflow : PRTL_INVERTED_FUNCTION_TABLE_WIN7_32(table)->Overflow) ?
616 STATUS_NO_MEMORY : STATUS_SUCCESS;
617 }
618}; // namespace peconv
619
620bool peconv::setup_exceptions(IN BYTE* modulePtr, IN size_t moduleSize)
621{
622 if (moduleSize == 0) {
623 const DWORD img_size = get_image_size(reinterpret_cast<BYTE*>(modulePtr));
624 if (!img_size) {
625 return false; // invalid image
626 }
627 moduleSize = img_size;
628 }
629 return NT_SUCCESS(peconv::RtlInsertInvertedFunctionTable(modulePtr, (ULONG)moduleSize)) ? true : false;
630}
#define RTL_VERIFY_FLAGS_MAJOR_VERSION
#define RTL_VERIFY_FLAGS_BUILD_NUMBERS
#define RTL_VERIFY_FLAGS_MINOR_VERSION
#define min(a, b)
#define RtlFindMemoryBlockFromModuleSection__leave
Functions related to Exceptions Table.
#define PECONV_FORCEINLINE
#define PECONV_TRY_EXCEPT_BLOCK_END
#define PECONV_TRY_EXCEPT_BLOCK_START
Compile-time configurable logging macros for peconv.
#define LOG_DEBUG(fmt,...)
Definition: logger.h:80
#define LOG_INFO(fmt,...)
Definition: logger.h:74
struct peconv::_LDR_DATA_TABLE_ENTRY_WIN8 * PLDR_DATA_TABLE_ENTRY_WIN8
struct peconv::_RTL_INVERTED_FUNCTION_TABLE_WIN7_32 RTL_INVERTED_FUNCTION_TABLE_WIN7_32
struct peconv::_SEARCH_CONTEXT SEARCH_CONTEXT
struct peconv::_SEARCH_CONTEXT * PSEARCH_CONTEXT
struct peconv::_NtVersion * PNtVersion
_RTL_INVERTED_FUNCTION_TABLE_ENTRY_WIN7_32 RTL_INVERTED_FUNCTION_TABLE_ENTRY
struct peconv::_NtVersion NtVersion
struct peconv::_RTL_INVERTED_FUNCTION_TABLE_ENTRY_WIN7_32 * PRTL_INVERTED_FUNCTION_TABLE_ENTRY_WIN7_32
RTL_INVERTED_FUNCTION_TABLE_WIN7_32 _RTL_INVERTED_FUNCTION_TABLE
struct peconv::_RTL_INVERTED_FUNCTION_TABLE_WIN7_32 * PRTL_INVERTED_FUNCTION_TABLE_WIN7_32
struct peconv::_LDR_DDAG_NODE_WIN8 * PLDR_DDAG_NODE_WIN8
_RTL_INVERTED_FUNCTION_TABLE_ENTRY_WIN7_32 * PRTL_INVERTED_FUNCTION_TABLE_ENTRY
struct peconv::_RTL_INVERTED_FUNCTION_TABLE_ENTRY_WIN8_PLUS_32 RTL_INVERTED_FUNCTION_TABLE_ENTRY_WIN8_PLUS_32
DWORD get_image_size(IN const BYTE *payload)
bool setup_exceptions(IN BYTE *modulePtr, IN size_t moduleSize)
struct peconv::_RTL_INVERTED_FUNCTION_TABLE_ENTRY_WIN7_32 RTL_INVERTED_FUNCTION_TABLE_ENTRY_WIN7_32
RTL_INVERTED_FUNCTION_TABLE_WIN7_32 RTL_INVERTED_FUNCTION_TABLE
struct peconv::_RTL_INVERTED_FUNCTION_TABLE_64 RTL_INVERTED_FUNCTION_TABLE_64
struct peconv::_RTL_INVERTED_FUNCTION_TABLE_ENTRY_64 RTL_INVERTED_FUNCTION_TABLE_ENTRY_64
struct peconv::_RTL_INVERTED_FUNCTION_TABLE_ENTRY_WIN8_PLUS_32 * PRTL_INVERTED_FUNCTION_TABLE_ENTRY_WIN8_PLUS_32
struct peconv::_RTL_INVERTED_FUNCTION_TABLE_64 * PRTL_INVERTED_FUNCTION_TABLE_64
struct peconv::_RTL_INVERTED_FUNCTION_TABLE_ENTRY_64 * PRTL_INVERTED_FUNCTION_TABLE_ENTRY_64
struct peconv::_LDR_DATA_TABLE_ENTRY_WIN8 LDR_DATA_TABLE_ENTRY_WIN8
_RTL_INVERTED_FUNCTION_TABLE_ENTRY_WIN7_32 _RTL_INVERTED_FUNCTION_TABLE_ENTRY
struct peconv::_LDR_DDAG_NODE_WIN8 LDR_DDAG_NODE_WIN8
RTL_INVERTED_FUNCTION_TABLE_WIN7_32 * PRTL_INVERTED_FUNCTION_TABLE
Wrappers over various fields in the PE header. Read, write, parse PE headers.
PACTIVATION_CONTEXT EntryPointActivationContext
PLDRP_CSLIST_DEPENDENT Dependencies
PLDRP_CSLIST_INCOMMING IncomingDependencies
PLDR_SERVICE_TAG_RECORD ServiceTagList
RTL_INVERTED_FUNCTION_TABLE_ENTRY_64 Entries[0x200]
PIMAGE_RUNTIME_FUNCTION_ENTRY ExceptionDirectory
RTL_INVERTED_FUNCTION_TABLE_ENTRY_WIN7_32 Entries[0x200]
Miscellaneous utility functions.