6

这是我的一些代码:

MyClass* MyClass::getInstance()
{
   static MyClass instance;
   return &instance;
}

我想看看这个单身人士的当前值。但我目前在执行过程中暂停了三个小时,我暂停的原因是我内存不足。所以我不能在这个方法中放一个断点来查看值是什么。

那么我的问题是如何instance从全局范围内引用这个变量。我试过把它称为,MyClass::getInstance::instance但这不起作用。我猜getInstance必须以某种方式装饰。有谁知道怎么做?

这是在 Visual Studio 2008 中。

4

3 回答 3

5

好吧,函数范围的静态instance变量不会出现在由.map生成的文件中cl.exe /Fm,并且在我在 WinDbg 中使用时也不会出现x programname!*MyClass*,因此损坏的名称似乎根本不包含MyClass

选项 1:拆卸MyClass::getInstance

这种方法似乎更容易:

0:000> uf 程序名!MyClass::getInstance
程序名!MyClass::getInstance [程序名.cpp @ 14]:
   14 00401050 55 推 ebp
   14 00401051 8bec 移动 ebp,esp
   15 00401053 a160b34200 mov eax,dword ptr [程序名!$S1 (0042b360)]
   15 00401058 83e001 和 eax,1
   15 0040105b 7526 jne funcstat!MyClass::getInstance+0x33 (00401083)

程序名!MyClass::getInstance+0xd [程序名.cpp @ 15]:
   15 0040105d 8b0d60b34200 mov ecx,dword ptr [程序名!$S1 (0042b360)]
   15 00401063 83c901 或 ecx,1
   15 00401066 890d60b34200 mov dword ptr [程序名!$S1 (0042b360)],ecx
   15 0040106c b9b0be4200 mov ecx,偏移程序名!实例(0042beb0)
   15 00401071 e88fffffff 调用程序名!ILT+0(??0MyClassQAEXZ) (00401005)
   15 00401076 68e03e4200 推送偏移程序名!`MyClass::getInstance'::`2'::`'instance' (00423ee0) 的动态 atexit 析构函数
   15 0040107b e8f3010000 调用程序名!atexit (00401273)
   15 00401080 83c404 添加 esp,4

程序名!MyClass::getInstance+0x33 [程序名.cpp @ 16]:
   16 00401083 b8b0be4200 mov eax,偏移程序名!实例(0042beb0)
   17 00401088 5d 弹出 ebp
   17 00401089 C3 RET

由此我们可以看出编译器调用了对象$S1。当然,这个名称将取决于您的程序有多少函数范围的静态变量。

选项 2:在内存中搜索对象

为了扩展@gbjbaanb 的建议,如果MyClass有虚函数,您可能会很难找到它的位置:

  • 对进程进行完整的内存转储。
  • 将完整的内存转储加载到 WinDbg。
  • 使用x命令查找 MyClass 的 vtable 的地址:
    0:000> x 程序名!MyClass::`vftable'
    00425c64 程序名!MyClass::`vftable' =
  • 使用s命令搜索进程的虚拟地址空间(在本例中为 0-2GB)以查找指向 MyClass 的 vtable 的指针:
    0:000> s -d 0 L?7fffffff 00425c64
    004010dc 00425c64 c35de58b cccccccc cccccccc d\B...].........
    0040113c 00425c64 8bfc458b ccc35de5 cccccccc d\B..E...]......
    0042b360 00425c64 00000000 00000000 00000000 分贝......
  • 使用该dt命令查找类的 vtable 偏移量,并从搜索返回的地址中减去该偏移量。这些是对象的可能地址。
    0:000> dt 程序名!MyClass
       +0x000 __VFN_table : Ptr32
       +0x008 x : Int4B
       +0x010 y : 浮动
  • 用于dt programname!MyClass 0042b360检查对象的成员变量,检验对象位于 0042b360(或其他地址)的假设。正如我在上面所做的那样,您可能会得到一些误报,但是通过检查成员变量,您可能能够找出哪个是您的单例。

这是一种查找 C++ 对象的通用技术,当您可以反汇编时,这有点矫枉过正MyClass::getInstance

于 2008-11-15T19:41:44.243 回答
1

在 gdb 中,您可以将观察点放在变量的损坏名称上。

例如,使用此功能:

int f() {
    static int xyz = 0;
    ++xyz;

    return xyz;
}

我可以观看 _ZZ1fvE3xyz(被 gcc 3.2.3 或 gcc 4.0.1 破坏)。

于 2008-11-13T21:11:55.217 回答
1

该代码看起来很危险...... :-)

但无论如何,你的名字将取决于你的调用约定 所以在你找到你的名字之前,你需要知道你的构建环境使用什么作为调用约定。MSDN 有更多关于调用约定的信息。

除此之外,找出关于你的类的所有这些信息的一种方法是检查你的 VTable,它位于对象的前 4 个字节中。逆向器使用的一个绝妙技巧是隐藏的 VC++ 标志reportSingleClassLayout,它以 ASCII 艺术方式打印类结构。

于 2008-11-14T02:53:54.810 回答