AddressHook -- 虚函数Hook

c++

Posted by YiMiTuMi on May 8, 2020

虚函数Hook

在编译后,虚函数表就是一个固定的表了,它位于PE的.rdata段。

对虚函数表进行Hook:查找原函数位置、修改页面属性、写入Detour函数的地址。

步骤:

1)确定虚函数表中的函数位置及函数原型:在C++类中如果有虚函数成员,那么第一个元素就是虚函数表,也就是地址表,重载就是用子类的方法去覆盖父类的方法,也就是地址替换(实际上Hook时也是这么做的)。

2)根据目标函数的原型定义类,每个类都有一个与TargetFun相同的虚函数成员。

3)修改虚函数表,实现Hook。

.h文件: 关联第1步

#include <iostream>

using namespace std;

class base
{
public:
	virtual int AddNew(int a, int b);
	virtual void g(){cout << "base::g" << endl;};
	virtual void h(){cout << "base::h" << endl;};
	void novirtual(){cout << "base::not virtual" << endl;};
};


class DetourClass
{
public:
	virtual int DetourFun(int a, int b);
};


class TrampolineClass
{
public:
	virtual int TrampolineFun(int a, int b){return 0;};
};

.cpp文件:关联第2步

#include "stdafx.h"
#include <windows.h>
#include "VirtualHook.h"
#include <iostream>

using namespace std;


int DetourClass::DetourFun(int a, int b)
{
	printf("Hook good\n");
	return a + b;
}


int base::AddNew(int a, int b)
{
	return a - b;
}

.main函数:Hook的实现

#include "stdafx.h"
#include <windows.h>
#include "VirtualHook.h"
#include <iostream>

using namespace std;

DWORD GetClassVirtualFnAddress(DWORD * BaseAddr, int count)
{

	DWORD dwOLD;
	MEMORY_BASIC_INFORMATION mbi;
	ULONG uAddr = 0;
	DWORD dwReturn;

	VirtualQuery(BaseAddr, &mbi, sizeof(mbi));
	VirtualProtect(mbi.BaseAddress, mbi.RegionSize, PAGE_EXECUTE_READWRITE, &dwOLD);

	dwReturn = BaseAddr[count];
	//恢复内存页属性
	VirtualProtect(mbi.BaseAddress, mbi.RegionSize, dwOLD, 0);

	return dwReturn;		
}

//Hook实现
void HookClassMemberByAnotherClassMember()
{
	base b;
	base *pbase = &b;
	
	TrampolineClass CTr;
	TrampolineClass* pCTr = &CTr;

	DetourClass DeC;
	DetourClass* pDeC = &DeC;

	DWORD dwOLD;
	MEMORY_BASIC_INFORMATION mbi;
	ULONG uAddr = 0;

	DWORD *vfTableToHook = (DWORD *) *(DWORD*) pbase;
	DWORD *vfTableTrampoline = (DWORD*) * (DWORD*) pCTr;
	DWORD *vfDetourClass = (DWORD*) * (DWORD*) pDeC;

	VirtualQuery(vfTableTrampoline, &mbi, sizeof(mbi));
	VirtualProtect(mbi.BaseAddress, mbi.RegionSize, PAGE_EXECUTE_READWRITE, &dwOLD);

	//在C++类中如果有虚函数成员,那么第一个元素就是虚函数表,也就是地址表,重载就是用子类的方法去覆盖父类的方法,也就是地址替换(实际上Hook时也是这么做的)。
	//修改Trampoline的虚函数表,原函数位于第几个这里就是第几个,位置必须一样

	vfTableTrampoline[0] = (DWORD)GetClassVirtualFnAddress(vfTableToHook, 0);
	
	//恢复内存页属性
	VirtualProtect(mbi.AllocationBase, mbi.RegionSize, dwOLD, 0);


	VirtualQuery(vfTableToHook, &mbi, sizeof(mbi));
	VirtualProtect(mbi.AllocationBase, mbi.RegionSize, PAGE_EXECUTE_READWRITE, &dwOLD);
	vfTableToHook[0] = (DWORD)GetClassVirtualFnAddress(vfDetourClass, 0);
	VirtualProtect(mbi.BaseAddress, mbi.RegionSize, dwOLD, 0);

	int result = pbase->AddNew(1, 2); //会调用DetourFun函数
	printf("result = %d \nafter call member fun.\n", result);

}

int _tmain(int argc, _TCHAR* argv[])
{
	HookClassMemberByAnotherClassMember();

	system("pause");
	return 0;
}

连翘 – 步步高升