虚函数

1.关于虚函数
在名函数前加关键字“virtual”的函数为虚函数;
例如:class Base            
{            
public:            
    void Function_1()            
    {            
        printf("Function_1...\n");            
    }            
    virtual void Function_2()   //虚函数         
    {            
        printf("Function_2...\n");            
    }            
};    

 

反汇编分析:
可以看到:
    通过对象调用时,virtual函数与普通函数都是E8 Call  
    通过指针调用时,virtual函数是FF Call,也就是间接Call 
        pe的IAT表使用的就是FF Call ;
        使用间接call的原因是因为虚函数的地址不靠谱,可能被改掉;   
        比如,子类覆盖父类函数时;
 
1)虚函数的特点
#include "stdafx.h"
    class Base                     
    {      
    public:    
        int x;
        int y;
        Base(){
            x=1;
            y=2;
        }
        void fun(){
        }
        virtual fun2(){
        }
    };                      
                        
    int main(int argc, char* argv[])                    
    {                    
        Base b;
        Base* pb = &b;
        pb ->fun2();
 
        getchar();
        return 0;                
    }                         
测试上面结构的大小:Base base;            
printf("%x\n",sizeof(base));    
 结果是:0x0c;
普通函数放结构体里面时,不会影响结构体大小,结构大小应该是两个int的大小8个字节;
但在结构体中有一个或多个虚函数时,多了4个字节;
 
反汇编分析:
 调用结构体里面的函数时,会用ecx传递this指针;
this指针指向的就是对象的结构体;
可以看到:有虚函数的对象的结构体中在结构体开始处多了4个字节,存放的是42501c是一个地址,这个地址就是虚函数表的地址;      
将42501c存入edx,然后FF call这个地址;
 
如果有多个虚函数反汇编:
 可以看到,第一个虚函数call的是[edx],第二个虚函数call的是[edx+4];
 
总结:                            
    1、当类中有虚函数时,会多一个属性,4个字节                            
    2、多出的属性是一个地址,指向一张表,里面存储了所有虚函数的地址                            
 
2.解析虚表信息
class Base                    
{                    
public:                    
    int x;                
    int y;                
    virtual void Function_1()                    
    {                    
        printf("Function_1...\n");                    
    }                    
    virtual void Function_2()                    
    {                    
        printf("Function_2...\n");                    
    }                    
    virtual void Function_3()                    
    {                    
        printf("Function_3...\n");                    
    }                    
};                    
                    
void TestMethod()                    
{                    
    //查看 Sub 的虚函数表                
    Base base;                    
                    
    //对象的前四个字节就是虚函数表                
    printf("base 的虚函数表地址为:%x\n",*(int*)&base);                
                    
    //通过函数指针调用函数,验证正确性                
    typedef void(*pFunction)(void);                    
                    
    pFunction pFn;                
                    
    for(int i=0;i<3;i++)                
    {                
        int temp = *((int*)(*(int*)&base)+i);            
        pFn = (pFunction)temp;            
        pFn();            
    }                
                    
}                   
虚表的结构:
 
 
 
 
 
posted @ 2019-11-27 10:15  L丶银甲闪闪  阅读(344)  评论(0编辑  收藏  举报