polyHook,比detours更好用的hook框架

PolyHook支持x86/x64平台,源码地址为 https://github.com/stevemk14ebr/PolyHook。 一共提供了6种hook方法。

  1. Detour
  2. Virtual Function Detour
  3. Virtual Function Pointer Swap
  4. Virtual Table Pointer Swap
  5. Import Address Table
  6. VEH

我目前比较常用也只是用第一种hook方法。

配置

主要文件为PolyHook.hpp和Capstone库。 在属性->VC++目录中包含Capstone库,注意区分对应的平台。 添加PolyHook.hpp到工程中,用于提供的是hpp文件,声明和实现都在同一个文件,几个文件包含的话就会报重复定义的错误。 因此我在PolyHook.hpp文件的末尾自己封装了下hook方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
class HookMgr
{
public:
HookMgr(PVOID src, PVOID DstFunction)
{
m_DstFunction = DstFunction;
m_src = src;
std::shared_ptr<PLH::Detour> Detour_Ex(new PLH::Detour);
m_Detour_Ex = Detour_Ex;
}
~HookMgr()
{
}
private:
PVOID m_src;
PVOID m_DstFunction;
std::shared_ptr<PLH::Detour> m_Detour_Ex;
public:
void hook()
{
m_Detour_Ex->SetupHook(m_src, m_DstFunction);
m_Detour_Ex->Hook();
}
//获取原函数
FARPROC GetOriginal()
{
return (FARPROC)m_Detour_Ex->GetOriginal<decltype(&m_DstFunction)>();
}
void unhook()
{
m_Detour_Ex->UnHook();
}

标准API HOOK

hook MessageBoxA函数,

1
2
3
4
HookMgr* hook = new HookMgr(MessageBoxA, myMessageBox);
hook->hook();
oMessageBoxA = (decltype(&MessageBoxA))hook->GetOriginal();

函数已经被hook,我们要调用原函数不能直接调用,需要通过GetOriginal来获取函数指针。 如下,我们在myMessageBox调用的是通过GetOriginal得到的oMessageBoxA函数指针。

1
2
3
4
int WINAPI myMessageBox(HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType)
{
return oMessageBoxA(hWnd, "Hooked", "Hooked", 0);
}

任意函数 HOOK

有时我们想要hook的函数不是windows api,这时应该怎么hook?,答案是通过地址。前提时该地址能够被访问。 地址可以通过硬编码或者动态获取。

用IDA找到想要hook的函数。我要想hook这个函数signed int sub_F5D33D0()

1
2
3
HookMgr* hook = new HookMgr((PVOID)F5D33D0, youfunction);
hook->hook();
oMessageBoxA = (decltype(&youfunction))hook->GetOriginal();

_usercall hook

用IDA反编译时我们经常看到_usercall调用的函数,使用寄存器传参,这时又应该如何hook?

以下面这个函数举例 int __usercall sub_F5D4140@<eax>(int a1@<eax>, int a2@<ecx>, int a3, int a4)

  1. 将hook函数封装成其他形式的调用,如__cdecall 或者 __stdcall等等。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
void __declspec(naked) sub_F5D4140()
{
__asm
{
push [esp + 08h] // a4
push [esp + 08h] // a3
push ecx // a2
push eax // a1
// Call your __cdecl function here:
call func
add esp, 4 //
pop ecx // a2
add esp, 4 // a3
add esp, 4 // a4
retn
}
}

如果需要调用原函数,可在func函数内嵌入汇编代码,需要注意的是_usercall调用的函数由调用者平衡堆栈。

1
2
3
4
5
6
7
8
9
10
_asm
{
push param4
push param3
mov ecx,param2
mov eax,param1
call origin_fun
add esp,0x8 //压了两次,因此加8平衡堆栈
}
文章目录
  1. 1. 配置
  • 标准API HOOK
  • 任意函数 HOOK
  • _usercall hook
  • |