简介
Microsoft Research Detours Package
Detours是微软官方的一个Hook库,该库可直接使用vs进行编译,使用的是inline hook
Detours的使用
利用Detours库进行Hook时,只需要提供三个信息:
- 原函数的原型信息(汇编级别的原型就行:参数个数、大小、调用约定、返回类型大小)
- 原函数的地址
- Hook函数的地址
Detours库的使用主要为以下两部分:
Hook
DetourRestoreAfterWith
,恢复之前的状态DetourTransactionBegin
,开始事物DetourUpdateThread
,刷新当前线程DetourAttach
,设置HookDetourTransactionCommit
,提交事物
UnHook
DetourTransactionBegin
,开始事物DetourUpdateThread
,刷新当前线程DetourDetach
,设置UnHookDetourTransactionCommit
,提交事物
Hook 自定义C函数
- 确定目标函数地址,硬编码、内存搜索都可以
- 确定目标函数原型,没有源码的时候逆向就行,原型只要求在汇编级别上一致即可
- 在DLL中编写Hook函数,完成Hook
/********************************** TestProject.exe **********************************/
#include <stdio.h>
#include <Windows.h>
int foo(int a, int b)
{
printf("foo func: %d\n", a + b);
return a + b;
}
int main(void)
{
printf("num = %d\n", foo(1, 2));
system("pause");
// Hook
HMODULE hmodule = LoadLibraryA("HookTest.dll"); // 加载DLL来模拟注入
printf("num = %d\n", foo(1, 2));
FreeLibrary(hmodule);
system("pause");
// UnHook
printf("num = %d\n", foo(1, 2));
return 0;
}
/********************************** HookTest.dll **********************************/
#include "D:/Third-party Library/Detours/include/detours.h"
#ifdef _WIN64
#pragma comment(lib, "D:/Third-party Library/Detours/lib.X64/detours.lib")
#else
#pragma comment(lib, "D:/Third-party Library/Detours/lib.X86/detours.lib")
#endif
// 目标函数指针
typedef int (*FOO_PTR)(int a, int b);
FOO_PTR foo_ptr = (FOO_PTR)0x00411780; // 目标函数地址
// 定义Hook函数
int hook_foo(int a, int b)
{
a *= 10;
b += 5;
return foo_ptr(a, b);
}
void start_hook()
{
DetourRestoreAfterWith(); // 恢复之前的状态,防止重复Hook
DetourTransactionBegin(); // 开始事物
DetourUpdateThread(GetCurrentThread()); // 刷新当前线程
DetourAttach(&(void *&)foo_ptr, hook_foo); // 设置Hook
DetourTransactionCommit(); // 提交事物
}
void stop_hook()
{
DetourTransactionBegin(); // 开始事物
DetourUpdateThread(GetCurrentThread()); // 刷新当前线程
DetourDetach((void **)&foo_ptr, hook_foo); // 设置UnHook
DetourTransactionCommit(); // 提交事物
}
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
start_hook();
break;
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
stop_hook();
break;
}
return TRUE;
}
Hook 类成员函数
DetourAttach
函数的第二个参数类型为PVOID
,在高版本的编译器中,对类成员函数强转有很严格的要求,基本上不可能转为PVOID
,那么就需要换一种思路,利用静态成员函数来完成,自己保存this
指针,必要时使用裸函数__declspec(naked)
,自己平栈
针对前例的修改如下:
/********************************** TestProject.exe **********************************/
class Test {
public:
int bar(int n)
{
printf("bar func: %d\n", n);
return n;
}
};
int main(void)
{
Test test;
test.bar(1);
system("pause");
// Hook
HMODULE hmodule = LoadLibraryA("HookTest.dll");
test.bar(1);
FreeLibrary(hmodule);
system("pause");
// UnHook
test.bar(1);
return 0;
}
/********************************** HookTest.dll **********************************/
class HookTest {
public:
static int hook_bar(int n)
{
__asm push ecx
n += 100;
//return (this->*bar_ptr)(n);
ULONG_PTR this_obj;
__asm {
pop eax
mov this_obj, eax
}
return (((HookTest *)this_obj)->*bar_ptr)(n);
}
static int (HookTest::*bar_ptr)(int n); // 类成员函数指针
};
int (HookTest::*HookTest::bar_ptr)(int n) = NULL; // 初始化静态成员函数指针,后续在赋值
ULONG_PTR target = 0x0401080; // 目标函数地址
void start_hook()
{
...
DetourAttach((void **)&HookTest::bar_ptr, (void *)HookTest::hook_bar); // 设置Hook
...
}
void stop_hook()
{
...
DetourDetach((void **)&HookTest::bar_ptr, (void *)HookTest::hook_bar); // 设置UnHook
...
}
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
memcpy(&HookTest::bar_ptr, &target, sizeof(target));
start_hook();
break;
...
}
return TRUE;
}
Hook API
可以使用DetourFindFunction
函数来获取API的地址,同时DetourCreateProcessWithDll
函数可以创建进程并注入DLL,其原理也就是调用CreateProcess
,创建标志给上CREATE_SUSPENDED
,以暂停进程,之后进行注入
注意:使用DetourCreateProcessWithDll
函数,目标DLL必须要有至少一个导出函数
/********************************** TestProject.exe **********************************/
#include <stdio.h>
#include <Windows.h>
#include "D:/Third-party Library/Detours/include/detours.h"
#ifdef _WIN64
#pragma comment(lib, "D:/Third-party Library/Detours/lib.X64/detours.lib")
#else
#pragma comment(lib, "D:/Third-party Library/Detours/lib.X86/detours.lib")
#endif
int main(void)
{
TCHAR proc_name[256] = L"notepad.exe";
char dll_name[256] = "E:\\WorkSpace\\HookTest\\HookTest\\Release\\HookTest.dll";
STARTUPINFO si { 0 };
PROCESS_INFORMATION pi { 0 };
si.cb = sizeof(si);
DetourCreateProcessWithDll(NULL, proc_name, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi, dll_name, NULL);
WaitForSingleObject(pi.hProcess, INFINITE);
return 0;
}
/********************************** HookTest.dll **********************************/
HOOKTEST_API BOOL MyWriteFile(
HANDLE hFile,
LPCVOID lpBuffer,
DWORD nNumberOfBytesToWrite,
LPDWORD lpNumberOfBytesWritten,
LPOVERLAPPED lpOverlapped
)
{
hFile = INVALID_HANDLE_VALUE;
return WriteFile(hFile, lpBuffer, nNumberOfBytesToWrite, lpNumberOfBytesWritten, lpOverlapped);
}
void start_hook()
{
DetourRestoreAfterWith(); // 恢复之前的状态,防止重复Hook
DetourTransactionBegin(); // 开始事物
DetourUpdateThread(GetCurrentThread()); // 刷新当前线程
PVOID write_file_ptr = DetourFindFunction("kernel32.dll", "WriteFile"); // 查找WriteFile地址
DetourAttach(&write_file_ptr, MyWriteFile); // 设置Hook
DetourTransactionCommit(); // 提交事物
}
void stop_hook()
{
DetourTransactionBegin(); // 开始事物
DetourUpdateThread(GetCurrentThread()); // 刷新当前线程
PVOID write_file_ptr = DetourFindFunction("kernel32.dll", "WriteFile"); // 查找WriteFile地址
DetourDetach(&write_file_ptr, MyWriteFile); // 设置UnHook
DetourTransactionCommit(); // 提交事物
}