我正在使用IDA Pro 6.3对Win32 .dll进行静态分析,并使用Hex-Rays反编译器与IDA反汇编程序一起使用。我想了解这一行的作用。
v4 = (*(int (__thiscall **)(int, int))(*(_DWORD *)dword_10087418 + 4))(dword_10087418, v11);
它的格式类似于函数调用。这是在子程序调用中使用指向函数的指针时反编译代码的样子吗?
感谢。
答案 0 :(得分:1)
这很可能是C ++,而不是普通的C.这正是Visual C ++生成的虚拟方法调用的样子。我会说:
dword_10087418
是指向对象的指针。它可以是全局变量,也可以是静态变量,而不是本地变量。SomeClass::Instance->func(arg)
。如果您不熟悉C ++对象布局,则应阅读C++ Under the Hood,Reversing: Secrets of Reverse Engineering或Inside 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);