#include <iostream>
using namespace std;
class A
{
public:
A()
{
a = 10;
}
private:
virtual void Func1()
{
cout << "class A Func1" << endl;
cout << a << endl;
}
virtual void Func2()
{
cout << "class A Func2" << endl;
}
private:
int a;
};
int _tmain(int argc, _TCHAR* argv[])
{
A a;
//得到虚表的地址
int* v_ptrAdrs = *((int**)&a);
//得到虚表中的第一个值
int* funcAddr = *((int**)v_ptrAdrs);
typedef void (*gFUNC)();
A* pp = &a;
//如果你用的是vs,可以通过汇编压入this指针,目前只在vs2008下测试过
__asm mov ecx, pp;
//直接调用虚函数,此处绕过了private的保护
(*(gFUNC)funcAddr)();
return 0;
}
当然,这只能是在没有参数的情况下才能调用成功,如果存在参数,那么还是会失败,下面我们修改一下类A,为函数添加一个入参:
class A
{
public:
A()
{
a = 10;
}
public:
virtual void Func1(int para)
{
cout << "class A Func1" << endl;
cout << a*para << endl;
}
virtual void Func2()
{
cout << "class A Func2" << endl;
}
private:
int a;
};
我们通过汇编代码来查看为什么会失败,截取汇编代码如下:
(*(gFUNC)funcAddr)(10);
004144FD 8B F4 mov esi,esp
004144FF 6A 0A push 0Ah --入栈,压参10
00414501 FF 55 DC call dword ptr [funcAddr] --调用函数,跟入函数内部,我们会发现,函数的最后会进行出栈操作
00414504 83 C4 04 add esp,4 --出栈
00414507 3B F4 cmp esi,esp
00414509 E8 BE CC FF FF call @ILT+455(__RTC_CheckEsp) (4111CCh)
通过上述汇编代码,就会发现,错误出在调用方式上,下面只要稍作改动就可以成功了。
int _tmain(int argc, _TCHAR* argv[])
{
A a;
//得到虚表的地址
int* v_ptrAdrs = *((int**)&a);
//得到虚表中的第一个值
int* funcAddr = *((int**)v_ptrAdrs);
typedef void (__stdcall *gFUNC)(int);
A* pp = &a;
//如果你用的是vs,可以通过汇编压入this指针,目前只在vs2008下测试过
__asm mov ecx, pp;
//直接调用虚函数,此处绕过了private的保护
(*(gFUNC)funcAddr)(10);
return 0;
}