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