如何对 RTTI 类型描述符中的名称进行解码?

逆向工程 微信 改名
2021-06-28 09:24:54

我目前正在浏览 MSVC++2003 可执行文件中可用的 RTTI 信息(编写 IDAPython 脚本以重新创建类层次结构的结构)。显然,正如这里所看到的,RTTI 类型描述符存储类名称或它们的构造函数之类的内容:

.?AVexception@@
    .?AUescaped_list_error@boost@@
    .?AVruntime_error@stlp_std@@

但是,它采用了我还不认识的重整方案。该名称以 a 开头.,根据此wiki,它甚至不是损坏的 MSVC 名称的有效开头。IDA 和在线名称 demangler也无法对这些名称进行 demangle。根据这些脚本(s. ms_rtti4.idc) 这些应该映射到:

typeid(struct exception)
    typeid(struct boost::escaped_list_error)
    typeid(struct stlp_std::runtime_error)

我尝试删除前导点以至少获得有效的开始,但它仍然无效。快速编写一个过于简单的 python 行来至少修复命名空间类名......

return "::".join(reversed(name[4:-2].split("@")))

...它当然会因泛型类型名称而失败,就像这里的这些类一样:

ns::FunctionBase             (.?AVFunctionBase@ns@@)
    ns::Z::P6AXPAX::?$FunctionT  (.?AV?$FunctionT@P6AXPAX@Z@ns@@)
    ns::Z::P6AHH::?$FunctionT    (.?AV?$FunctionT@P6AHH@Z@ns@@)
    ns::Z::P6AHPB_W::?$FunctionT (.?AV?$FunctionT@P6AHPB_W@Z@ns@@)
    ns::Z::P6AHI::?$FunctionT    (.?AV?$FunctionT@P6AHI@Z@ns@@)

我注意到从这些中删除.?AUor.?AV前缀会产生一些有用的结果(遗憾地缺少命名空间):

FunctionT@ns@@
    FunctionT<void (__cdecl*)(void *)>
    FunctionT<int (__cdecl*)(int)>
    FunctionT<int (__cdecl*)(wchar_t const *)>
    FunctionT<int (__cdecl*)(unsigned int)>

...但同样,现在这个名称不适用于非通用名称。

我想知道 RTTI 类型描述符名称方案是否已记录在案,或者是否有逻辑将其转换为实际的 RTTI 名称,我可以使用常用工具进行修改?

2个回答

通过Igor Skochinsky 的经典 IDA RTTI 脚本,我发现我发布的名称等同于typeid(struct xyz)(因为我已添加到我的问题中)。

滥用从它们的子字符串创建一个有效的损坏的 ctor 名称,然后从结果中剥离 ctor 部分会产生很好的类名。

这是我的 Python 脚本和结果:

def demangle(name):
    # Check if this even is a problematic typeid.
    if name.startswith(".?A"):
        # Remove the .?AU or .?AV prefix.
        name = name[4:]
        # Demangle it as a default public constructor call.
        ctor_name = "??0" + name + "QAE@XZ"
        name = your_default_msvc_demangler.demangle(ctor_name)
        # Strip constructor pre and suffixes again (accessor / cconv and parameter list).
        name = name[len("public: __thiscall "):name.rfind("(")]
        # Remove ctor name.
        parts = name.split("::")
        return "::".join(parts[:-1])
    else:
        return your_default_msvc_demangler.demangle(name)

以下是我的问题中给出的名称的示例结果:

exception
    boost::escaped_list_error
    stlp_std::runtime_error

ns::FunctionBase::FunctionBase
    ns::FunctionT<void (__cdecl *)(void *)>
    ns::FunctionT<int (__cdecl *)(int)>
    ns::FunctionT<int (__cdecl *)(wchar_t const *)>
    ns::FunctionT<int (__cdecl *)(unsigned int)>

可能不是很优雅,但工作。

vc++filt 似乎破坏了它

?AVexception@@
 ?? AVexception
?AUescaped_list_error@boost@@
 ?? boost::AUescaped_list_error
?AVruntime_error@stlp_std@@
 ?? stlp_std::AVruntime_error
?AUescaped_list_error@boost@@
 ?? boost::AUescaped_list_error

src 稍微编辑为 strip 。在前

cat cpp.cpp
#include <windows.h>
#include <stdio.h>
#include <dbghelp.h>
#pragma comment(lib,"dbghelp.lib")
#define MAXLEN 0x1000
char buff[MAXLEN];
int main (int argc , char * argv[])
{
memset(buff,0,MAXLEN);
if( argc !=2 )
    {
        printf ("usage %s undemsym",argv[0]);
        exit(-1); 
    }
    char *nodot;
    if( *(char *) argv[1] == '.'  )
    {
        nodot = argv[1]+1;
    }
    else if (*(char *) argv[1] == '?')
    {
        nodot = argv[1];
    }
    else
    {        
        printf("not a valid msvc mangled name\n");
        exit(-2);
    }
    if ( ( UnDecorateSymbolName(nodot , buff,MAXLEN,UNDNAME_COMPLETE)) !=0 )
        {
            printf ("%s\n",buff);
        }
        else
        {
            printf("error %x\n" , GetLastError());
        }
}

编译链接

cl /Zi /W4 /analyze /Od cpp.cpp /link /release

测试

cpp.exe
usage cpp.exe sym
cpp.exe .?AVruntime_error@stlp_std@@
.?AVruntime_error@stlp_std@@

cpp.exe ?AVruntime_error@stlp_std@@
 ?? stlp_std::AVruntime_error

编辑评论(将这些行添加到上面的 src 中)

if ( ( UnDecorateSymbolName(nodot , buff,MAXLEN,  UNDNAME_NO_ARGUMENTS )) !=0 )
{
    printf ("%s\n",buff);
}
else
{
    printf("error %x\n" , GetLastError());
}

结果

cppundem.exe .?AUescaped_list_error@boost@@
 ?? boost::AUescaped_list_error
struct boost::escaped_list_error

完整结果

:\cat mang.txt
.?AVFunctionBase@ns@@
.?AV?$FunctionT@P6AXPAX@Z@ns@@
.?AV?$FunctionT@P6AHH@Z@ns@@
.?AV?$FunctionT@P6AHPB_W@Z@ns@@
.?AV?$FunctionT@P6AHI@Z@ns@@
:\for /F %i in (mang.txt) do cppundem.exe %i

:\cppundem.exe .?AVFunctionBase@ns@@
 ?? ns::AVFunctionBase
class ns::FunctionBase

:\cppundem.exe .?AV?$FunctionT@P6AXPAX@Z@ns@@
?AV?$FunctionT@P6AXPAX@Z@ns@@
class ns::FunctionT<void (__cdecl*)(void *)>

:\cppundem.exe .?AV?$FunctionT@P6AHH@Z@ns@@
?AV?$FunctionT@P6AHH@Z@ns@@
class ns::FunctionT<int (__cdecl*)(int)>

:\cppundem.exe .?AV?$FunctionT@P6AHPB_W@Z@ns@@
?AV?$FunctionT@P6AHPB_W@Z@ns@@
class ns::FunctionT<int (__cdecl*)(wchar_t const *)>

:\cppundem.exe .?AV?$FunctionT@P6AHI@Z@ns@@
?AV?$FunctionT@P6AHI@Z@ns@@
class ns::FunctionT<int (__cdecl*)(unsigned int)>

:\