欢迎来到 嗅灵易学

零基础也能上手的脚本技术课,一对一答疑带你入门

C++类虚函数逆向学习总结

C++类虚函数逆向学习总结

[摘要]受menting影响,也对C++也逆向了一把.由于刚刚接触逆向,都是自己学习总结的,又是第一次发贴,因此不免有误解之处,还请各位多多指教,谢谢.

[正文]先来看一下C++类的虚函数的实例:
class clsC
{
private:
  int m_c;
public:
  clsC(){m_c=0;}
  ~clsC(){};
  void show(){cout<<"I'm in BaseC Class.";};
  void show2(){cout<<"I'm in BaseC Class2.";}
};
class clsB:public clsC
{
private:
  int m_b;
public:
  clsB(){m_b=0;}
  ~clsB(){};
  virtual void show(){cout<<"I'm in BaseB Class.";}
  virtual void show2(){cout<<"I'm in BaseB Class2.";}
};
class clsA:public clsB
{
private:
  int m_a;
  int m_b;
  int m_c;
public:
  clsA();
  ~clsA(){};
  virtual void show(){cout<<"I'm in sub Class.";}
};
clsA::clsA():m_b(1),m_c(2),m_a(0)
{
}
void main()
{
  clsA a;       //局部实例类,main函数反汇编代码如下:
  clsB *pb = &a;
  clsC *pc = &a;
  pb->show2();
  pc->show();
}

sub esp,24 在堆栈中为局部变量a和指针pb、pc、临时指针分配36字节.其中clsA类大小为24字节(clsA有3*4=12字节成员变量, clsB有4字节成员变量, clsC有4字节成员变量,虚函数有个指向vtable的虚函数表指针,占4字节.因此一共12+4+4+4=24)
构造函数反汇编如下:

派生类的构造函数首先调用基类的构造函数,基类clsB的构造函数如下:

类clsB的构造函数又调用基类clsC的构造函数:

由于顶层基类clsC无虚函数,因此可见,clsB类的虚函数表vtable指针也占用类的第1个DWORD空间.故类的派生结构体系中,如果存在虚函数,则虚函数表vtable指针一定占用类的第1个DWORD位置.基类clsB的构造函数将基类的所有虚函数的地址存放到虚函数地址表vtable中:
    下面看一下这两个地址所指向的汇编代码:


可见基类clsB的虚函数表指向基类clsB的虚函数地址show()和show2()
但基类构造完后,派生类的构造函数改写了这个虚函数表vtable指针.下面看下派生类的虚函数表vtable指针:
    下面看一下这两个地址所指向的汇编代码:


由于派生类无show2()函数,因此可见派生类的虚函数表指向派生类的虚函数地址show()和基类的虚函数show2().
因此,整个构造函数中,派生类的虚函数表vtable指针会改写基类的虚函数表vtable指针来实现虚函数的特性.以后调用虚函数时直接从虚函数表vtable中获取函数的地址来调用.
如果派生类中没有重写基类的某虚函数,则将在派生类的虚函数表vtable中使用基类的某虚函数地址.
这里pc->show();的调用由于为非虚函数,因此不再使用虚函数特性.反汇编代码显示在编译时使用了clsC:: show()函数地址的硬编码的调用方式.
最后整个clsA类在栈的分配结构图如下:

注意:上传附件及图片大小不得大于30M。

⚠️ 版权声明:
本博客所有内容(含教程、源码、工具)仅供个人技术学习与研究交流使用,严禁商用、倒卖、二次分发及非法用途
未经作者书面授权,任何组织或个人不得转载、复制或用于其他平台,违者将追究相关责任。

0 0 0 举报
复制成功