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