类虚函数表原理实现分析
发布日期:2021-06-30 22:07:57 浏览次数:2 分类:技术文章

本文共 3234 字,大约阅读时间需要 10 分钟。

原理分析

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

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

实验

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

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

知识点

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

* 类成员函数指针的执行

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

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

实验代码

// virtual void fnFoo(); ///< cc's fnFootypedef void (CC::*PFN_fnFoo)();typedef union un_function_pt{    PFN_fnFoo pfn;    int ifunAddr;}UN_FUNCTION_PT;void fnReplaceVirtualFunction(){    /// 替换虚表函数的实验    /// 通过实验可知, CC虚函数有2个    /// 虚函数1 CC析构函数    /// 虚函数2 CC::fnFoo        /// 我们将 CC::fnFoo 在虚表中替换为 fnNewVirtualFunction()        int iVirtualTblAddr = 0; ///< CC虚函数表地址    int iVirtualFunctionAddr_CC_fnFoo = 0; ///< CC::fnFoo 对象方法的地址    UN_FUNCTION_PT unFunPt; ///< 用于int转fun*, 绕过编译器限制    DWORD dwOldProtect = 0;        CA* pCA = new CC();        iVirtualTblAddr = *((int*)pCA);    iVirtualFunctionAddr_CC_fnFoo = *((int*)iVirtualTblAddr + 1);        /// 执行CC.fnFoo虚函数的原始函数    unFunPt.ifunAddr = iVirtualFunctionAddr_CC_fnFoo;    (((CC*)pCA)->*unFunPt.pfn)();        /// 手工执行一下pCA的fnNewFunctionSameDefineAsfnFoo    /// 让CC实例执行我们自己的指定的CC类成员函数    /// 必须是CC类已经有的同参同返回值的函数    unFunPt.pfn = &CC::fnNewFunctionSameDefineAsfnFoo;    (((CC*)pCA)->*unFunPt.pfn)();        // make memory writable    if (VirtualProtect((void*)iVirtualTblAddr, 8, PAGE_EXECUTE_READWRITE, &dwOldProtect))    {        /// 替换虚表中的CC::fnFoo 为 CC::fnNewFunctionSameDefineAsfnFoo        unFunPt.pfn = &CC::fnNewFunctionSameDefineAsfnFoo;                ///< 不解除代码段0x0040的写限制, 会C05        *((int*)iVirtualTblAddr + 1) = unFunPt.ifunAddr;                // reprotect        VirtualProtect((void*)iVirtualTblAddr, 8, dwOldProtect, NULL);                /// 执行pCA->fnFoo变成了执行pCA->fnNewFunctionSameDefineAsfnFoo        pCA->fnFoo();                /// ok 已经执行了我们自己指定的CC中的和CC::fnFoo同参同返回值的函数        /// 这个函数可以是非虚函数    }}

// ClassTest.h: interface for the CClassTest class.////#if !defined(AFX_CLASSTEST_H__D794CC4B_D79E_4A61_9D5A_95110788AE39__INCLUDED_)#define AFX_CLASSTEST_H__D794CC4B_D79E_4A61_9D5A_95110788AE39__INCLUDED_#if _MSC_VER > 1000#pragma once#endif // _MSC_VER > 1000#include 
using namespace std;class CA{public: CA(); virtual ~CA(); virtual void fnFoo();};class CB : public CA{public: CB(); virtual ~CB(); virtual void fnFoo();};class CC : public CB{public: CC(); virtual ~CC(); virtual void fnFoo(); void fnNewFunctionSameDefineAsfnFoo();};#endif // !defined(AFX_CLASSTEST_H__D794CC4B_D79E_4A61_9D5A_95110788AE39__INCLUDED_)
// ClassTest.cpp: implementation of the CClassTest class.////#include "ClassTest.h"//// CA//CA::CA(){    cout << "CA::CA" << endl;}CA::~CA(){    cout << "CA::~CA" << endl;}void CA::fnFoo(){    cout << "CA::fnFoo" << endl;}//// CB//CB::CB(){    cout << "CB::CB" << endl;}CB::~CB(){    cout << "CB::~CB" << endl;}void CB::fnFoo(){    cout << "CB::fnFoo" << endl;}//// CC//CC::CC(){    cout << "CC::CC" << endl;}CC::~CC(){    cout << "CC::~CC" << endl;}void CC::fnFoo(){    cout << "CC::fnFoo" << endl;}void CC::fnNewFunctionSameDefineAsfnFoo(){    /// 用来替换虚函数的同参, 同返回值的函数    cout << "CC::fnNewFunctionSameDefineAsfnFoo" << endl;}

实行效果

CA::CACB::CBCC::CCCC::fnFooCC::fnNewFunctionSameDefineAsfnFooCC::fnNewFunctionSameDefineAsfnFoo

转载地址:https://lostspeed.blog.csdn.net/article/details/50359445 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:未知类函数指针的size
下一篇:中文关键字编程

发表评论

最新留言

表示我来过!
[***.240.166.169]2024年04月23日 21时31分17秒