【问题标题】:How to find the first field from an object/class?如何从对象/类中找到第一个字段?
【发布时间】:2018-12-10 13:20:42
【问题描述】:

早上好, 在this post 中,我正在寻找一种在转储中找到CString 条目的方法,但我仍然是:-)
根据 Windbg 的x /2 结果中提到的第一个字段,似乎可以找到与对象相关的条目。对于具有虚拟方法的对象,这似乎是 __vptr 字段(对应于 *vftable' 条目),我认为这个问题对于 CString 类的特殊情况很容易。

在源代码 (C:\Program Files (x86)\Microsoft Visual Studio\2017\Professional\VC\Tools\MSVC\<version>\crt\src\vcruntime\undname.cxx) 中,我发现以下条目:

#if ( !NO_COMPILER_NAMES )
    "`vftable'",                          <--- vftable: the one I'm working with
    "`vbtable'",
    "`vcall'",
    "`typeof'",
    "`local static guard'",
    "`string'",
    "`vbase destructor'",
    "`vector deleting destructor'",
    "`default constructor closure'",
    "`scalar deleting destructor'",
    "`vector constructor iterator'",
    "`vector destructor iterator'",
    "`vector vbase constructor iterator'",
    "`virtual displacement map'",
    "`eh vector constructor iterator'",
    "`eh vector destructor iterator'",
    "`eh vector vbase constructor iterator'",
    "`copy constructor closure'",
    "`udt returning'",
    "`EH", //eh initialized struct
    "`RTTI", //rtti initialized struct
    "`local vftable'",
    "`local vftable constructor closure'",
#endif // !NO_COMPILER_NAMES

这让我想知道我是否可以使用提到的条目之一作为对象的第一个字段的候选者。我已经发现windbgx /2 *!ATL::CStringT*命令中有一个条目,以scalar deleting destructor'结尾,但我不知道我是否可以将其用作“第一字段”候选。

附:如果你想知道“但你为什么不试试呢?”,我的转储文件中存在的CStringT 对象包含一些奇怪的字符,这使得很难看出我是否做正确的事,看到奇怪但正确的字符,或者我正在查看虚假结果。

提前致谢

【问题讨论】:

    标签: c++ windbg dump pykd


    【解决方案1】:

    看来CString只是封装了一个指针,没有任何虚方法,所以没有vtable。

    这是一个小例子:

    #include <atlstr.h>
    
    void SayHello(CHAR* arg)
    {
        CStringA cstring = arg;
    
        CStringA message = "Hello " + cstring + "!";
    
        printf("message: %s", (LPCSTR)message);
    }
    
    int main(int argc, CHAR** argv)
    {
        if (argc < 2)
            return -1;
    
        SayHello(argv[1]);
    
        return 0;
    }
    

    将生成的可执行文件放入 Windbg 并以 world 作为参数启动。

    放一个BP然后去

    0:000> bp ConsoleApplication1!SayHello
    0:000> bl
         0 e Disable Clear  x86 00000000`01041420     0001 (0001)  0:**** ConsoleApplication1!SayHello
    0:000> g
    

    BP 被击中;只需一步通过cstring local var init:

    Breakpoint 0 hit
    ConsoleApplication1!SayHello:
    01041420 55              push    ebp
    0:000:x86> p
    

    您可以使用dt 命令(显示类型)来查看类型中有哪些字段。 此处使用查看cstring 本地变量:

    0:000:x86> dt cstring
    Local var @ 0x114f944 Type ATL::CStringT<char,ATL::StrTraitATL<char,ATL::ChTraitsCRT<char> > >
       +0x000 m_pszData        : 0x01224e20  "world"
    

    CString 中只有一个字段,其名称为 m_pszData,它只是一个指针:

    0:000:x86> dx -r1 ((ConsoleApplication1!char *)0x1224e20)
    ((ConsoleApplication1!char *)0x1224e20)                 : 0x1224e20 : "world" [Type: char *]
    

    sizeof 本地变量上的运算符仅给出 4:

    0:000:x86> ?? sizeof(cstring)
    unsigned int 4
    

    da确认:

    0:000:x86> dp cstring L4
    0114f944  01224e20 3ec0fed1 0114f998 01042bf1
    
    0:000:x86> da 01224e20 
    01224e20  "world"
    

    您将无法在转储中找到 CString 实例,因为它们只是指向数据的指针。

    【讨论】:

    • 感谢您的回答,Neitsa。似乎编译器在处理虚拟方法时确实添加了关键字vftable,而在其他情况下默认不添加任何内容。您是否知道 Windows 编译器的任何设置可能会在其他情况下添加其他内容?
    • @Dominique 我不知道,如果代码是使用/GR 开关编译的(在 vtable 中添加指向元信息的指针),则 RTTI 信息除外。不过这种情况很少见:(
    • 同时我找到了源代码,关于vftable' 条目,其他条目似乎也存在,但我不知道我是否可以使用它们。
    • 抱歉,我花了几天时间才明​​白 TL、DR 的意思 :-( 点了 :-)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-06-17
    • 1970-01-01
    • 1970-01-01
    • 2015-12-21
    • 2019-11-21
    • 2021-07-31
    相关资源
    最近更新 更多