2

我正在使用 IDA Pro 6.3 对 Win32 .dll 进行静态分析,并将 Hex-Rays 反编译器与 IDA 反汇编器结合使用。我想了解这条线的作用。

v4 = (*(int (__thiscall **)(int, int))(*(_DWORD *)dword_10087418 + 4))(dword_10087418, v11);

它的格式类似于函数调用。当在子例程调用中使用指向函数的指针时,这是否是反编译代码的样子?

谢谢。

4

2 回答 2

3

这很可能是 C++,而不是普通的 C。这正是 Visual C++ 生成的虚拟方法调用的样子。我会这样说:

  • dword_10087418是指向对象的指针。它要么是全局变量,要么是静态变量,而不是局部变量。
  • 该对象有一个虚拟方法表,代码正在调用该表中的第二个函数。
  • 假设 Hex-Rays 已正确识别函数参数,则被调用的函数采用一个 32 位参数。返回类型不清楚。
  • C++ 调用很可能非常简单,类似于SomeClass::Instance->func(arg).

如果您不熟悉 C++ 对象布局,您应该阅读C++ Under the HoodReversing: Secrets of Reverse EngineeringInside the C++ Object Model。IDA Pro Book 也有关于该主题的简短部分。


如果你想要一个简短的总结,请继续阅读。请记住,所有这些都是 MSVC 的实现细节,其他编译器的做法不同,他们可以随意更改它。(另外,我通过不提及虚拟/多重继承来简化事情)。当一个类使用虚函数时,编译器会为该类中的所有此类函数构建一个表,并将指向该表的指针作为该类每个对象的第一个隐藏成员。那么,从表中调用虚函数就很简单了:

mov ecx, esi   ; pretend that esi contains a pointer 
               ; to the object whose method is being called
               ; also known as "this"
               ; __thiscall functions expect to find this pointer in ecx
               ;  and all later arguments on the stack
mov edx, [ecx] ; get the vtable address
push edi       ; set up some integer-sized argument
call [edx + 4] ; call the second function in the vtable

这基本上就是那行代码正在做的事情:

(*(int (__thiscall **)(int, int))(*(_DWORD *)dword_10087418 + 4))(dword_10087418, v11)
                                  ^-----------------------^
                                  dereference pointer to get the address of the vtable
                                  (it's the first piece of data in the object)
                                 ^-----------------------------^
                                 add 4 bytes to get address of the second function
^------------------------------------------------------------------------------------^
cast that pointer to a particular function pointer and call it
(cast is invisible in assembler code, so it's just a call)

请注意,由于成员函数需要访问this,编译器也必须传递它。这是一个在 C++ 中不可见的细节,但this被视为函数的附加参数 - 因此您看到两个参数,但函数只接受一个(MSVC 的thiscall约定要求this指针传入ecx)。IDA 不会费心隐藏那个指针,因为那会让人感到困惑。


更多建议:获取ms_rttiIDA 脚本并运行它以查找 DLL 中的虚拟方法表,然后搜索其他引用以dword_10087418查看写入了哪些值 - 您应该能够确定哪个 vtable 与该对象关联并且然后找出正在调用的函数。

如果为类和相关的 vtable 定义存根结构类型,则可以使 Hex-Rays 以更易读的方式显示代码,然后告诉 IDA 指针使用该结构类型。

于 2013-05-23T19:45:31.570 回答
0

这是将 *dword_10087418 + 4 处的地址转换为函数并调用它。

所以它将 dword_10087418 转换为 dword 指针,然后取消引用它,然后将 4 添加到该结果。结果地址被转换为一个函数,其声明如下:

int __thiscall foo(int, int)

使用int (__thiscall **)(int, int)带有两个整数参数的 __thiscall 调用约定创建一个指向函数的双指针。然后*()围绕所有将其取消引用到单个函数指针。所以最后你将一些结果地址转换为函数指针。

dword_10087418 和 v11 是传递给此函数的整数。函数调用的结果保存在 v4 中。C 代码如下所示:

int v4 = foo(dword_10087418, v11);
于 2013-05-21T23:56:57.620 回答