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;
}
__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;
}