如何获取指向 COM 方法的指针以进行挂钩?

Posted

技术标签:

【中文标题】如何获取指向 COM 方法的指针以进行挂钩?【英文标题】:How to get a pointer to a COM method for hooking? 【发布时间】:2011-04-04 18:38:08 【问题描述】:

我知道这似乎是一个过度回答的问题,但这个问题不同。 我有这个导出一些方法的 ActiveX 对象。我需要在它的一种方法上设置一个钩子,即Func1,我知道如何使用VirtualProtect() 等来做到这一点。如果我打开ollydbg 并深入研究ActiveX DLL,我会看到@987654323 的地址@ 我需要设置钩子的地方。

使用 Visual Studio 2008,我正在使用预编译器指令:

#import "myactx.dll" no_namespace, named_guids, raw_interfaces_only

在我的代码中,我正在尝试这样做:

LPVOID ptr = &IMyActx::Func1;

编译时返回错误:

错误 C2440:“正在初始化”:无法从“HRESULT (__stdcall IMyActx::*)(BSTR,BSTR)”转换为“LPVOID”。

我研究并发现由于隐含的 this 参数,我无法将指向类方法的指针转换为指向函数的指针。

但是,我不打算调用这个函数。我只想知道它在内存中的地址,以便我可以将它传递给我的挂钩例程(它需要一个 LPVOID 指针)。

这对我来说似乎不可思议,我可以调用一个函数但不能在内存中获取它的原始地址。这让我想插入一些 x86 汇编代码只是为了得到我想要的指针。

非常感谢您的任何建议,感谢阅读。

编辑... 现在想起来了……LPVOID ptr = &IMyActx::Func1; 不应该工作,因为IMyActx 是一个纯虚拟类!无论如何,我在实例化一个对象之前尝试了一些组合并尝试获取指向Func1 的原始指针,但到目前为止没有任何效果。我在 ollydbg 中看到对Func1 的调用生成为:

mov edx, [eax];
call dword ptr ds:[edx + 0x1C];

所以我可以假设我需要在vptr + 0x1C 字节处读取DWORD,然后瞧。

如果我没记错的话,组件对象模型保证它总是位于[vptr + 0x1C]Func1 ptr 给定相同的接口ID。永远。对吧?

我可能会用一些伪代码来做这样的事情:

#define FUNC1_ENTRY   0x1C / sizeof(LPBYTE)

CoCreateInstance(CLSID_MyActx, 0, CLSCTX_ALL, IID_IMyActxObj, (LPVOID*) &pObj);

LPVOID pToHook = (*pObj)[FUNC1_ENTRY];

【问题讨论】:

指向方法的指针和指向函数的指针不可转换,因为标准不保证(故意)方法指针可以存储在 void* 中。而一个简单的函数指针可以存储在一个 void* 中。 @Martin reinterpret_cast 编译时返回:code 错误 C2440:'reinterpret_cast':无法从 'HRESULT (__stdcall IMyActx::* )(BSTR,BSTR)' 转换为 'LPVOID' 1>没有可以进行这种转换的上下文code 抱歉,这是一时冲动,虽然我认为是错误的。我把它拿出来是因为它不应该工作。 (注意方法指针可能比普通指针大。所以它不能转换成 void*)。 问题不仅在于指针大小,还在于ptm性质。如果它指向抽象类的虚拟方法,并且仅在您提供此方法时才调用分派;)?指向成员的指针根本不是“真正的”内存指针...... 您在 update 中描述的解决方案应该可以工作,但看起来很危险 :) 几年前,我使用绕道来连接 activex 对象。我刚刚使用了 ANSI C 版本的 activex 接口(你知道,midl 在一个文件中生成两个版本,一个用于 C,一个用于 C++)。 【参考方案1】:

COM 对象的方法实际上是普通的函数。这就是使 COM 客户端能够用 C 而不是 C++ 编写的原因。

我建议为 C 客户端生成头文件,然后可以轻松检索函数地址。但是,您首先需要一个要挂钩的类的实例。

【讨论】:

COM 对象的方法不是实际上是普通函数。如果将对象实现为 C++ 类,则不会有任何“常规”C 函数。使用C-client头文件,你不会只是得到一个stub方法的地址吗?然而,这对于 OP 的目的来说可能已经足够了。 @Andre:它们是使用 stdcall 调用约定的普通 C 函数。 COM 对象只不过是一个指向普通 C 函数指针结构的指针。这就是使 COM 服务器能够以非 C++ 语言编写的原因。存根仅涉及跨进程封送处理。事实上,Visual C++,当虚拟成员函数被声明为__stdcall 时,恰好生成了一个与 COM ABI 匹配的 vtable,这是一个令人高兴的巧合(尽管当然是由 Visual C++ 团队有意实现的)......所有的 COM 都定义在纯 C 的术语。【参考方案2】:

如果我理解正确,您想将指向类方法的指针转换为函数指针。

这实际上是不可能的。

简单示例:

class A 
    public:
    void func()
    
        this->var = 0;
    
    int var;
;

A myObj;
A::func* ptr2 = &(myObj::func); // works
void* ptr = &(myObj::func); // doesn't: what would "this" in line 5 point to?

你甚至不能使用reinterpret_cast

曾经也遇到过这个问题。然后我只需要创建一个函数,将输入值映射到指向对象的指针。也许您可以创建一个包装函数,在其中通过指向它的指针来调用该方法?

【讨论】:

在使用__stdcall 调用约定时情况会发生变化,因为它适用于所有 COM 对象方法。使用 stdcall 的类成员函数是一个以this 作为第一个参数的普通函数。 (对于使用默认的 __thiscall 调用约定的成员函数,情况并非如此。) 现在,即使成员函数是普通的__stdcall 函数,指向成员函数的指针仍然与函数指针不同,这是正确的。事实上,我不认为有一个简单的语法来获取一个普通的函数指针,一个可以读取 vtable 或者通过它的错位名称获取函数的地址。

以上是关于如何获取指向 COM 方法的指针以进行挂钩?的主要内容,如果未能解决你的问题,请参考以下文章

在 C++ 中,如何获取指向向量的指针?

如何获取数组指针?

如何获取在 C++ 中排序后保留的列表元素的指针

c ++如何获取指向另一个类中的当前对象的指针?

如何防止内存编辑以防止挂钩

如何获得指向类的复制构造函数的成员函数指针?