抱歉,您的浏览器无法访问本站
本页面需要浏览器支持(启用)JavaScript
了解详情 >

Inline Hook(内联钩子注入)流程

  1. 构造跳转指令[JMP后的偏移量 = 目标地址 - 原地址 - jcc的指令长度]
  2. 在内存中找到欲HOOK函数地址,并保存欲HOOK位置处的前5个字节
  3. 将构造的跳转指令写入需HOOK的位置处
  4. 当被HOOK位置被执行时会转到自己的流程执行
  5. 如果要执行原来的流程,取消HOOK,还原被修改的字节
  6. 执行原来的流程
  7. 继续HOOK住原来的位置

仓库地址

5字节Inline Hook(x86)

  • 5字节Inline Hook中jcc指令长度为5
  • 根据计算公式:JMP后的偏移量 = 目标地址 - 原地址- 5

代码实现

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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
PROC m_FuncAddress;     // 要Hook的函数地址
BYTE m_OldBytes[5]; // 要Hook函数的头5个字节
BYTE m_NewBytes[5]; // 要替换到目标函数头五个字节的新字节(jmp xxxxxxxx/ E9 xxxxxxxx)

BOOL Hook(const char* pszModuleName, const char* pszFuncName, PROC pfnHookFunc)
{
m_FuncAddress = (PROC)GetProcAddress(GetModuleHandle(pszModuleName), pszFuncName);
if(m_FuncAddress == NULL)
{
return FALSE;
}
SIZE_T dwSize = 0;
ReadProcessMemory(GetCurrentProcess(), m_FuncAddress, m_OldBytes, 5, &dwSize);
m_NewBytes[0] = '\xE9';
*(DWORD*)(m_NewBytes + 1) = (DWORD)pfnHookFunc - (DWORD)m_FuncAddress - 5;
WriteProcessMemory(GetCurrentProcess(), m_FuncAddress, m_NewBytes, 5, &dwSize);
return TRUE;
}

BOOL UnHook()
{
if (m_FuncAddress != 0)
{
SIZE_T dwSize = 0;
WriteProcessMemory(GetCurrentProcess(), m_FuncAddress, m_OldBytes, 5, &dwSize);
}
return TRUE;
}

BOOL ReHook()
{
if (m_FuncAddress != 0)
{
SIZE_T dwSize = 0;
WriteProcessMemory(GetCurrentProcess(), m_FuncAddress, m_NewBytes, 5, &dwSize);
}
return TRUE;
}

int
WINAPI
MyMessageBoxA(
_In_opt_ HWND hWnd,
_In_opt_ LPCSTR lpText,
_In_opt_ LPCSTR lpCaption,
_In_ UINT uType)
{
UnHook();
int nRet = MessageBoxA(hWnd, "Hello Dokey", "Hello Dokey", uType);
ReHook();
return nRet;
}

// VA Virtual Address
// HMODULE hModule 模块加载基址 ImageBase 模块句柄
// DWORD ul_reason_for_call 以什么原因触发的
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
// MessageBox(NULL, "Dokey", "Dokey", MB_OK);
m_FuncAddress = NULL;
memset(m_OldBytes, 0, 5);
memset(m_NewBytes, 0, 5);
Hook("user32.dll", "MessageBoxA", (PROC)MyMessageBoxA);
break;
case DLL_THREAD_ATTACH:
break;
case DLL_THREAD_DETACH:
break;
case DLL_PROCESS_DETACH:
UnHook();
break;
}
return TRUE;
}

7字节Inline Hook(x86)

  • 5字节Inline Hook通过构造一个jmp指令来修改目标函数入口的字节内容,jmp指令后面的偏移量是由于CPU机器码要求jmp指令后是一个偏移量
  • 7字节Inline Hook通过修改函数入口的两条指令来完成
    • 一条是把目标地址存入寄存器eax中: mov eax, xxxxxxxx / B8 xxxxxxxx
    • 然后用jmp指令直接跳转到寄存器eax中保存的地址: jmp eax / FF E0
    • 通过指令的机器码是不变的,变化的只有地址,需要将目标函数地址保存在从第一至第四字节的位置就可以了
    • Byte bJmpCode[] = {'\xb8', '\0', '\0', '\0', '\0', '\xff', '\xe0'}

代码实现

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
34
35
36
37
38
39
40
PROC m_FuncAddress;
BYTE m_OldBytes[7];
BYTE m_NewBytes[7];

BOOL Hook(const char* pszModuleName, const char* pszFuncName, PROC pfnHookFunc)
{
m_FuncAddress = GetProcAddress(GetModuleHandle(pszModuleName), pszFuncName);
if(m_FuncAddress == NULL)
{
return FALSE;
}
SIZE_T dwSize = 0;
ReadProcessMemory(GetCurrentProcess(), m_FuncAddress, m_OldBytes, 7, &dwSize);
m_NewBytes[0] = '\xb8';
m_NewBytes[5] = '\xff';
m_NewBytes[6] = '\xe0';
*(DWORD*)(m_NewBytes + 1) = (DWORD)pfnHookFunc;
WriteProcessMemory(GetCurrentProcess(), m_FuncAddress, m_NewBytes, 7, &dwSize);
return TRUE;
}

BOOL UnHook()
{
if(m_FuncAddress != 0)
{
SIZE_T dwSize = 0;
WriteProcessMemory(GetCurrentProcess(), m_FuncAddress, m_OldBytes, 7, &dwSize);
}
return TRUE;
}

BOOL ReHook()
{
if(m_FuncAddress != 0)
{
SIZE_T dwSize = 0;
WriteProcessMemory(GetCurrentProcess(), m_FuncAddress, m_NewBytes, 7, &dwSize);
}
return TRUE;
}

12字节Inline Hook(x64)

  • 原理: mov rax, Address/jmp rax;
  • 硬编码: Byte[12] = {0x48, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xe0}

代码实现

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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
PROC m_FuncAddress;
BYTE m_OldBytes[12];
BYTE m_NewBytes[12];

BOOL Hook(const char* pszModulesName, const char* pszFuncName, PROC pfnHookFunc)
{
m_FuncAddress = GetProcAddress(GetModuleHandle(pszModuleName), pszFuncName);
if (m_FuncAddress == NULL)
{
return FALSE;
}
SIZE_T dwSize = 0;
ReadProcessMemory(GetCurrentProcess(), m_FuncAddress, m_OldBytes, 12, &dwSize);
m_NewBytes[0] = '\x48';
m_NewBytes[1] = '\xb8';
m_NewBytes[10] = '\xff';
m_NewBytes[11] = '\xe0';
*(DWORD64*)(m_NewBytes + 2) = (DWORD64)pfnHookFunc;
WriteProcessMemory(GetCurrentProcess(), m_FuncAddress, m_NewBytes, 12, &dwSize);
return TRUE;
}

BOOL UnHook()
{
if(m_FuncAddress == 0)
{
return FALSE;
}
SITE_T dwSize = 0;
WriteProcessMemory(GetCurrentProcess(), m_FuncAddress, m_OldBytes, 12, &dwSize);
return TRUE;
}

BOOL ReHook()
{
if(m_FuncAddress == 0)
{
return FALSE;
}
SIZTE_T dwSize = 0;
WriteProcessMemory(GetCurrentProcess(), m_FuncAddress, m_NewBytes, 12, &dwSize);
}

int
WINAPI
MyMessageBoxA(
_In_opt_ HWND hWnd,
_In_opt_ LPCSTR lpText,
_In_opt_ LPCSTR lpCaption,
_In_ UINT uType)
{
UnHook();
int nRet = MessageBoxA(hWnd, "Dokey 12", "Dokey 12", uType);
ReHook();
return nRet;
}

int
WINAPI
MyMessageBoxW(
_In_opt_ HWND hWnd,
_In_opt_ LPCWSTR lpText,
_In_opt_ LPCWSTR lpCaption,
_In_ UINT uType)
{
UnHook();
int nRet = MessageBoxW(hWnd, L"Dokey 12", L"Dokey 12", uType);
ReHook();
return nRet;
}

#ifdef UNICODE
#define MyMessageBox MyMessageBoxW
constexpr auto MessageBoxText = "MessageBoxW";
#else
#define MyMessageBox MyMessageBoxA
constexpr auto MessageBoxText = "MessageBoxA";
#endif // !UNICODE

...

评论