基于Detours库HOOK API

Tattoo

发布日期: 2018-12-20 12:14:21 浏览量: 3375
评分:
star star star star star star star star_border star_border star_border
*转载请注明来自write-bug.com

背景

可能我们开发程序的时候,会用到Inline Hook Api的技术。Inline Hook 的原理是在系统访问一个函数的时候先替换原函数入口处的内容跳转到自己设计的Hook函数中,然后在自己函数中进行Hook工作。但在并行系统中,很可能有个线程就在这个时候调用了被自己改掉的系统函数,出现我们无法预期的结果。

这时,我们可以考虑使用Detuors库。Detours是微软开发的一个函数库,可用于捕获系统API。Detours库Hook过程原理和我们自己写的基本一样,不同的地方在于微软做了封装和相关的冲突检查,所以这种基于Detoursku的Api Hook更稳定些。

现在,我对使用Detours库进行HOOK API进行下讲解,并写成文档,分享给大家。

前期准备

本文开发的程序是使用VS2013进行开发的,开发之前,需要到微软的官网上下载Detuors库的源码程序,然后在本地编译得到库文件。至于Detours库的下载地址以及具体的编译步骤,可以参考本站上其他人写的“使用VS2013编译Detours库”这篇文章,里面有详细介绍。

实现原理

我们把使用Detuors库HOOK API的代码实现都写在DLL里面,方便以后的调用。在DLL加载的时候,即DLL入口点函数DllMain的DLL_PROCESS_ATTACH中,执行HOOK部分的代码。在DLL卸载的时候,即DLL入口函数DllMain的DLL_PROCESS_DETACH中,执行UNHOOK部分的代码。

那么,HOOK的原理是:

  • 首先,先调用Detours函数DetourRestoreAfterWith,恢复之前状态,避免反复拦截

  • 然后,调用DetourTransactionBegin,表示开始事务,准备HOOK;并调用DetourUpdateThread刷新当前线程

  • 接着,开始调用DetourAttach函数设置HOOK,可以连续多次HOOK不同的API函数

  • 最后,使用DetourTransactionCommit提交事务,上一步设置的HOOK操作,会立即生效

其中,DetourAttach传的是实际的API函数地址的指针和代替API函数的替代函数地址。

UNHOOK的原理和HOOK的原理是差不多的,原理是:

  • 首先,调用DetourTransactionBegin,表示开始事务,准备HOOK;并调用DetourUpdateThread刷新当前线程

  • 然后,开始调用DetourDetach函数设置UNHOOK,可连续多次UNHOOK不同的API函数

  • 最后,使用DetourTransactionCommit提交事务,上一步设置的UNHOOK操作,会立即生效

其中,DetourDetach传的是实际的API函数地址的指针和代替API函数的替代函数地址。

至于,Detours具体的操作,我们可以不用理会,只需交给Detours API去实现吧。

编码实现

导入Detours库文件

  1. #include "Detours\\detours.h"
  2. #pragma comment(lib, "Detours\\detours.lib")

HOOK API

  1. VOID HookApi_Detours()
  2. {
  3. // 恢复之前状态,避免反复拦截
  4. DetourRestoreAfterWith();
  5. // 开始事务, 开始HOOK API
  6. DetourTransactionBegin();
  7. // 刷新当前的线程
  8. DetourUpdateThread(GetCurrentThread());
  9. // 保存旧函数的地址
  10. Old_MessageBoxA = ::MessageBoxA;
  11. // HOOK API.这里可以连续多次调用DetourAttach, 表明HOOK多个函数
  12. DetourAttach((PVOID *)(&Old_MessageBoxA), New_MessageBoxA);
  13. // 提交事务, HOOK API立即生效
  14. DetourTransactionCommit();
  15. }

UNHOOK API

  1. VOID UnhookApi_Detours()
  2. {
  3. // 开始事务, 开始UNHOOK API
  4. DetourTransactionBegin();
  5. // 刷新当前的线程
  6. DetourUpdateThread(GetCurrentThread());
  7. // UNHOOK API.这可多次调用DetourDetach,表明撤销多个函数HOOK
  8. DetourDetach((PVOID *)(&Old_MessageBoxA), New_MessageBoxA);
  9. // 提交事务, UNHOOK API立即生效
  10. DetourTransactionCommit();
  11. }

程序测试

我们将上述封装好的Detours Hook Api函数写在一个DLL工程中,然后还另外写了一个控制台工程。让控制台工程加载DLL文件,DLL便会在入口点HOOK进程的API函数。当进程调用HOOK掉的API函数是,会直接执行到我们的NEW_API函数。

控制台工程的 main 函数为:

  1. int _tmain(int argc, _TCHAR* argv[])
  2. {
  3. // HOOK API前弹窗
  4. MyMessage();
  5. // 加载DLL, 执行HOOK API
  6. HMODULE hDll = ::LoadLibrary("HookApi_Detours_Dll.dll");
  7. if (NULL == hDll)
  8. {
  9. printf("LoadLibrary Error!\n");
  10. }
  11. // HOOK API后弹窗
  12. MyMessage();
  13. // 卸载DLL
  14. ::FreeLibrary(hDll);
  15. // UNHOOK API后弹窗
  16. MyMessage();
  17. system("pause");
  18. return 0;
  19. }

测试结果:

运行控制台.exe程序,首先弹出第一个HOOK MessageBoxA前的消息对话框:

然后,点击“确定”关闭对话框后,便会执行加载DLL,程序没有加载DLL出错提示,所以加载成功。而且,弹出第二个HOOK MessageBoxA之后的消息对话框,内容已经更改,所以,HOOK API成功:

然后,点击“确定”关闭对话框后,便会执行卸载DLL,那么DLL卸载处就会调用UNHOOK API,还原API,所以看到弹出的第三个消息对话框,内容是正常的:

总结

基于Detours库实现HOOK API确实很方便,即使你不理解其中的原理,照样可以根据Detours提供的API接口,实现较为完美的API HOOK。

参考

参考自《Windows黑客编程技术详解》一书

上传的附件 cloud_download HookApi_Detours_Test.7z ( 292.10kb, 44次下载 )

发送私信

人生最好的三个词:久别重逢,失而复得,虚惊一场

96
文章数
34
评论数
最近文章
eject