类虚函数表原理实现分析(当我们将虚表地址[n]中的函数替换,那么虚函数的实现就由我们来控制了)

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了类虚函数表原理实现分析(当我们将虚表地址[n]中的函数替换,那么虚函数的实现就由我们来控制了)相关的知识,希望对你有一定的参考价值。

原理分析

当调用一个虚函数时, 编译器生成的代码会调用 虚表地址[0](param1, param2)这样的函数. 已经不是在调用函数名了.

当我们将虚表地址[n]中的函数实现改为另外的函数, 虚函数的实现就由我们来控制了.

 

实验

根据虚表原理, 实验一下修改自己程序的虚函数表项地址. 

使编译器生成的代码执行一个虚函数A时, 执行的是我们自己定义的非虚函数B.

 

知识点

* 使用union赋值, 绕过编译器函数与变量强转赋值的限制

 

* 类成员函数指针的执行

* 修改和恢复自己的代码段属性

* 虚函数表项的定位和读写

实验代码

 

[cpp] view plain copy
 
  1. // virtual void fnFoo(); ///< cc‘s fnFoo  
  2. typedef void (CC::*PFN_fnFoo)();  
  3.   
  4. typedef union un_function_pt  
  5. {  
  6.     PFN_fnFoo pfn;  
  7.     int ifunAddr;  
  8. }UN_FUNCTION_PT;  
  9.   
  10. void fnReplaceVirtualFunction()  
  11. {  
  12.     /// 替换虚表函数的实验  
  13.     /// 通过实验可知, CC虚函数有2个  
  14.     /// 虚函数1 CC析构函数  
  15.     /// 虚函数2 CC::fnFoo  
  16.       
  17.     /// 我们将 CC::fnFoo 在虚表中替换为 fnNewVirtualFunction()  
  18.       
  19.     int iVirtualTblAddr = 0; ///< CC虚函数表地址  
  20.     int iVirtualFunctionAddr_CC_fnFoo = 0; ///< CC::fnFoo 对象方法的地址  
  21.     UN_FUNCTION_PT unFunPt; ///< 用于int转fun*, 绕过编译器限制  
  22.     DWORD dwOldProtect = 0;  
  23.       
  24.     CA* pCA = new CC();  
  25.       
  26.     iVirtualTblAddr = *((int*)pCA);  
  27.     iVirtualFunctionAddr_CC_fnFoo = *((int*)iVirtualTblAddr + 1);  
  28.       
  29.     /// 执行CC.fnFoo虚函数的原始函数  
  30.     unFunPt.ifunAddr = iVirtualFunctionAddr_CC_fnFoo;  
  31.     (((CC*)pCA)->*unFunPt.pfn)();  
  32.       
  33.     /// 手工执行一下pCA的fnNewFunctionSameDefineAsfnFoo  
  34.     /// 让CC实例执行我们自己的指定的CC类成员函数  
  35.     /// 必须是CC类已经有的同参同返回值的函数  
  36.     unFunPt.pfn = &CC::fnNewFunctionSameDefineAsfnFoo;  
  37.     (((CC*)pCA)->*unFunPt.pfn)();  
  38.       
  39.     // make memory writable  
  40.     if (VirtualProtect((void*)iVirtualTblAddr, 8, PAGE_EXECUTE_READWRITE, &dwOldProtect))  
  41.     {  
  42.         /// 替换虚表中的CC::fnFoo 为 CC::fnNewFunctionSameDefineAsfnFoo  
  43.         unFunPt.pfn = &CC::fnNewFunctionSameDefineAsfnFoo;  
  44.           
  45.         ///< 不解除代码段0x0040的写限制, 会C05  
  46.         *((int*)iVirtualTblAddr + 1) = unFunPt.ifunAddr;  
  47.           
  48.         // reprotect  
  49.         VirtualProtect((void*)iVirtualTblAddr, 8, dwOldProtect, NULL);  
  50.           
  51.         /// 执行pCA->fnFoo变成了执行pCA->fnNewFunctionSameDefineAsfnFoo  
  52.         pCA->fnFoo();  
  53.           
  54.         /// ok 已经执行了我们自己指定的CC中的和CC::fnFoo同参同返回值的函数  
  55.         /// 这个函数可以是非虚函数  
  56.     }  
  57. }  

 

 

[cpp] view plain copy
 
  1. // ClassTest.h: interface for the CClassTest class.  
  2. //  
  3. //////////////////////////////////////////////////////////////////////  
  4.   
  5. #if !defined(AFX_CLASSTEST_H__D794CC4B_D79E_4A61_9D5A_95110788AE39__INCLUDED_)  
  6. #define AFX_CLASSTEST_H__D794CC4B_D79E_4A61_9D5A_95110788AE39__INCLUDED_  
  7.   
  8. #if _MSC_VER > 1000  
  9. #pragma once  
  10. #endif // _MSC_VER > 1000  
  11.   
  12. #include <iostream>  
  13.   
  14. using namespace std;  
  15.   
  16. class CA  
  17. {  
  18. public:  
  19.     CA();  
  20.     virtual ~CA();  
  21.     virtual void fnFoo();  
  22. };  
  23.   
  24. class CB : public CA  
  25. {  
  26. public:  
  27.     CB();  
  28.     virtual ~CB();  
  29.     virtual void fnFoo();  
  30. };  
  31.   
  32. class CC : public CB  
  33. {  
  34. public:  
  35.     CC();  
  36.     virtual ~CC();  
  37.     virtual void fnFoo();  
  38.     void fnNewFunctionSameDefineAsfnFoo();  
  39. };  
  40.   
  41.   
  42. #endif // !defined(AFX_CLASSTEST_H__D794CC4B_D79E_4A61_9D5A_95110788AE39__INCLUDED_)  

 

[cpp] view plain copy
 
  1. // ClassTest.cpp: implementation of the CClassTest class.  
  2. //  
  3. //////////////////////////////////////////////////////////////////////  
  4.   
  5. #include "ClassTest.h"  
  6.   
  7. //////////////////////////////////////////////////////////////////////  
  8. // CA  
  9. //////////////////////////////////////////////////////////////////////  
  10.   
  11. CA::CA()  
  12. {  
  13.     cout << "CA::CA" << endl;  
  14. }  
  15.   
  16. CA::~CA()  
  17. {  
  18.     cout << "CA::~CA" << endl;  
  19. }  
  20.   
  21. void CA::fnFoo()  
  22. {  
  23.     cout << "CA::fnFoo" << endl;  
  24. }  
  25.   
  26. //////////////////////////////////////////////////////////////////////  
  27. // CB  
  28. //////////////////////////////////////////////////////////////////////  
  29.   
  30. CB::CB()  
  31. {  
  32.     cout << "CB::CB" << endl;  
  33. }  
  34.   
  35. CB::~CB()  
  36. {  
  37.     cout << "CB::~CB" << endl;  
  38. }  
  39.   
  40. void CB::fnFoo()  
  41. {  
  42.     cout << "CB::fnFoo" << endl;  
  43. }  
  44.   
  45. //////////////////////////////////////////////////////////////////////  
  46. // CC  
  47. //////////////////////////////////////////////////////////////////////  
  48.   
  49. CC::CC()  
  50. {  
  51.     cout << "CC::CC" << endl;  
  52. }  
  53.   
  54. CC::~CC()  
  55. {  
  56.     cout << "CC::~CC" << endl;  
  57. }  
  58.   
  59. void CC::fnFoo()  
  60. {  
  61.     cout << "CC::fnFoo" << endl;  
  62. }  
  63.   
  64. void CC::fnNewFunctionSameDefineAsfnFoo()  
  65. {  
  66.     /// 用来替换虚函数的同参, 同返回值的函数  
  67.     cout << "CC::fnNewFunctionSameDefineAsfnFoo" << endl;  
  68. }  



实行效果

[cpp] view plain copy
 
  1. CA::CA  
  2. CB::CB  
  3. CC::CC  
  4. CC::fnFoo  
  5. CC::fnNewFunctionSameDefineAsfnFoo  
  6. CC::fnNewFunctionSameDefineAsfnFoo  

http://blog.csdn.net/lostspeed/article/details/50359445

以上是关于类虚函数表原理实现分析(当我们将虚表地址[n]中的函数替换,那么虚函数的实现就由我们来控制了)的主要内容,如果未能解决你的问题,请参考以下文章

[ C++ ] 多态原理 多态

自己的真实面试

虚函数调用过程(用汇编和几个例子解释)

c++虚表学习2

c++虚表学习2

c++虚表学习2