1. 程式人生 > >從Hook虛擬函式到HOOK COM API

從Hook虛擬函式到HOOK COM API

// 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~