/*! RtlLookupFunctionTable * \brief Locates the table of RUNTIME_FUNCTION entries for a code address. * \param ControlPc * Address of the code, for which the table should be searched. * \param ImageBase * Pointer to a DWORD64 that receives the base address of the * corresponding executable image. * \param Length * Pointer to an ULONG that receives the number of table entries * present in the table. */ PRUNTIME_FUNCTION NTAPI RtlLookupFunctionTable( IN DWORD64 ControlPc, OUT PDWORD64 ImageBase, OUT PULONG Length) { PVOID Table; ULONG Size; /* Find corresponding file header from code address */ if (!RtlPcToFileHeader((PVOID)ControlPc, (PVOID*)ImageBase)) { /* Nothing found */ return NULL; } /* Locate the exception directory */ Table = RtlImageDirectoryEntryToData((PVOID)*ImageBase, TRUE, IMAGE_DIRECTORY_ENTRY_EXCEPTION, &Size); /* Return the number of entries */ *Length = Size / sizeof(RUNTIME_FUNCTION); /* Return the address of the table */ return Table; }
void* CDECL MSVCRT___RTDynamicCast(void *cppobj, int unknown, type_info *src, type_info *dst, int do_throw) { void *ret; if (!cppobj) return NULL; TRACE("obj: %p unknown: %d src: %p %s dst: %p %s do_throw: %d)\n", cppobj, unknown, src, dbgstr_type_info(src), dst, dbgstr_type_info(dst), do_throw); __TRY { int i; const rtti_object_locator *obj_locator = get_obj_locator( cppobj ); const rtti_object_hierarchy *obj_bases; const rtti_base_array *base_array; char *base; if (TRACE_ON(msvcrt)) dump_obj_locator(obj_locator); if(obj_locator->signature == 0) base = RtlPcToFileHeader((void*)obj_locator, (void**)&base); else base = (char*)obj_locator - obj_locator->object_locator; obj_bases = (const rtti_object_hierarchy*)(base + obj_locator->type_hierarchy); base_array = (const rtti_base_array*)(base + obj_bases->base_classes); ret = NULL; for (i = 0; i < obj_bases->array_len; i++) { const rtti_base_descriptor *base_desc = (const rtti_base_descriptor*)(base + base_array->bases[i]); const type_info *typ = (const type_info*)(base + base_desc->type_descriptor); if (!strcmp(typ->mangled, dst->mangled)) { void *this_ptr = (char *)cppobj - obj_locator->base_class_offset; ret = get_this_pointer( &base_desc->offsets, this_ptr ); break; } } if (!ret && do_throw) { const char *msg = "Bad dynamic_cast!"; bad_cast e; MSVCRT_bad_cast_ctor( &e, &msg ); _CxxThrowException( &e, &bad_cast_exception_type ); } } __EXCEPT_PAGE_FAULT { __non_rtti_object e; MSVCRT___non_rtti_object_ctor( &e, "Access violation - no RTTI data!" ); _CxxThrowException( &e, &bad_typeid_exception_type ); return NULL; } __ENDTRY return ret; }
static void dump_obj_locator( const rtti_object_locator *ptr ) { int i; char *base = ptr->signature == 0 ? RtlPcToFileHeader((void*)ptr, (void**)&base) : (char*)ptr - ptr->object_locator; const rtti_object_hierarchy *h = (const rtti_object_hierarchy*)(base + ptr->type_hierarchy); const type_info *type_descriptor = (const type_info*)(base + ptr->type_descriptor); TRACE( "%p: sig=%08x base_offset=%08x flags=%08x type=%p %s hierarchy=%p\n", ptr, ptr->signature, ptr->base_class_offset, ptr->flags, type_descriptor, dbgstr_type_info(type_descriptor), h ); TRACE( " hierarchy: sig=%08x attr=%08x len=%d base classes=%p\n", h->signature, h->attributes, h->array_len, base + h->base_classes ); for (i = 0; i < h->array_len; i++) { const rtti_base_descriptor *bases = (rtti_base_descriptor*)(base + ((const rtti_base_array*)(base + h->base_classes))->bases[i]); TRACE( " base class %p: num %d off %d,%d,%d attr %08x type %p %s\n", bases, bases->num_base_classes, bases->offsets.this_offset, bases->offsets.vbase_descr, bases->offsets.vbase_offset, bases->attributes, base + bases->type_descriptor, dbgstr_type_info((const type_info*)(base + bases->type_descriptor)) ); } }
const type_info* CDECL MSVCRT___RTtypeid(void *cppobj) { const type_info *ret; if (!cppobj) { bad_typeid e; MSVCRT_bad_typeid_ctor( &e, "Attempted a typeid of NULL pointer!" ); _CxxThrowException( &e, &bad_typeid_exception_type ); return NULL; } __TRY { const rtti_object_locator *obj_locator = get_obj_locator( cppobj ); char *base; if(obj_locator->signature == 0) base = RtlPcToFileHeader((void*)obj_locator, (void**)&base); else base = (char*)obj_locator - obj_locator->object_locator; ret = (type_info*)(base + obj_locator->type_descriptor); } __EXCEPT_PAGE_FAULT { __non_rtti_object e; MSVCRT___non_rtti_object_ctor( &e, "Bad read pointer - no RTTI data!" ); _CxxThrowException( &e, &bad_typeid_exception_type ); return NULL; } __ENDTRY return ret; }
// Checks if the address is out of any kernel modules. Beware that this is not // comprehensive check to detect all possible patterns of the interesting things _Use_decl_annotations_ bool GMonIsNonImageKernelAddress(ULONG_PTR address) { void *base = nullptr; if (address >= reinterpret_cast<ULONG_PTR>(MmSystemRangeStart) && !RtlPcToFileHeader(reinterpret_cast<void *>(address), &base)) { return true; } return false; }
__CxxThrowException( #endif void* pExceptionObject, // The object thrown _ThrowInfo* pThrowInfo // Everything we need to know about it ) { EHTRACE_ENTER_FMT1("Throwing object @ 0x%p", pExceptionObject); static const EHExceptionRecord ExceptionTemplate = { // A generic exception record EH_EXCEPTION_NUMBER, // Exception number EXCEPTION_NONCONTINUABLE, // Exception flags (we don't do resume) NULL, // Additional record (none) NULL, // Address of exception (OS fills in) EH_EXCEPTION_PARAMETERS, // Number of parameters { EH_MAGIC_NUMBER1, // Our version control magic number NULL, // pExceptionObject NULL, #if _EH_RELATIVE_OFFSETS NULL // Image base of thrown object #endif } // pThrowInfo }; EHExceptionRecord ThisException = ExceptionTemplate; // This exception ThrowInfo* pTI = (ThrowInfo*)pThrowInfo; if (pTI && (THROW_ISWINRT( (*pTI) ) ) ) { ULONG_PTR *exceptionInfoPointer = *reinterpret_cast<ULONG_PTR**>(pExceptionObject); exceptionInfoPointer--; // The pointer to the ExceptionInfo structure is stored sizeof(void*) infront of each WinRT Exception Info. WINRTEXCEPTIONINFO* wei = reinterpret_cast<WINRTEXCEPTIONINFO*>(*exceptionInfoPointer); pTI = wei->throwInfo; } // // Fill in the blanks: // ThisException.params.pExceptionObject = pExceptionObject; ThisException.params.pThrowInfo = pTI; #if _EH_RELATIVE_OFFSETS PVOID ThrowImageBase = RtlPcToFileHeader((PVOID)pTI, &ThrowImageBase); ThisException.params.pThrowImageBase = ThrowImageBase; #endif // // If the throw info indicates this throw is from a pure region, // set the magic number to the Pure one, so only a pure-region // catch will see it. // // Also use the Pure magic number on Win64 if we were unable to // determine an image base, since that was the old way to determine // a pure throw, before the TI_IsPure bit was added to the FuncInfo // attributes field. // if (pTI != NULL) { if (THROW_ISPURE(*pTI)) { ThisException.params.magicNumber = EH_PURE_MAGIC_NUMBER1; } #if _EH_RELATIVE_OFFSETS else if (ThrowImageBase == NULL) { ThisException.params.magicNumber = EH_PURE_MAGIC_NUMBER1; } #endif } // // Hand it off to the OS: // EHTRACE_EXIT; #if defined(_M_X64) && defined(_NTSUBSET_) RtlRaiseException( (PEXCEPTION_RECORD) &ThisException ); #else RaiseException( ThisException.ExceptionCode, ThisException.ExceptionFlags, ThisException.NumberParameters, (PULONG_PTR)&ThisException.params ); #endif }