原理分析
当调用一个虚函数时, 编译器生成的代码会调用 虚表地址[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