我正在使用 IDA Pro 6.3 对 Win32 .dll 进行静态分析,并将 Hex-Rays 反编译器与 IDA 反汇编器结合使用。我想了解这条线的作用。
v4 = (*(int (__thiscall **)(int, int))(*(_DWORD *)dword_10087418 + 4))(dword_10087418, v11);
它的格式类似于函数调用。当在子例程调用中使用指向函数的指针时,这是否是反编译代码的样子?
谢谢。
我正在使用 IDA Pro 6.3 对 Win32 .dll 进行静态分析,并将 Hex-Rays 反编译器与 IDA 反汇编器结合使用。我想了解这条线的作用。
v4 = (*(int (__thiscall **)(int, int))(*(_DWORD *)dword_10087418 + 4))(dword_10087418, v11);
它的格式类似于函数调用。当在子例程调用中使用指向函数的指针时,这是否是反编译代码的样子?
谢谢。
这很可能是 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
约定要求this
指针传入ecx
)。IDA 不会费心隐藏那个指针,因为那会让人感到困惑。
更多建议:获取ms_rtti
IDA 脚本并运行它以查找 DLL 中的虚拟方法表,然后搜索其他引用以dword_10087418
查看写入了哪些值 - 您应该能够确定哪个 vtable 与该对象关联并且然后找出正在调用的函数。
如果为类和相关的 vtable 定义存根结构类型,则可以使 Hex-Rays 以更易读的方式显示代码,然后告诉 IDA 指针使用该结构类型。
这是将 *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);