虚函数HOOK

看来一些资料,觉得这篇写的比较好,做此笔记。

栗子如下:

#pragma once
#include <iostream>
using namespace std;

class A
{
public:
	int iVal1;
	int iVal2;

	virtual void print1()
	{
		cout<<"iVal1(A) = "<<iVal1<<endl;
	}

	virtual void print2()
	{
		cout<<"iVal2(A) = "<<iVal2<<endl;
	}

	virtual void print_all()
	{
		cout<<"iVal1(A) = "<<iVal1<<"\t"<<"iVal2(A) = "<<iVal2<<endl;
	}

	virtual void print_extern(int ext)
	{
		cout<<"ext(A) = "<<(ext+0)<<endl;
	}
};


class B
{
public:
	int iVal1;
	int iVal2;

	virtual void print1()
	{
		cout<<"iVal1(B) = "<<iVal1<<endl;
	}

	virtual void print2()
	{
		cout<<"iVal2(B) = "<<iVal2<<endl;
	}

	virtual void print_all()
	{
		cout<<"iVal1(B) = "<<iVal1<<"\t"<<"iVal2(B) = "<<iVal2<<endl;
	}

	virtual void print_extern(int ext)
	{
		cout<<"ext(B) = "<<(ext+100)<<endl;
	}

};
大家应该比较熟悉这两个类的内存结构,如图:

Mission 1:对象a去调用类B的函数
方法:寄存器ecx中放入对象a的地址,然后找到类B相应的函数指针,调用之。

// 1.对象a去调用类B的函数
void CallAMethodWithBObject(A* pA, B* pB)
{
	_asm
	{
		push eax                              // 暂存eax寄存器到堆栈中
		push ecx                              // 暂存ecx寄存器到堆栈中

		mov eax,dword ptr [pB]				  // pB对象地址所指的内容放入eax中(指向pb虚表)
		mov ecx,dword ptr [pA]                // pA虚表的地址放入ecx中

		mov eax,dword ptr [eax]               // pB虚表的地址放入eax中(pB对象的第一个元素)
		add eax,12                            // 虚表地址+12,即b对象的第4个函数B::print_extern()的地址
		push  4
		call dword ptr [eax]				  // 调用类B的函数B::print_all(),但是实际上传入a对象的变量(this指针放在ecx中)

		pop ecx                               // 从堆栈中弹回ecx
		pop eax                               // 从堆栈中弹回eax
	}
}
Mission 2:交换对象a和对象b的所有虚函数
方法:很简单,就是交换两个对象的虚表指针,如图。


代码如下:

// 2.交互两个对象的虚表地址
void exchangVB(A* pA, B* pB)
{
	_asm
	{
		push eax
		push ecx
		push esi
		push edi

		mov esi, dword ptr[pB]
		mov edi, dword ptr[pA]

		mov eax, dword ptr[esi]
		mov ecx, dword ptr[edi]

		mov dword ptr[esi], ecx
		mov dword ptr[edi], eax

		pop edi
		pop esi
		pop ecx
		pop eax
	}
}

Mission 3:交换类A和类B的第二个和第四个函数
方法:需要修改虚表,交换类A和类B的第二、四个函数,如图:


代码如下:

// 3.交换类A和类B的第二个和第四个函数
void ExchangeMethod(A* pA, B* pB)
{
	HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, ::GetCurrentProcessId());
	long** pplVrtableA = (long**)(pA);
	long** pplVrtableB = (long**)(pB);

	MEMORY_BASIC_INFORMATION mbiA = {0};
	if (VirtualQueryEx(hProcess, (LPVOID)(*pplVrtableA), &mbiA, sizeof(mbiA)) != sizeof(mbiA))
		return;

	MEMORY_BASIC_INFORMATION mbiB = {0};
	if (VirtualQueryEx(hProcess, (LPVOID)(*pplVrtableB), &mbiB, sizeof(mbiB)) != sizeof(mbiB))
		return;

	DWORD dwOldProtectA = 0;
	DWORD dwOldProtectB = 0;
	if(!::VirtualProtectEx(hProcess, mbiA.BaseAddress, mbiA.RegionSize, PAGE_EXECUTE_READWRITE, &dwOldProtectA)) 
		return;

	if(!::VirtualProtectEx(hProcess, mbiB.BaseAddress, mbiB.RegionSize, PAGE_EXECUTE_READWRITE, &dwOldProtectB)) 
		return;

	_asm
	{
		push eax                        //压入需要使用的寄存器到堆栈中
		push ecx
		push esi
		push edi

		mov esi,dword ptr [pA]          //a对象指针
		mov edi,dword ptr [pB]			//b对象指针
		mov esi,dword ptr [esi]         //a对象虚表地址
		mov edi,dword ptr [edi]         //b对象虚表地址

		add esi,4
		add edi,4

		mov eax,dword ptr [esi]         //交换第二个函数地址:print2
		mov ecx,dword ptr [edi]
		mov dword ptr [edi],eax
		mov dword ptr [esi],ecx

		add esi,8
		add edi,8

		mov eax,dword ptr [esi]        //交换第四个函数地址:print_extern
		mov ecx,dword ptr [edi]
		mov dword ptr [edi],eax
		mov dword ptr [esi],ecx

		pop edi
		pop esi
		pop ecx
		pop eax
	}

	DWORD dwTemp = 0;
	::VirtualProtectEx(hProcess, mbiA.BaseAddress, mbiA.RegionSize, dwOldProtectA, &dwTemp);
	::VirtualProtectEx(hProcess, mbiB.BaseAddress, mbiB.RegionSize, dwOldProtectB, &dwTemp);

	CloseHandle(hProcess);
}

Mission 4:hook类A的第三个函数
方法:比较麻烦,但是也是不难弄的。将类A的第三个虚函数指针替换成我们自己定义的地址,如同:


代码如下:

void* g_pSaveAddr = 0;

void load_hook(A* pA, DWORD hook_proc)
{
	HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, ::GetCurrentProcessId());
	long** pplVrtableA = (long**)(pA);

	MEMORY_BASIC_INFORMATION mbiA = {0};
	if (VirtualQueryEx(hProcess, (LPVOID)(*pplVrtableA), &mbiA, sizeof(mbiA)) != sizeof(mbiA))
		return;

	DWORD dwOldProtectA = 0;
	if(!::VirtualProtectEx(hProcess, mbiA.BaseAddress, mbiA.RegionSize, PAGE_EXECUTE_READWRITE, &dwOldProtectA)) 
		return;

	_asm
	{
		push eax
		push ecx

		mov eax,dword ptr [pA]              //获取对象指针
		mov eax,dword ptr [eax]             //获取虚表地址

		add eax,8                           //获取虚表中类A第三个函数指针的地址
		mov ecx,dword ptr [eax]             //取出类A第三个函数指针
		mov dword ptr [g_pSaveAddr],ecx		//保存到g_pAddr变量中
		mov ecx, dword ptr hook_proc		//替换为hook_proc指针
		mov dword ptr [eax],ecx

		pop ecx
		pop eax
	}

	cout<<"A::print_all() hooked!"<<endl;

	DWORD dwTemp = 0;
	::VirtualProtectEx(hProcess, mbiA.BaseAddress, 4, dwOldProtectA, &dwTemp);
	CloseHandle(hProcess);
}

void unload_hook(A* pA)
{
	HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, ::GetCurrentProcessId());
	long** pplVrtableA = (long**)(pA);

	MEMORY_BASIC_INFORMATION mbiA = {0};
	if (VirtualQueryEx(hProcess, (LPVOID)(*pplVrtableA), &mbiA, sizeof(mbiA)) != sizeof(mbiA))
		return;

	DWORD dwOldProtectA = 0;
	if(!::VirtualProtectEx(hProcess, mbiA.BaseAddress, mbiA.RegionSize, PAGE_EXECUTE_READWRITE, &dwOldProtectA)) 
		return;

	_asm
	{
		push eax
		push ecx

		mov eax,dword ptr [pA]              //获取对象指针
		mov eax,dword ptr [eax]             //获取虚表地址
		add eax,8                          //获取虚表中类A第三个函数指针的地址
		mov ecx,dword ptr [g_pSaveAddr]		//取出事先保存的A::print_all()地址
		mov dword ptr [eax],ecx

		pop ecx
		pop eax
	}

	cout<<"A::print_all() unhooked!"<<endl;

	DWORD dwTemp = 0;
	::VirtualProtectEx(hProcess, mbiA.BaseAddress, 4, dwOldProtectA, &dwTemp);
	CloseHandle(hProcess);
}
主函数如下:

int _tmain(int argc, _TCHAR* argv[])
{
	A a;
	a.iVal1 = 0;
	a.iVal2 = 1;

	B b;
	b.iVal1 = 1000;
	b.iVal2 = 1001;

	A* pA = &a;
	B* pB = &b;

	//CallAMethodWithBObject(pA, pB);
    //ExchangeMethod(pA, pB);
	//pA->print1();
	//pA->print2();
	//pA->print_all();
	//pA->print_extern(-200);

	//cout<<endl;

	//pB->print1();
	//pB->print2();
	//pB->print_all();
	//pB->print_extern(-200);

	load_hook(pA, DWORD(&hook_proc));
	pA->print_all();

	unload_hook(pA);
	pA->print_all();

	getchar();

	return 0;
}

本文引用:http://bbs.pediy.com/showthread.php?t=71775

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值