关于C++虚函数Hook的一些小事儿

最近在做C++虚函数Hook的时候想起了一点比较有趣的东西,不是什么高深的技术,就是简单的记录一下。

做C++的对于虚函数和纯虚函数应该不陌生,简单来说就是用虚表的形式实现的,网上关于虚函数的理论知识和图太多,我这里就不贴了,直接用一段测试代码上调试器实际看一下。

类定义如下:

通过调试的结果可以直观的看出,对象this指针所指向的(*this)正好是虚表的地址,拿到了虚表的地址,我们就可以对虚表中的函数地址进行修改,或者直接调用里面的函数,反正能想到什么都能做。

先搞一个有意思的东西,直接调用一下虚表中的函数。

在这里要插一嘴,关于三种常见函数调用约定的东西,虽然这个也是老生常谈了。

__cdecl: C/C++默认方式,参数从右向左入栈,主调函数负责栈平衡。

__stdcall: Windows API默认方式,参数从右向左入栈,被调函数负责栈平衡。

__thiscall : C++成员函数调用方式,参数从右到左入栈,被调函数负责栈平衡,this指针存放于CX/ECX寄存器中。

C++成员函数都是__thiscall调用约定,又需要特别提到的,成员函数默认第一个参数是this指针【其实这都是基础我也不想多说

所以按下面的方式声明函数类型:

main中代码如下:

执行结果如下:

如果想要Hook虚表中的函数,这样是不够的,C风格函数无法定义__thiscall调用约定,所以要构造的函数第一个参数必须是this指针,但是__thiscall调用约定this指针是通过ECX传入的,我们通过栈传入this指针,实际上相当于多传了一个参数。如果对于无其他参数的函数,可以用__cdecl声明替换的函数,在函数外把多传的this指针平衡调;但是对于多参数的函数,无论用__cdecl还是__stdcall调用约定,都无法正常平衡堆栈,在Debug模式编译CheckEsp就会直接报栈不平,在Release编译模式下虽不会报错,但实际上栈是没有平衡的。所以我在这里选择构造一个类,在类中实现一个__thiscall调用约定的函数,然后替换进虚表中。

 

有了方法之后怎么利用就根据场景去做变通吧,其实这片真的很水,只是遇到了随便写一下记录一下。