hook com vtable entry

com interface 包括 d3d interface 都采用了 __stdcall 调用协议来声明成员函数,这样的声明使得编译出的汇编代码的传参中多出一个push,

所有参数push stack后,还会将对象对地址也push stack;

这样做的目的,使得可以用__stdcall 的 c函数来替换vtable中的函数,要求第一个参数是对象指针;其他参数和对应成员函数的参数相同;

因为com设计之初,就支持CINTERFACE.

 

#include  " objbase.h "
__declspec(novtable) 
interface  AA: public  IUnknown
{
public :
    
virtual  HRESULT STDMETHODCALLTYPE QueryInterface( 
            
/*  [in]  */  REFIID riid,
            
/*  [iid_is][out]  */  __RPC__deref_out  void  __RPC_FAR  * __RPC_FAR  * ppvObject) 
    {
        
return  S_OK;
    }

    
virtual  ULONG STDMETHODCALLTYPE AddRef(  void )
    {
        
return   0 ;
    }

    
virtual  ULONG STDMETHODCALLTYPE Release(  void )
    {
        
return   0 ;
    }
   
// 成员函数采用__stdcall 
     virtual   void  __stdcall v1( void *  p)
    {
    }
    
virtual   void  __stdcall v2( void *  p)
    {
    }
    
virtual   void  __stdcall v3( void *  p)
    {
    }
};
// c函数声明比AA::v1要多出一个AA* pthis参数
void  __stdcall fpv1( AA *  pthis, void *  p )
{
    pthis
-> v2(p);
}

int  _tmain( int  argc, _TCHAR *  argv[])
{
    AA aa1,aa2;

    unsigned 
int  p1  =   * (unsigned  int * ) & aa1;
    unsigned 
int  p2  =   * (unsigned  int * ) & aa2;
    unsigned 
int *  v  =  (unsigned  int * )p1;
    DWORD dwProtected 
=   0 ;

    VirtualProtect(v,
256 ,PAGE_EXECUTE_READWRITE, & dwProtected ); // 去掉可执行代码的写保护
    v[ 3 =  (unsigned  int ) & fpv1; // 替换v1所在的vtable条目
    AA *  pp1  =   & aa1;
    pp1
-> v1( NULL ); // 将会跳转到fpv1,查看汇编代码回看到push 0 之后还会有一个push pp1

    
return   0 ;
}


你可能感兴趣的:(table)