Date: Tue, 9 Apr 2024 12:50:51 +0100
On Tue, Apr 9, 2024 at 8:13 AM Frederick Virchanza Gotham wrote:
>
> Over the next few days I'll try to figure out what it's doing to see what information
> I can get from Microsoft's std::type_info.
In order to see what information is available in Microsoft's
implementation of "std::typeinfo", I've tried to generate C/C++ code
from the assembler for "__RTDynamicCast", and you can see my full
attempt in this post if you scroll down to the end. There are some
very interesting lines in it such as:
int32_t *p_something_interesting0 = (int32_t*) *(*p_type_info_RCX - 1);
The above line seems to find a pointer at the beginning of the
type_info, and dereferences it to find something else (not sure what
yet -- but something juicy no doubt). Then we have:
char *p_something_interesting1 = (char *)p_type_info_RCX
- p_something_interesting0[1]
- offset;
which uses the aforementioned pointer to find some more intriguing
data, and seems to apply an offset (treating the aforementioned
pointer as pointing to an array and getting its 3rd element). Also I
see a 32-Bit integer which is a bitmask of flags -- I hope those flags
are things like IsPointer, IsPointerToMember, IsPolymorphic, and so
forth. If anyone has ever dissected Microsoft's type_info before then
could you please chime in here? I'll figure out what those pointers
point to . . . and what those bitmask flags are . . . and I bet ya I
can find an array of pointers to all the base classes' type_info's.
Here's my attempted generation of C/C++ from the assembler (might not
be perfect):
void *_RTDynamicCast(type_info *p_type_info_RCX, void *p_object,
type_info *p_type_info_from_R8, type_info *p_type_info_to_R9, bool
whether_to_throw)
{
if ( nullptr == p_type_info_RCX ) return nullptr;
// Backup the arguments before the registers get re-used
type_info *p_type_info_to_R15 = p_type_info_to_R9;
type_info *p_type_info_from_R12 = p_type_info_from_R8;
int32_t *p_something_interesting0 = (int32_t*) *(*
(uint64_t**)p_type_info_RCX - 1 );
uint32_t offset = 0u;
if ( p_something_interesting0[2] )
{
char *p = (char*)p_type_info_RCX - p_something_interesting0[2];
offset = *(uint32_t*)p;
}
char *p_something_interesting1 = (char*)p_type_info_RCX
- p_something_interesting0[1]
- offset;
char *some_important_address;
if ( *p_something_interesting0 )
{
some_important_address = (char*)p_something_interesting0 -
p_something_interesting0[5];
}
else
{
void *dummy;
some_important_address =
(char*)RtlPcToFileHeader(p_something_interesting0, &dummy);
}
uint32_t const some_bitmask_of_flags = *(uint32_t*)(
some_important_address + p_something_interesting0[4] + 4 );
int32_t *p_base_class;
char *some_important_address2;
type_info *p_type_info_to_STACK;
if ( some_bitmask_of_flags & 1 )
{
some_important_address2 = some_important_address;
p_type_info_to_STACK = p_type_info_to_R15;
void (*some_secret_function)(void*,void*) =
(some_bitmask_of_flags & 2) ? &secret_function0 : &secret_function1;
p_base_class = some_secret_function(p_something_interesting1,
p_something_interesting0);
}
else
{
p_base_class = secret_function2(p_something_interesting0,
p_type_info_from_R12, p_type_info_to_R15);
}
if ( p_base_class )
{
int64_t temp = 0;
if ( p_base_class[3] >= 0 )
{
temp = p_base_class[3];
uint64_t const temp2 =
*(uint64_t*)(p_something_interesting1 + p_base_class[3])
temp += *(int32_t*)(temp2 + p_base_class[4]);
}
return p_something_interesting1 + temp + p_base_class[2];
}
// control reaches here if the dynamic_cast failed
char dummy_object_to_throw;
if ( boolean_whether_to_throw )
{
secret_function3(
&dummy_object_to_throw,
"Bad dynamic_cast!",
p_type_info_from_R8,
p_base_class,
p_type_info_to_STACK,
some_important_address2);
CxxThrowException(&dummy_object_to_throw, &ThrowInfo_for_bad_cast);
}
return nullptr;
}
>
> Over the next few days I'll try to figure out what it's doing to see what information
> I can get from Microsoft's std::type_info.
In order to see what information is available in Microsoft's
implementation of "std::typeinfo", I've tried to generate C/C++ code
from the assembler for "__RTDynamicCast", and you can see my full
attempt in this post if you scroll down to the end. There are some
very interesting lines in it such as:
int32_t *p_something_interesting0 = (int32_t*) *(*p_type_info_RCX - 1);
The above line seems to find a pointer at the beginning of the
type_info, and dereferences it to find something else (not sure what
yet -- but something juicy no doubt). Then we have:
char *p_something_interesting1 = (char *)p_type_info_RCX
- p_something_interesting0[1]
- offset;
which uses the aforementioned pointer to find some more intriguing
data, and seems to apply an offset (treating the aforementioned
pointer as pointing to an array and getting its 3rd element). Also I
see a 32-Bit integer which is a bitmask of flags -- I hope those flags
are things like IsPointer, IsPointerToMember, IsPolymorphic, and so
forth. If anyone has ever dissected Microsoft's type_info before then
could you please chime in here? I'll figure out what those pointers
point to . . . and what those bitmask flags are . . . and I bet ya I
can find an array of pointers to all the base classes' type_info's.
Here's my attempted generation of C/C++ from the assembler (might not
be perfect):
void *_RTDynamicCast(type_info *p_type_info_RCX, void *p_object,
type_info *p_type_info_from_R8, type_info *p_type_info_to_R9, bool
whether_to_throw)
{
if ( nullptr == p_type_info_RCX ) return nullptr;
// Backup the arguments before the registers get re-used
type_info *p_type_info_to_R15 = p_type_info_to_R9;
type_info *p_type_info_from_R12 = p_type_info_from_R8;
int32_t *p_something_interesting0 = (int32_t*) *(*
(uint64_t**)p_type_info_RCX - 1 );
uint32_t offset = 0u;
if ( p_something_interesting0[2] )
{
char *p = (char*)p_type_info_RCX - p_something_interesting0[2];
offset = *(uint32_t*)p;
}
char *p_something_interesting1 = (char*)p_type_info_RCX
- p_something_interesting0[1]
- offset;
char *some_important_address;
if ( *p_something_interesting0 )
{
some_important_address = (char*)p_something_interesting0 -
p_something_interesting0[5];
}
else
{
void *dummy;
some_important_address =
(char*)RtlPcToFileHeader(p_something_interesting0, &dummy);
}
uint32_t const some_bitmask_of_flags = *(uint32_t*)(
some_important_address + p_something_interesting0[4] + 4 );
int32_t *p_base_class;
char *some_important_address2;
type_info *p_type_info_to_STACK;
if ( some_bitmask_of_flags & 1 )
{
some_important_address2 = some_important_address;
p_type_info_to_STACK = p_type_info_to_R15;
void (*some_secret_function)(void*,void*) =
(some_bitmask_of_flags & 2) ? &secret_function0 : &secret_function1;
p_base_class = some_secret_function(p_something_interesting1,
p_something_interesting0);
}
else
{
p_base_class = secret_function2(p_something_interesting0,
p_type_info_from_R12, p_type_info_to_R15);
}
if ( p_base_class )
{
int64_t temp = 0;
if ( p_base_class[3] >= 0 )
{
temp = p_base_class[3];
uint64_t const temp2 =
*(uint64_t*)(p_something_interesting1 + p_base_class[3])
temp += *(int32_t*)(temp2 + p_base_class[4]);
}
return p_something_interesting1 + temp + p_base_class[2];
}
// control reaches here if the dynamic_cast failed
char dummy_object_to_throw;
if ( boolean_whether_to_throw )
{
secret_function3(
&dummy_object_to_throw,
"Bad dynamic_cast!",
p_type_info_from_R8,
p_base_class,
p_type_info_to_STACK,
some_important_address2);
CxxThrowException(&dummy_object_to_throw, &ThrowInfo_for_bad_cast);
}
return nullptr;
}
Received on 2024-04-09 11:51:05