反编译__thiscall表达式指向函数的指针?

时间:2013-05-15 23:48:25

标签: decompiling decompiler ida

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

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

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

感谢。

2 个答案:

答案 0 :(得分:1)

这很可能是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约定{} {{1} }指针在this)中传递。 IDA并不打扰隐藏指针,因为这会让人感到困惑。


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

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

答案 1 :(得分:0)

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

所以它将dword_10087418转换为双指针然后解除引用,然后将4添加到该结果。生成的地址将转换为声明如下的函数:

int __thiscall foo(int, int)

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

dword_10087418和v11是传递给此函数的整数。函数调用的结果保存在v4中。 C代码看起来像这样:

int v4 = foo(dword_10087418, v11);