【问题标题】:How to iterate the vtable of COM coclass?如何迭代 COM coclass 的 vtable?
【发布时间】:2011-01-26 01:19:05
【问题描述】:

如何迭代/访问 COM coclass 的 vtable,它将实现其公开接口的方法?

我需要访问存储其接口公开方法的所有地址的 vtable 部分。

例如Math是COM对象,它暴露的接口是“Operations”,“Sum”是这个接口的方法,如何获取“Sum”的地址?

【问题讨论】:

    标签: com vtable


    【解决方案1】:

    我不会问你为什么要这样做,但也许这会有所帮助...... 每个 COM 对象必须至少实现 IUnknown 接口。因此,COM 对象实例的前四个字节是指向 IUnknown 对象的指针。 IUnknown 对象(以及任何其他具有虚函数的对象)的前四个字节是指向 vtbl 的指针。

    (此示例中没有错误检查,因此请不要在该主题上分叉。)

    我使用了 IReferenceClock 的实例进行演示。

    int main()
    {
    
        CoInitialize( NULL );
    
        IReferenceClock* pRefClock;
        HRESULT hr = CoCreateInstance( CLSID_SystemClock, NULL, CLSCTX_INPROC_SERVER, IID_IReferenceClock, (void**)&pRefClock );
    
        DWORD* pIUnknownAddress = (DWORD*)pRefClock;
        DWORD* pVTBLaddress = (DWORD*)*pIUnknownAddress;
    
        // for example, the next interface could be accessed like this
        DWORD* pNextInterfaceAddress = ( (DWORD*)pRefClock ) + 1;
        DWORD* pNextVTBLaddress = (DWORD*)*pNextInterfaceAddress;
        // and you would access virtual functions in the same way as QueryInterface, AddRef and Release below in this example
    
        HRESULT (__stdcall *pQueryInterfaceFunction)(void*, REFIID, void**);
        ULONG (__stdcall *pAddRef)( void* );
        ULONG (__stdcall *pRelease)( void* );
    
        // IUnknown looks like this:
        // 
        // virtual HRESULT QueryInterface( REFIID riid, void** ppvObject);
        // virtual ULONG AddRef( void );
        // virtual ULONG Release( void );
        //
        // So, the first function in vtbl is QueryInterface, the second is AddRef...
    
        pQueryInterfaceFunction = (HRESULT (__stdcall*)(void*, REFIID, void**))*pVTBLaddress;
        pAddRef = (ULONG (__stdcall *)( void* ))*( pVTBLaddress + 1 );
        pRelease = (ULONG (__stdcall *)( void* ))*( pVTBLaddress + 2 );
    
        // Note: extra void* is actually this pointer.. see below that we pass pRefClock to every call
    
        IUnknown* pUnknown;
        UINT nRefCount;
    
        hr = pQueryInterfaceFunction( pRefClock, IID_IUnknown, (void**)&pUnknown );
    
        if( SUCCEEDED( hr ) )
        {
            nRefCount = pUnknown->Release();
            ATLTRACE( TEXT( "nRefCount = %d\n" ), nRefCount );
        }
    
        nRefCount = pAddRef( pRefClock );
        ATLTRACE( TEXT( "nRefCount after AddRef() call = %d\n" ), nRefCount );
    
        nRefCount = pRelease( pRefClock );
        ATLTRACE( TEXT( "nRefCount after Release() call = %d\n" ), nRefCount );
    
        nRefCount = pRefClock->Release();
    
        CoUninitialize();
    
        return 0;
    }
    

    【讨论】:

    • 赞成不要尝试就“不良做法”进行演讲或询问“为什么需要它”,而是提供答案。
    • 冰淇淋,非常感谢您的评论。我是认真的,因为几乎不可能找到不需要在任何可用主题上分头的开发人员。干杯!!!
    【解决方案2】:

    很抱歉回答一个问题,但我必须问“从哪里来?”

    如果您的意思是,如何从 COM 客户端遍历 vtable,我认为您不能。在客户端,您所拥有的只是一个知道如何与 COM 服务器通信(可能是跨公寓或跨进程)的代理。您也许可以探测该代理的 vtable,但它永远无法告诉您 COM 服务器中函数的地址。

    当然,如果服务器实际上运行在不同的进程中,函数的地址可能对你没什么用处。即使服务器在同一个进程中,但在不同的单元中,获取函数地址也可能是危险的:你可以直接调用函数,绕过 COM 的拦截,打破服务器类对调用线程的假设等。

    我猜想迭代 vtable 是一种达到目的的手段...?也许发布您实际尝试做的事情,我认为 COM 可能有办法做到这一点。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-11-01
      • 1970-01-01
      • 1970-01-01
      • 2022-08-10
      • 1970-01-01
      • 2013-02-26
      • 2011-03-21
      • 2011-10-24
      相关资源
      最近更新 更多