1. 程式人生 > >hook模板x86/x64通用版(3)--CHook.h說明

hook模板x86/x64通用版(3)--CHook.h說明

因為註釋比較齊全,所以不多說別的了。

Hook.h:

#pragma once

#ifdef _UNICODE
#define _T(x)      L ## x
#else
#define _T(x)      x
#endif

#ifdef _WIN64
#define WriteCall      WriteCall_x64
#define WriteJMP       WriteJMP_x64
#else
#define WriteCall      WriteCall_x86
#define WriteJMP       WriteJMP_x86
#endif

#ifdef _WIN64
//普通hook的shellcode大小
#define TRANSFER_FUNC_SIZE	0xcd
//API hook的shellcode大小
#define TRANSFER_FUNC_FOR_CALL_SIZE	0x193
//64位下跳轉指令需要的空間大小
#define JMP_CODE_LEN	0xe
//引數結構
struct ST_PARAMS 
{
	//ST_REGISTER結構中RSP後面的5個暫存器還有0x20的保護空間,一共9個,用不到也別修改 
	const DWORD64 no_use[9]; //不包含返回地址,返回地址會先pop掉
	DWORD64 pdwParams[]; //非API頭的hook不要使用該結構
};
//儲存hook現場的結構,一般x64的前四個引數是按順序安排在RCX,RDX,R8,R9
struct ST_REGISTER
{
	DWORD64 dw64_R15;
	DWORD64 dw64_R14;
	DWORD64 dw64_R13;
	DWORD64 dw64_R12;
	DWORD64 dw64_R11;
	DWORD64 dw64_R10;
	union
	{
		DWORD64 dw64_R9;
		DWORD64 dw64_Param3;
	};
	union
	{
		DWORD64 dw64_R8;
		DWORD64 dw64_Param2;
	};
	DWORD64 dw64_Rdi;
	DWORD64 dw64_Rsi;
	union
	{
		DWORD64 dw64_Rsp;
		ST_PARAMS* pstMoreParams;
	};
	DWORD64 dw64_Rbp;
	DWORD64 dw64_Rbx;
	union
	{
		DWORD64 dw64_Rdx;
		DWORD64 dw64_Param1;
	};
	union
	{
		DWORD64 dw64_Rcx;
		DWORD64 dw64_Param0;
	};
	DWORD64 dw64_Rax;
};

#else
//普通hook的shellcode大小
#define TRANSFER_FUNC_SIZE	0x49
//API hook的shellcode大小
#define TRANSFER_FUNC_FOR_CALL_SIZE	0x7d
//32位下跳轉指令需要的空間大小
#define JMP_CODE_LEN	5
//儲存hook現場的結構
struct ST_REGISTER
{
	DWORD dw_edi;
	DWORD dw_esi;
	DWORD dw_ebp;
	union
	{
		DWORD dw_esp;
		DWORD* pParamsOfCall;//API頭的hook使用該結構可以修改引數數值
	};
	DWORD dw_ebx;
	DWORD dw_edx;
	DWORD dw_ecx;
	DWORD dw_eax;
};

#endif

class CHook
{
public:
	//一個類只hook一個地址,所以在建構函式這裡進行hook防止使用者多次呼叫
	CHook(void* pOriginAdr , void* pNewHook);
	CHook(void* pOriginAdr , void* pNewHook , void* pHookAfterCall);
	~CHook(void);

	//移除hook的函式,未作測試=。=
	BOOL RemoveHook();
	//直接移除hook的函式,在本hook的使用者函式中呼叫的話會出大事,所以名字加了unsafe。
	//在其他地方呼叫的話要確保沒有執行到該hook的程式碼,所以最好還是呼叫上面那個函式
	BOOL RemoveHook_unsafe();
	//獲取hook點現場
	ST_REGISTER* GetRegOnHookPoint();

private:
	//初始化,然而並沒有初始化多少東西
	void Init();
	//給某地址寫跳轉指令
	void WriteJMP_x86(DWORD_PTR dwFrom , DWORD_PTR dwTo);
	void WriteJMP_x64(DWORD_PTR dwFrom , DWORD_PTR dwTo);
	//給某地址寫一個call指令
	void WriteCall_x86(DWORD_PTR dwFrom , DWORD_PTR dwTo);
	void WriteCall_x64(DWORD_PTR dwFrom , DWORD_PTR dwTo);

	//在地址pOriginAdr設定普通hook,使用者定義回撥函式pNewHook
	BOOL SetHook(void* pOriginAdr , void* pNewHook);
	//在函式頭pOriginAdr設定hook,使用者定義回撥函式pNewHook在函式執行前執行,用於攔截和修改引數;
	//pHookAfterCall在函式執行後執行,用於攔截和修改函式返回。pNewHook和pHookAfterCall不可同時為空
	BOOL SetHook(void* pOriginAdr , void* pNewHook , void* pHookAfterCall);

	//遷移、儲存hook點被破壞的程式碼
	int TransplantCode( void* pOriginAdr , BYTE* pDestAdr);

	//儲存hook現場的Tls索引
	DWORD m_dwTlsIndexForRegister;
	//儲存API頭hook儲存函式返回地址的Tls索引
	DWORD m_dwTlsIndexForRetAdr;

	//儲存hook點地址
	void* m_pOrigin_Adr;
	//儲存hook點被破壞的指令長度
	int m_nOrigin_CodeLen;
	//hook點被破壞的指令遷移到的地址
	BYTE* m_pOldCode;

	//每個CHook類初始化時會申請一塊記憶體,把shellcode複製進去並修正一些偏移,作為中轉函式
	BYTE* m_szMyTransfer;

	//單純c3返回的函式,用於API hook時候某個使用者定義的函式為空的時候直接呼叫這個函式
	//在修正shellcode的時候能簡化一點操作
	static BYTE* m_szRet;
	//普通hook的shellcode模板
	static BYTE m_szTransferFunction[TRANSFER_FUNC_SIZE];
	//API hook的shellcode模板
	static BYTE m_szTransferFunction_ForCall[TRANSFER_FUNC_FOR_CALL_SIZE];
};