// HookVtable.cpp : Defines the entry point for the console application.
//

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

using namespace std;

class Test{
private:
	HANDLE m_hProcess;
	DWORD m_dwOldProtectFlag;
	ULONG_PTR** m_pplVrtable;
	ULONG_PTR m_OldProcAddress;
	size_t m_sizeRead;
	MEMORY_BASIC_INFORMATION mbi;
public:
	Test() :m_hProcess(NULL),
		m_dwOldProtectFlag(0),
		m_pplVrtable(NULL),
		m_OldProcAddress(0),
		m_sizeRead(0)
	{
		ZeroMemory(&mbi, sizeof(mbi));
	}
	~Test()
	{
	};
	virtual void fun1()
	{
		cout <<this<<":"<< "fun1 called!" << endl;
	}
	virtual void fun2()
	{
		cout << this << ":" << "fun2 called!" << endl;
	}
	virtual void fun3()
	{
		cout << this << ":" << "fun3 called!" << endl;
	}
	void Hook(ULONG_PTR dwAddFun)
	{
		m_pplVrtable = (ULONG_PTR**)(this);
		m_hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, ::GetCurrentProcessId());
		if (VirtualQueryEx(m_hProcess, (LPVOID)(*m_pplVrtable), &mbi, sizeof(mbi)) != sizeof(mbi))
			return;
		if (!VirtualProtectEx(m_hProcess, mbi.BaseAddress, 16, PAGE_EXECUTE_READWRITE, &m_dwOldProtectFlag))
			return;
		ReadProcessMemory(m_hProcess, &(*m_pplVrtable)[1], &m_OldProcAddress, sizeof(ULONG_PTR), &m_sizeRead);
		(*m_pplVrtable)[1] = dwAddFun;

	}
	void UnHook()
	{
		DWORD dwTemp = 0;
		(*m_pplVrtable)[1] = m_OldProcAddress;
		VirtualProtectEx(m_hProcess, mbi.BaseAddress, 16, m_dwOldProtectFlag, &dwTemp);
		CloseHandle(m_hProcess);
	}

};

void MyFun()
{
	cout << "This is fake function" << endl;
}

int _tmain(int argc, _TCHAR* argv[])
{
	Test* pA = new Test;
	Test* pA2 = new Test;
	pA->Hook((ULONG_PTR)MyFun);
	pA->fun1();
	pA->fun2();
	pA2->fun2();
	pA->UnHook();
	pA->fun1();
	pA->fun2();
	pA2->fun2();
	delete pA;
	return 0;
}

 

同一个进程下 某个类的虚函数列表是唯一的, 所有类对象共享 ,类对象的this指针指向的第一个地址就是虚函数表的地址。

修改表中某个虚函数的地址就能修改所有类对象的函数跳转 (虚函数的索引 是虚函数在类里面的排序位置 由0开始)。

以上就是HOOK COM API的基本原理

测试一下吧

ITextServices* pTextServices = NULL;
typedef HRESULT(ITextServices::*TrueTxSendMessage)(UINT msg, WPARAM wparam, LPARAM lparam, LRESULT *plresult);
TrueTxSendMessage g_func = NULL;


HRESULT STDMETHODCALLTYPE FakeTxSendMessage(
	UINT msg,
	WPARAM wparam,
	LPARAM lparam,
	LRESULT *plresult)
{
	MessageBox(NULL, _T("FakeTxSendMessage"), _T("FakeTxSendMessage"), MB_OK);
	return (pTextServices->*(g_func))(msg,wparam,lparam,plresult);
}

HANDLE m_hProcess = NULL;
DWORD** m_pplVrtable = NULL;
DWORD m_dwOldProtectFlag = 0;
DWORD m_OldProcAddress = 0;
DWORD m_sizeRead = 0;
MEMORY_BASIC_INFORMATION mbi = {0};
void Hook(DWORD dwAddFun, ITextServices* pITextServices)
{
	m_pplVrtable = (DWORD**)(pITextServices);
	m_hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, ::GetCurrentProcessId());
	if (VirtualQueryEx(m_hProcess, (LPVOID)(*m_pplVrtable), &mbi, sizeof(mbi)) != sizeof(mbi))
		return;
	if (!VirtualProtectEx(m_hProcess, mbi.BaseAddress, 16, PAGE_EXECUTE_READWRITE, &m_dwOldProtectFlag))
		return;
	ReadProcessMemory(m_hProcess, &(*m_pplVrtable)[3], &m_OldProcAddress, sizeof(DWORD), &m_sizeRead);
	memcpy(&g_func, &m_OldProcAddress, sizeof(DWORD));
	(*m_pplVrtable)[3] = dwAddFun;

}
void UnHook()
{
	DWORD dwTemp = 0;
	(*m_pplVrtable)[3] = m_OldProcAddress;
	VirtualProtectEx(m_hProcess, mbi.BaseAddress, 16, m_dwOldProtectFlag, &dwTemp);
	CloseHandle(m_hProcess);
}

do
	{
		HRESULT hr;

		IUnknown* pUnk = NULL;


		// Create an instance of the application-defined object that implements the ITextHost interface.
		MyTextHost* pTextHost = new MyTextHost(g_hWnd);
		MyTextHost* pTextHost2 = new MyTextHost(g_hWnd);
		

		if (pTextHost == NULL)
			break;
		PCreateTextServices TextServicesProc = NULL;
		HMODULE hmodRichEdit = LoadLibrary(_T("Msftedit.dll"));

		// Retrieve the IID_ITextServices interface identifier from Msftedit.dll. 
		IID* pIID_ITS = NULL;
		if (hmodRichEdit)
		{
			pIID_ITS = (IID*)(VOID*)GetProcAddress(hmodRichEdit, "IID_ITextServices");
			TextServicesProc = (PCreateTextServices)GetProcAddress(hmodRichEdit, "CreateTextServices");
		}

		if (TextServicesProc)
		{
			hr = TextServicesProc(NULL, pTextHost, &pUnk);
		}

		// Create an instance of the text services object.
		//hr = CreateTextServices(NULL, pTextHost, &pUnk);

		if (FAILED(hr))
			break;

		

		// Retrieve the ITextServices interface.    
		hr = pUnk->QueryInterface(*pIID_ITS, (void **)&pTextServices);
		

		Hook((ULONG_PTR)FakeTxSendMessage, pTextServices);
		//UnHook();

		if (TextServicesProc)
		{
			hr = TextServicesProc(NULL, pTextHost2, &pUnk);
			hr = pUnk->QueryInterface(*pIID_ITS, (void **)&pTextServices);
		}

		pUnk->Release();

		
		hr = pTextServices->TxSendMessage(WM_SETFOCUS, 0, 0, 0);

		if (FAILED(hr))
			break;

		

	} while (0);

 

注意事项:

1,保存原有虚函数的指针类型需要为类成员函数指针类型

typedef HRESULT(ITextServices::*TrueTxSendMessage)(UINT msg, WPARAM wparam, LPARAM lparam, LRESULT *plresult);

否则异常

2,要保证调用约定前后一致

HRESULT STDMETHODCALLTYPE FakeTxSendMessage(
    UINT msg,
    WPARAM wparam,
    LPARAM lparam,
    LRESULT *plresult)
{
    MessageBox(NULL, _T("FakeTxSendMessage"), _T("FakeTxSendMessage"), MB_OK);
    return (pTextServices->*(g_func))(msg,wparam,lparam,plresult);
}

否则异常

Thanks~

Logo

CSDN联合极客时间,共同打造面向开发者的精品内容学习社区,助力成长!

更多推荐