类虚函数表原理实现分析
发布日期:2021-06-30 22:07:57
浏览次数:3
分类:技术文章
本文共 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#includeusing 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 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!
发表评论
最新留言
网站不错 人气很旺了 加油
[***.192.178.218]2024年04月15日 10时13分53秒
关于作者
喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!
推荐文章
QNX相关资料整理
2019-05-01
Nacos Discovery Starter Configurations
2019-05-01
ConfigurationProperties实现
2019-05-01
loadbalancer动态刷新nacos的server
2019-05-01
@FeignClient注解的重复名称解决
2019-05-01
org.openjdk.jol
2019-05-01
自己解析class文件
2019-05-01
access_flags
2019-05-01
ClassFile之Fields
2019-05-01
ClassFile之Methods
2019-05-01
scala var val
2019-05-01
oracle sql
2019-05-01
spark单机安装
2019-05-01
java.net.BindException: 无法指定被请求的地址
2019-05-01
scala list
2019-05-01
多人协作流程与规范
2019-05-01
k8s设置阿里云仓库
2019-05-01
svn服务器安装
2019-05-01
spark 笔记1
2019-05-01
SVN服务器多个项目的权限分组管理
2019-05-01