读书人

经过虚函数指针绕过虚函数的保护机制

发布时间: 2013-02-15 15:46:56 作者: rapoo

通过虚函数指针绕过虚函数的保护机制

#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                          --入栈,压参1000414501 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;}



3楼chen_ang1小时前
期待楼主下一次的分享
2楼pochioly昨天 15:08
不是VC++不一定用ECX传this,下面是C++允许的做法n[code=cpp]nint main(){n A a; n typedef void (A:: *gFUNC)(int); n int* v_ptrAdrs = *((int**)&a); n gFUNC funcAddr = *((gFUNC*)v_ptrAdrs); nn A* pp = &a; n (pp->*((gFUNC)funcAddr))(10); n return 0; n}nnn[/code]
Re: fengqiao1999昨天 23:59
回复pochiolyn传this的方式,不同编译器应该是不一样的,我这个只是针对vc++。(pp->*((gFUNC)funcAddr))(10); 这种方式确实简单多了,而且可行,谢谢楼主的支持!!
1楼chen_ang昨天 15:07
好呀,开了眼界,我又学到了一招!

读书人网 >编程

热点推荐