《C++反汇编与逆向分析技术揭秘》--虚函数 读书笔记

前言:

      虚函数是面向对象程序设计的关键部分,对象的多态性需要通过虚函数表和虚函数指针来完成,虚函数表指针被定义在对象首地址前四个字节地方,因此虚函数必须作为成员函数使用,由于非成员函数没有this指针,无法获得虚表指针,进而无法获得虚表,也就无法访问虚函数

 

这次学习主要解决认识几个问题:

  1. 为什么虚函数后需要提供默认的构造函数呢?

  2. 构造函数内发生了哪些变化呢?

  

虚函数的机制

编译器处理虚函数的方法是:为每个类对象添加一个隐藏成员,隐藏成员中保存了一个指向函数地址数组的指针,称为虚表指针(vptr),这种数组成为虚函数表(virtual function table, vtbl),即,每个类使用一个虚函数表,每个类对象用一个虚表指针。

下面实例:

 

虚函数的识别

鉴别类中是否出现了以下特征:

  • 类中隐式定义了一个数据成员;
  • 该数据成员在首地址处,占4字节;
  • 构造函数会将此数据成员初始化未某个数组(虚表)的首地址;
  • 这个地址属于数据区,是相对固定的地址;
  • 在这个数组内,每个元素都是函数指针;
  • 仔细观察这些函数,它们被调用时,第一个参数必然是this指针(要注意调用约定);
  • 在这些函数内部,很有可能对this指针使用相对间接的访问方式;
1 ;具有成员函数特征,传递对象首地址作为this指针
2 lea ecx,[ebp-8]    ;获取对象首地址(貌似对象首地址常在[ebp-8]中)
3 call XXXXXXXXh     ;调用函数
4  
5 ;调用函数的实现代码
6 mov reg,this       ;某寄存器得到对象首地址
7 ;向对象首地址处写入4字节数据,查看并确认此4字节数据是否为函数地址表的首地址

如遇以上代码,可高度怀疑为一个构造函数或者析构函数。查看并确认此4字节数据是否为函数地址表的首地址,即可判断是否为构造或析构函数。

如何区分构造函数与析构函数:

1、构造函数一定出现在析构函数之前,且构造函数执行前虚表指针没有指向虚表的首地址;

2、析构函数出现在所有成员函数之后,在实现过程中,虚表指针以及指向了某一个虚表的首地址。

posted @ 2020-04-25 23:15  坚持,每天进步一点点  阅读(314)  评论(0编辑  收藏  举报