MCPcopy Create free account
hub / github.com/NetSPI/BOF-PE / FindLdrpInvertedFunctionTable

Function FindLdrpInvertedFunctionTable

loader/mappedmodule.cpp:201–260  ·  view source on GitHub ↗

Source from the content-addressed store, hash-verified

199}
200
201static RTL_INVERTED_FUNCTION_TABLE* FindLdrpInvertedFunctionTable(uintptr_t& mrDataPtr, DWORD& mrDataSize) {
202
203 auto ntPe = Pe::PeNative::fromModule(GetModuleHandle("ntdll.dll"));
204 auto mrData = FindSection(".mrdata", ntPe);
205 RTL_INVERTED_FUNCTION_TABLE* table = nullptr;
206
207 if (mrData == nullptr) {
208 return nullptr;
209 }
210
211 mrDataPtr = uintptr_t(ntPe.base()) + mrData->VirtualAddress;
212 uintptr_t mrDataPtrEnd = mrDataPtr + mrData->SizeOfRawData;
213 mrDataSize = mrData->SizeOfRawData;
214
215 //Iterate through the .mrdata section of ntdll a byte at a time searching for the LdrpInvertedFunctionTable
216 while (mrDataPtr++ < mrDataPtrEnd) {
217
218 table = reinterpret_cast<RTL_INVERTED_FUNCTION_TABLE*>(mrDataPtr);
219
220 // Basic checks for a candidate table, if these are out of range,
221 // it's not the table we are looking for
222 if (table->MaxCount > 512 || table->MaxCount == 0 || table->Count == 0 || table->Count > table->MaxCount)
223 continue;
224
225 MEMORY_BASIC_INFORMATION mbi = {};
226
227 // We only need to check the first entry in the table which is always ntdll.dll.
228 // If the entry has the following attributes, we have a candidate for further checks
229 // * Exception table is within the range of the image memory address space
230 // * The ImageBase is indeed allocated, valid and commited to memory
231 // * The initial allocation of the memory range was allocated with WRX, which is typical of loaded modules
232 if (table->Entries[0].FunctionTable < table->Entries[0].ImageBase ||
233 uintptr_t(table->Entries[0].FunctionTable) >= uintptr_t(table->Entries[0].ImageBase) + table->Entries[0].SizeOfImage ||
234 NtQueryVirtualMemory(GetCurrentProcess(), table->Entries[0].ImageBase, MemoryBasicInformation, &mbi, sizeof(mbi), nullptr) != 0 ||
235 (mbi.State & MEM_COMMIT) == 0 ||
236 (mbi.AllocationProtect != PAGE_EXECUTE_WRITECOPY))
237 continue;
238
239 //Now that we are fairy certain the ImageBase is ntdll, lets double check
240 //by parsing the PE from memory and checking that it looks like a PE
241 auto tablePe = Pe::PeNative::fromModule(table->Entries[0].ImageBase);
242 auto exceptionTableSize = 0ul;
243 auto exceptionTable = GetExceptionTables(tablePe, exceptionTableSize);
244
245 // The final checks for the inverted function table:
246 // * Does the ImageBase memory contents looks like a PE
247 // * Does the imageSize of the parse PE match the entry within the table
248 // * Does the size of the execption information in the PE match that of the table
249 // * Does the address of the exception table from the PE match the entry in the table
250 if (!tablePe.valid() ||
251 tablePe.imageSize() != table->Entries[0].SizeOfImage ||
252 exceptionTableSize != table->Entries[0].SizeOfTable ||
253 exceptionTable != table->Entries[0].FunctionTable)
254 continue;
255
256 break;
257 }
258

Calls 5

FindSectionFunction · 0.85
GetExceptionTablesFunction · 0.85
baseMethod · 0.80
imageSizeMethod · 0.80
validMethod · 0.45

Tested by

no test coverage detected