当前位置:编程学习 > C/C++ >>

用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++ ,
CopyRight © 2022 站长资源库 编程知识问答 zzzyk.com All Rights Reserved
部分文章来自网络,