5

公開されたインターフェイスのメソッドを実装する COM コクラスの vtable を反復/アクセスするにはどうすればよいですか?

インターフェイスの公開されたメソッドのすべてのアドレスが格納されている vtable の部分にアクセスする必要があります。

たとえば、Math は COM オブジェクトであり、その公開インターフェイスは「Operations」であり、「Sum」はこのインターフェイスのメソッドです。「Sum」のアドレスを取得するにはどうすればよいですか?

4

2 に答える 2

7

なぜこのようにしているのかを尋ねるつもりはありませんが、おそらくこれが役立つでしょう... すべての COM オブジェクトは、少なくとも IUnknown インターフェイスを実装する必要があります。したがって、COM オブジェクト インスタンスの最初の 4 バイトは、IUnknown オブジェクトへのポインターです。IUnknown オブジェクト (および仮想関数を持つその他のオブジェクト) の最初の 4 バイトは、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;
}
于 2010-12-07T09:46:33.227 に答える
0

質問で申し訳ありませんが、「どこから?」と尋ねなければなりません。

つまり、COM クライアントから vtable をどのように反復処理できるのかということですが、できないと思います。クライアント側では、COM サーバーとの通信方法 (おそらくクロス アパートメントまたはクロス プロセス) を認識しているプロキシしかありません。そのプロキシの vtable を調べることはできますが、COM サーバー内の関数のアドレスを知ることはできません。

もちろん、サーバーが実際に別のプロセスで実行されている場合、関数のアドレスはほとんど役に立たない可能性があります。サーバーが同じプロセスにあっても別のアパートメントにある場合でも、関数のアドレスを取得するのは危険な場合があります。関数を直接呼び出して、COM のインターセプトを回避し、スレッドの呼び出しに関するサーバー クラスの想定を破ることができます。

vtable を反復することは、目的を達成するための手段だと思います...? あなたが実際にやろうとしていることを投稿するかもしれません.COMにはおそらくそれを行う方法があると思います.

于 2010-07-22T13:04:06.497 に答える