用detours对C++类成员函数加钩子
我所遇到的问题是,我想给一个flash中的某个函数加钩子,我知道这个函数的地址,但是它是一个C++的类成员函数。detours的安装目录下的samples\member就是一个如何对C++的类成员函数加hook的例子。
假设原来的函数声明是:
class CMember {
public:
void Target(const char* str);
};
一般来说,类成员函数都是遵守__thiscall。但是我们不能强行给一个全局函数加上__thiscall的修饰符。所以,首先,必须得先写一个虚假的类,然后重新声明这个函数。
class CDetour {
public:
void Mine_Target(const char* str);
};
然后我做了一点小技巧,把以前的函数声明成__stdcall
typedef void (__stdcall *pfunc)(const char* str);
pfunc oldfunc=(pfunc)0×00401040;
然后还是按以前那样attach,但是此时成员函数指针的转换很巧妙
DetourAttach( &(PVOID &)oldfunc,(PVOID)(&(PVOID&) A::func));
你不能把一个成员函数转换成void*,但是你可以把它转换成void*&。
顺便今天发现一个技巧,这样输出的结果是一个index,如0、1、2
void CMember::Target(const char* str){
std::cout<<&CMember::Target<<std::endl;
}
但是这样输出的就是函数地址:
void CMember::Target(const char* str){
std::cout<<(void*&)CMember::Target<<std::endl;
}
嗯,继续说,Mine_Target的实现
我想到的第一个方法是,利用__stdcall模拟__thiscall。
先保存ecx,并用this给ecx赋值。p.s.如果不是this,而是一个栈变量,mov就要换成lea。
__asm{
push ecx;
mov ecx,this;
}
然后调用以前的函数:
oldfunc(str);
然后恢复ecx:
__asm{
pop ecx;
}
这里利用的原理就是,__stdcall和__thiscall的区别仅在于后者多传一个ecx。但是这种方法有时候不成功。因为在调用oldfunc的时候,需要传递参数,此时有可能会利用ecx作临时寄存器,先把参数mov到ecx中,然后push。
我最后的办法是用__fastcall来模拟__thiscall,这种方法很优雅,不需要内联汇编。原来的函数定义就变成了
typedef char (__fastcall *pFunc)(void* pthis,int dummy,const char *str);
按照__fastcall的规范,最前面2个参数应该通过ecx,edx传递,后面的从右向左依次push。相当于我多传递了一个edx,无所谓啦。
作者 changming
补充:软件开发 , C++ ,