类虚函数表原理实现分析(当我们将虚表地址[n]中的函数替换,那么虚函数的实现就由我们来控制了)
原理分析
当调用一个虚函数时, 编译器生成的代码会调用 虚表地址[0](param1, param2)这样的函数. 已经不是在调用函数名了.
当我们将虚表地址[n]中的函数实现改为另外的函数, 虚函数的实现就由我们来控制了.
实验
根据虚表原理, 实验一下修改自己程序的虚函数表项地址.
使编译器生成的代码执行一个虚函数A时, 执行的是我们自己定义的非虚函数B.
知识点
* 使用union赋值, 绕过编译器函数与变量强转赋值的限制
* 类成员函数指针的执行
* 修改和恢复自己的代码段属性
* 虚函数表项的定位和读写
实验代码
- // virtual void fnFoo(); ///< cc's fnFoo
- typedef 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 <iostream>
- 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::CA
- CB::CB
- CC::CC
- CC::fnFoo
- CC::fnNewFunctionSameDefineAsfnFoo
- CC::fnNewFunctionSameDefineAsfnFoo
http://blog.csdn.net/lostspeed/article/details/50359445
类虚函数表原理实现分析(当我们将虚表地址[n]中的函数替换,那么虚函数的实现就由我们来控制了)的更多相关文章
- C++虚函数表原理
C++中的虚函数的作用主要是实现了多态的机制.关于多态,简而言之就是用父类型别的指针指 向其子类的实例,然后通过父类的指针调用实际子类的成员函数.这种技术可以让父类的指针有“多种形态”,这是一种泛型技 ...
- C++类成员空间分配和虚函数表
最近在自学python,看到继承和类,就顺便复习了C++的类和继承等方面的知识. 先看Base基类 class Base { private: virtual void display() { cou ...
- C++ 类中有虚函数(虚函数表)时 内存分布
虚函数表 对C++ 了解的人都应该知道虚函数(Virtual Function)是通过一张虚函数表(Virtual Table)来实现的.简称为V-Table.在这个表中,主是要一个类的虚函数的地址表 ...
- (C/C++学习)4.C++类中的虚函数表Virtual Table
说明:C++的多态是通过一张虚函数表(Virtual Table)来实现的,简称为V-Table.在这个表中,主要为一个类的虚函数的地址表,这张表解决了继承.覆写的问题,保证其真实反应实际的虚函数调用 ...
- 我理解的C++虚函数表
今天拜读了陈皓的C++ 虚函数表解析的文章,感觉对C++的继承和多态又有了点认识,这里写下自己的理解.如果哪里不对的,欢迎指正.如果对于C++虚函数表还没了解的话,请先拜读下陈皓的C++ 虚函数表解析 ...
- 关于C++中虚函数表存放位置的思考
其实这是我前一段时间思考过的一个问题,是在看<深入探索C++对象模型>这本书的时候我产生的一个疑问,最近在网上又看到类似的帖子,贴出来看看: 我看到了很多有意思的答案,都回答的比较好,下面 ...
- C++虚函数表和对象存储
C++虚函数表和对象存储 C++中的虚函数实现了多态的机制,也就是用父类型指针指向其子类的实例,然后通过父类的指针调用实际子类的成员函数,这种技术可以让父类的指针有"多种形态",这 ...
- C++ 虚函数表解析
转载:陈皓 http://blog.csdn.net/haoel 前言 C++中 的虚函数的作用主要是实现了多态的机制.关于多态,简而言之就是用父类型别的指针指向其子类的实例,然后通过父类的指针调用实 ...
- C++虚函数和虚函数表
前导 在上面的博文中描述了基类中存在虚函数时,基类和派生类中虚函数表的结构. 在派生类也定义了虚函数时,函数表又是怎样的结构呢? 先看下面的示例代码: #include <iostream> ...
随机推荐
- Ext JS学习第四天 我们所熟悉的javascript(三)
此文用来记录学习笔记: •javascript之函数 •this关键字的使用 –this关键字总是指向调用者,谁调用函数,this就指向谁 •call.apply的使用 –call和apply主要应用 ...
- JS+CSS打造三级折叠菜单,自动收缩其它级 js
<html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="C ...
- [HDU 1016]--Prime Ring Problem(回溯)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1016 Prime Ring Problem Time Limit: 4000/2000 MS (Jav ...
- Android空指针异常的常见情况
把我经常遇到的nullpoitException写在这里,以便以后自己查找原因. 1.用findViewById(param )的方法获取一个view对象的时候,有的时候其实应该是获取一个layout ...
- Google Code Jam Round 1C 2015 Problem A. Brattleship
Problem You're about to play a simplified "battleship" game with your little brother. The ...
- HDU 5012 Dice DFS
简单DFS //#pragma comment(linker, "/STACK:16777216") //for c++ Compiler #include <stdio.h ...
- STRUTS2获得session和request
在struts1中,获得到系统的request或者session对象非常方便,都是按照形参传递的,但是在struts2中,request和session都被隐藏了struts提供两种方式访问sessi ...
- poj 2356鸽笼原理水题
关于鸽笼原理的知识看我写的另一篇博客 http://blog.csdn.net/u011026968/article/details/11564841 (需要说明的是,我写的代码在有答案时就输出结果了 ...
- 红黑树和AVL树的实现与比较-----算法导论
一.问题描述 实现3种树中的两种:红黑树,AVL树,Treap树 二.算法原理 (1)红黑树 红黑树是一种二叉查找树,但在每个结点上增加一个存储位表示结点的颜色,可以是red或black.红黑树满足以 ...
- go - 变量和常量
1.定义变量 goLang中定义变量的方式很多 先声明再使用:如果定义的变量未使用编译时会报错 a. /*定义单个变量*/ var varName type //定义一个 type 类型的变量 var ...