您的位置:首页 > 财经 > 金融 > 微软Detours Hook库编译与使用

微软Detours Hook库编译与使用

2024/12/23 15:54:56 来源:https://blog.csdn.net/lyshark_csdn/article/details/141194827  浏览:    关键词:微软Detours Hook库编译与使用

Detours 是微软开发的一个强大的Windows API钩子库,用于监视和拦截函数调用。它广泛应用于微软产品团队和众多独立软件开发中,旨在无需修改原始代码的情况下实现函数拦截和修改。Detours 在调试、监控、日志记录和性能分析等方面表现出色,已成为开发者的重要工具。本章将指导读者编译并使用Detours库,通过实现一个简单的弹窗替换功能,帮助读者熟悉该库的使用技巧。

Detours 是一个兼容多个Windows系列操作系统版本(包括 Windows XPWindows 11)的工具库。它现在在 MIT 开源许可证下发布,简化了开发者的使用许可流程,并允许社区利用开源工具和流程来支持其发展,目前该库的稳定版本为4.0.1读者可通过如下官方链接自行下载到本地。

  • Detours 4.0.1:https://github.com/microsoft/Detours/releases

下载文件后打开目录,其中src目录下存储的是Detours库的源代码,而samples则是一些使用案例,当准备就绪后读者需要打开Visual Studio开发者命令提示符,你可以从开始菜单中找到Visual Studio Tools工具菜单,并在其中找到VS20XX x86 本机工具命令提示Developer Command Prompt for VS 20XX字样,此处以x86为例,在命令提示符中跳转到Detours源代码目录,运行 nmake 命令执行编译。

在这里插入图片描述

如果一切顺利,这将会编译Detours库并生成所需的二进制文件,其中include保存有头文件信息,而lib.X86则包含有detours.lib库文件,如下图中所示。

在这里插入图片描述

接着我们打开Visual Studio工具,新建一个可执行控制台项目并配置包含引用目录及库目录,如下图所示;

在这里插入图片描述

接着我们来实现拦截并替换弹窗功能,在Windows中弹窗接口为MessageBoxW函数,首先需要定义OriginalMessageBoxW的函数指针,该指针用于指向原始的MessageBoxW函数地址。接着定义CustomMessageBoxW函数,在函数内首先将弹窗提示替换为自定义内容,并携带该参数调用OriginalMessageBoxW原函数地址,以此来实现替代弹窗功能。

#include <iostream>
#include <Windows.h>
#include "detours.h"#pragma comment(lib, "detours.lib")// 定义指向原始 MessageBoxW 函数的指针
static int (WINAPI *OriginalMessageBoxW)(_In_opt_ HWND hWnd,_In_opt_ LPCWSTR lpText,_In_opt_ LPCWSTR lpCaption,_In_ UINT uType) = MessageBoxW;// 自定义的 MessageBoxW 函数,用于替换原始函数
static int WINAPI CustomMessageBoxW(_In_opt_ HWND hWnd,_In_opt_ LPCWSTR lpText,_In_opt_ LPCWSTR lpCaption,_In_ UINT uType)
{// 调用原始的 MessageBoxW 函数,但修改了显示的文本return OriginalMessageBoxW(hWnd, L"hello lyshark", L"MsgBox", MB_OK);
}

接着就是对挂钩与摘钩的函数封装,分别定义这两个函数,其中InstallHook 函数通过Detours事务的方式,将原始的 MessageBoxW 函数指针替换为自定义的 CustomMessageBoxW 函数指针,从而拦截并修改该函数的行为。相反,RemoveHook 函数则通过类似的事务机制,将自定义的 CustomMessageBoxW 函数指针替换回原始的 MessageBoxW 函数指针,以恢复函数的原始行为。

// 安装钩子
void InstallHook()
{// 开始一个 Detours 事务if (DetourTransactionBegin() == NO_ERROR){// 更新当前线程以准备进行钩子操作if (DetourUpdateThread(GetCurrentThread()) == NO_ERROR){// 将原始函数指针替换为自定义的函数指针if (DetourAttach(&(PVOID&)OriginalMessageBoxW, CustomMessageBoxW) == NO_ERROR){// 提交事务,完成钩子安装if (DetourTransactionCommit() == NO_ERROR){printf("钩子已成功安装。\n");return;}}}// 如果任何步骤失败,则中止事务DetourTransactionAbort();}printf("安装钩子失败。\n");
}// 移除钩子
void RemoveHook()
{// 开始一个 Detours 事务if (DetourTransactionBegin() == NO_ERROR){// 更新当前线程以准备进行钩子操作if (DetourUpdateThread(GetCurrentThread()) == NO_ERROR){// 将自定义的函数指针替换回原始函数指针if (DetourDetach(&(PVOID&)OriginalMessageBoxW, CustomMessageBoxW) == NO_ERROR){// 提交事务,完成钩子移除if (DetourTransactionCommit() == NO_ERROR){printf("钩子已成功移除。\n");return;}}}// 如果任何步骤失败,则中止事务DetourTransactionAbort();}printf("移除钩子失败。\n");
}

在程序入口处,我们分三次调用MessageBoxW函数,其中第一次调用及最后依次调用均在未挂钩状态下进行,第二次调用之前通过InstallHook()安装钩子,之后再调用MessageBoxW函数,并在调用结束后通过RemoveHook()移除钩子,编译这段代码。

int main(int argc, char *argv[])
{// 显示原始的消息框MessageBoxW(NULL, L"hello world", L"MsgBox", MB_OK);// 安装钩子并显示修改后的消息框InstallHook();MessageBoxW(NULL, L"hello world", L"MsgBox", MB_OK);// 移除钩子并恢复为原始的消息框RemoveHook();MessageBoxW(NULL, L"hello world", L"MsgBox", MB_OK);system("pause");return 0;
}

使用x64dbg调试器加载运行代码,并寻找到程序的入口处,由于此处的入口处仅仅是一个main(int argc, char *argv[])所以,在汇编中我们可以直接寻找三个参数的关键变量位置,找到后即可定位到入口处,此时直接跟进去就可以看到主函数代码;

在这里插入图片描述

如下图中所示,当0x00321314处被执行后则钩子生效,当钩子生效后则底部0x00321347处的地址将被替换为自定义钩子地址,此时在其之上的入栈操作数将会失效;

在这里插入图片描述

继续跟进0x00321347这个地址,如下图所示该地址中的入口处已被替换为我们自定义的弹窗位置,此处是一个jmp无条件跳转,预示着将要转向。

在这里插入图片描述

我们继续跟进这个转向地址,则可看到如下图所示的反汇编指令集,这里的代码重新入栈了新的字符串变量,并在入栈后调用了原始MessageBoxW函数,并依次来实现替换函数弹窗中的内容。

在这里插入图片描述

此时,当继续调用原始函数时,虽函数中的提示信息为hello world但由于挂钩生效了则提示信息会被变更为hello lyshark,以此来实现对函数功能的替换与更正。

在这里插入图片描述

在实际应用中,我们通常通过 DLL 注入的方式使用 Detours 库,以便更好地实现对第三方程序的功能替换或修改,例如改变弹窗提示。这种方法能够更高效地应用 Hook 技术,实现对目标程序行为的控制和定制。

例如如下所示的这段代码,当使用注入器将其注入到第三方进程中时,首先DLL_PROCESS_ATTACH将被执行也就是开始挂钩,在挂钩函数中通过DetourFindFunction寻找到MessageBoxW函数的入口地址,并将其存储到OriginalMessageBoxW指针中,并通过DetourAttach对其进行挂钩。

#include <windows.h>
#include "detours.h"
#include "detver.h"#pragma comment(lib, "detours.lib")// 定义 MessageBoxW 函数指针类型
static int (WINAPI *OriginalMessageBoxW)(HWND hWnd, LPCWSTR lpText, LPCWSTR lpCaption, UINT uType) = NULL;// 自定义的 MessageBoxW 函数
int WINAPI MyMessageBoxW(HWND hWnd, LPCWSTR lpText, LPCWSTR lpCaption, UINT uType)
{// 可以在这里添加自定义逻辑return OriginalMessageBoxW(hWnd, L"hello lyshark", lpCaption, uType);
}// 安装钩子
void InstallHooks()
{DetourRestoreAfterWith();// 开始事务DetourTransactionBegin();// 更新当前线程DetourUpdateThread(GetCurrentThread());// 查找并拦截 MessageBoxW 函数OriginalMessageBoxW = (int (WINAPI *)(HWND, LPCWSTR, LPCWSTR, UINT))DetourFindFunction("User32.dll", "MessageBoxW");if (OriginalMessageBoxW != NULL){// 开始挂钩DetourAttach(&(PVOID&)OriginalMessageBoxW, MyMessageBoxW);}// 提交事务DetourTransactionCommit();
}// 卸载钩子
void UninstallHooks()
{// 开始事务DetourTransactionBegin();// 更新当前线程DetourUpdateThread(GetCurrentThread());// 撤销拦截 MessageBoxW 函数if (OriginalMessageBoxW != NULL){// 摘除钩子DetourDetach(&(PVOID&)OriginalMessageBoxW, MyMessageBoxW);}// 提交事务DetourTransactionCommit();
}// DLL 入口点
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{switch (ul_reason_for_call){case DLL_PROCESS_ATTACH:// 禁用线程库调用DisableThreadLibraryCalls(hModule);// 安装钩子InstallHooks();break;case DLL_THREAD_ATTACH:break;case DLL_THREAD_DETACH:break;case DLL_PROCESS_DETACH:// 卸载钩子UninstallHooks();break;}return TRUE;
}

当挂钩成功后则进程中任何调用弹窗的提示信息都将被替换成hello lyshark提示,而标题栏因未被替换则依然会保持原始状态,如下图是注入之前与注入之后的提示变化;

在这里插入图片描述

至此本章内容结束,其实Hook在安全领域的应用相当广泛,例如可以监控和拦截指定的API调用,检测分析程序的行为,拦截网络通信函数,监控数据传输,拦截文件操作和注册表访问等等,本文也只是抛砖引玉让读者能认识Detours库。更多有用的案例可自行参考samples目录下的内容学习。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com