因为注释比较齐全,所以不多说别的了。
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];
};