一、detours 的下载和编译
2、编译
cd Detours\vc
打开 Detours.sln 编译运行
如果编译失败,重定向一下解决方案
3、编译运行成功之后会生成 detours.lib
4、使用头文件和 detours.lib
二、使用 detours.lib 进行 Hook
这里我们进行 SendMessage 的 Hook,Hook 新定义的输出函数要和原函数参数是一样的
1、进行 API 的 Hook
主要函数
LONG WINAPI DetourAttach(_Inout_ PVOID *ppPointer,
_In_ PVOID pDetour);
第一个参数是原来的函数的地址,第二个参数是 Hook 之后的函数名称
void Hook() {
DetourRestoreAfterWith();
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
//这里可以连续多次调用DetourAttach,表明HOOK多个函数
DetourAttach(&(PVOID&)OldSendMessage, NewSendMessage);
DetourTransactionCommit();
}
2、取消 Hook
void UnHook() {
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
//这里可以连续多次调用DetourDetach,表明撤销多个函数HOOK
DetourDetach(&(PVOID&)OldSendMessage, NewSendMessage);
DetourTransactionCommit();
}
3、具体代码
HWND hwnd;
static LRESULT(WINAPI* OldSendMessage)(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) = SendMessage;
LRESULT WINAPI NewSendMessage(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) {
MessageBox(hwnd, TEXT("就不关闭!"), TEXT("关闭程序"), MB_OK | MB_ICONINFORMATION);
return 0;
}
void Hook() {
DetourRestoreAfterWith();
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
//这里可以连续多次调用DetourAttach,表明HOOK多个函数
DetourAttach(&(PVOID&)OldSendMessage, NewSendMessage);
DetourTransactionCommit();
}
void UnHook() {
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
//这里可以连续多次调用DetourDetach,表明撤销多个函数HOOK
DetourDetach(&(PVOID&)OldSendMessage, NewSendMessage);
DetourTransactionCommit();
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) {
switch (message) {
case WM_CLOSE:
DestroyWindow(hwnd);
break;
case WM_DESTROY:
// MessageBox(hwnd, TEXT("关闭程序!"), TEXT("结束"), MB_OK | MB_ICONINFORMATION);
PostQuitMessage(0);
break;
default:
return DefWindowProc(hwnd, message, wParam, lParam);
}
return 0;
}
int main(void) {
Hook();
static TCHAR szAppName[] = TEXT("TextWindow");
MSG msg;
WNDCLASS wndclass;
// wndclass.cbSize = sizeof(WNDCLASSEX);
wndclass.style = CS_HREDRAW | CS_VREDRAW; //窗口样式
wndclass.lpszClassName = szAppName; //窗口类名
wndclass.lpszMenuName = NULL; //窗口菜单:无
wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); //窗口背景颜色
wndclass.lpfnWndProc = WndProc; //窗口处理函数
wndclass.cbWndExtra = 0; //窗口实例扩展:无
wndclass.cbClsExtra = 0; //窗口类扩展:无
wndclass.hInstance = GetModuleHandle(0); //窗口实例句柄
wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION); //窗口最小化图标:使用缺省图标
wndclass.hCursor = LoadCursor(NULL, IDC_ARROW); //窗口采用箭头光标
UnregisterClass(wndclass.lpszClassName, GetModuleHandle(0));
if (!RegisterClass(&wndclass)) {
MessageBox(NULL, TEXT("窗口注册失败"), TEXT("错误"), MB_OK | MB_ICONERROR);
return 0;
}
hwnd = CreateWindow(szAppName, TEXT("测试窗口"), WS_OVERLAPPEDWINDOW,
0, 0, 500, 400, NULL, NULL, GetModuleHandle(0), NULL);
ShowWindow(hwnd, SW_SHOW);
UpdateWindow(hwnd);
std::thread close_work = std::thread([&]() {
for (int i = 0; i < 5; ++i) {
std::cout << "close work: " << 5 - i << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
}
::SendMessage(hwnd, WM_CLOSE, 0, 0);
});
while (GetMessage(&msg, NULL, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
if (close_work.joinable()) {
close_work.join();
}
std::cout << "Finish" << std::endl;
UnHook();
getchar();
return 0;
}
4、运行结果
正常情况下如果不 Hook 的话,5s 过后窗口就退出了,使用 Hook 的话 5s 过后程序也不会退出