zoukankan      html  css  js  c++  java
  • 类虚函数表原理实现分析(当我们将虚表地址[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

  • 相关阅读:
    鸿蒙的js开发模式19:鸿蒙手机下载python服务器端文件的实现
    【资源下载】Linux下的Hi3861一站式鸿蒙开发烧录(附工具)
    并发编程大扫盲:带你了解何为线程上下文切换
    内存溢出 MAT 排查工具,它真香香香
    面试官问:如何排除GC引起的CPU飙高?我脱口而出5个步骤
    小学妹问我:如何利用可视化工具排查问题?
    你不得不知的6个JDK自带JVM调优工具
    那个小白还没搞懂内存溢出,只能用案例说给他听了
    听说同学你搞不懂Spring Boot集成Mybatis的玩法,田哥来教你
    手把手教你设置JVM调优参数
  • 原文地址:https://www.cnblogs.com/findumars/p/5187277.html
Copyright © 2011-2022 走看看