Detour开发包介绍(2):使用

一般来说,使用Detours的代码都具有固定的模式。Detours 1.5和Detours 2.1的接口函数变了很多,这里按照2.1版本对基本的使用方法进行说明。常用的函数有下面几个:

DetourTransactionBegin():开始一次截获或者解除截获过程。

DetourUpdateThread():列入一个在DetourTransaction过程中要进行update的线程。这个函数的作用稍微有一些复杂,会在后面专门说明。

DetourAttach()添加一个要截获目标函数。

DetourDetach():用来解除截获的函数。

DetourTransactionCommit():执行当前的Transaction过程。在这个函数中才会真正进行截获或者解除截获操作。前面三个函数都只是做一些记录工作。

在使用的时候,这几个函数的调用步骤基本上也是按照上面列出来的顺序。举例来说,我们要截获API函数MessageBoxA,将消息框弹出的消息修改掉,可以按下面的方法做(这里是DLL注入的方式)

先写一个调用了MessageBoxA的程序。建立一个MFC对话框工程(在建立向导中选"Dialog based",其余默认)打开Resource View中的对话框IDD_MESSAGEBOXAPP_DIALOG,添加OK按钮的单击处理事件OnBnClickedOk(),在其中加入对MessageBoxA函数的调用,如下:

[cpp]  view plain copy
  1. void CMessageBoxAppDlg::OnBnClickedOk()  
  2. {  
  3.     // TODO: Add your control notification handler code here  
  4.     ::MessageBoxA(NULL, "Execute target function: MessageBoxA""Info", MB_OK | MB_ICONINFORMATION);  
  5.       
  6.     OnOK();  
  7. }  

编译后的程序名称MessageBoxApp.exe,运行它并单击OK按钮时会弹出相应消息框。现在我们要截获这个EXE文件中对MessageBoxA函数的调用,以跳转到我们自己定义的D函数处。我们需要先编写一个DLL以拦截目标函数,然后将该DLL注入到目标程序MessageBoxApp.exe的空间中。

1、编写目标函数的拦截DLL

    建立一个Win32的DLL工程(在Win32应用程序向导中选Dll),名为ApiHook,也可以不用IDE而是用原始的记事本来编写DLL。把detours.h和detours.lib、detoured.lib拷贝到工程目录下。源文件ApiHook.cpp的代码如下:

[cpp]  view plain copy
  1. // ApiHook.cpp : Defines the entry point for the DLL application.  
  2. #include "stdafx.h"  
  3. #include <stdio.h>  
  4. #include "detours.h"  
  5. #pragma comment(lib,"detours.lib")  
  6. #pragma comment(lib,"detoured.lib")  
  7. #ifdef _MANAGED  
  8. #pragma managed(push, off)  
  9. #endif  
  10.   
  11. //目标函数原型声明  
  12. typedef int (WINAPI* pfnMessageBoxA)(HWND hWnd,LPCSTR lpText,LPCSTR lpCaption,UINT uType);  
  13. //声明一个指向目标函数的指针  
  14. pfnMessageBoxA g_pMessageBoxA=::MessageBoxA;  
  15.   
  16. //截获函数  
  17. int WINAPI HookMessageBoxA(HWND hWnd,LPCSTR lpText,LPCSTR lpCaption,UINT uType){  
  18.     return g_pMessageBoxA(hWnd,"Target function /"MessageBoxA/" detoured./nExecute our HookMessageBoxA","Test Detour",MB_OK | MB_ICONINFORMATION);  
  19. }  
  20. //截获操作  
  21. __declspec(dllexportBOOL StartHook(){  
  22.     DetourTransactionBegin();  
  23.     DetourUpdateThread(GetCurrentThread()); //只有一个线程,所以用GetCurrentThread  
  24.     //关联目标函数和我们自定义的截获函数  
  25.     if(DetourAttach(&(PVOID&)g_pMessageBoxA,HookMessageBoxA)!=NO_ERROR){  
  26.         printf("HookMessageBoxA fail!/n");  
  27.     }  
  28.     //完成事务  
  29.     if(DetourTransactionCommit()!=NO_ERROR){  
  30.         printf("DetourTransactionCommit fail!/n");  
  31.     }else{  
  32.         printf("DetourTransactionCommit ok!/n");  
  33.         return TRUE;  
  34.     }  
  35.     return FALSE;  
  36. }  
  37. //解除截获操作  
  38. __declspec(dllexportBOOL StopHook(){  
  39.     DetourTransactionBegin();  
  40.     DetourUpdateThread(GetCurrentThread());  
  41.     //解除截获关系  
  42.     if(DetourDetach(&(PVOID&)g_pMessageBoxA,HookMessageBoxA)!=NO_ERROR){  
  43.         printf("HookMessageBoxA fail!/n");  
  44.     }  
  45.     //完成事务  
  46.     if(DetourTransactionCommit()!=NO_ERROR){  
  47.         printf("DetourTransactionCommit fail!/n");  
  48.     }else{  
  49.         printf("DetourTransactionCommit ok!/n");  
  50.         return TRUE;  
  51.     }  
  52.     return FALSE;  
  53. }  
  54.   
  55. BOOL APIENTRY DllMain( HMODULE hModule,DWORD  ul_reason_for_call,LPVOID lpReserved)  
  56. {  
  57.     switch(ul_reason_for_call){  
  58.         case DLL_PROCESS_ATTACH:  
  59.             StartHook();  
  60.             break;  
  61.         case DLL_PROCESS_DETACH:  
  62.             StopHook();  
  63.             break;  
  64.     }  
  65.     return TRUE;  
  66. }  
  67. #ifdef _MANAGED  
  68. #pragma managed(pop)  
  69. #endif  

拦截操作一般按如下步骤进行:

    1) 首先需要定义目标函数的原型。如果目标函数是Windows API,可以到MSDN中查阅,但是需要注意ANSI版本和Unicode版本的区别。如果没有确切的原型声明,或者目标函数是通过逆向工程找出来的,那么需要定义一个和目标函数原型兼容的声明,即参数个数和调用约定要相同。如MessageBoxA的原型是:

[cpp]  view plain copy
  1. int MessageBoxA( HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType);  

则使用typedef定义目标函数原型如下:

[cpp]  view plain copy
  1. typedef int (WINAPI *pfnMessageBoxA)( HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType);  

2) 定义指向目标函数的函数指针:

[cpp]  view plain copy
  1. pfnMessageBoxA g_pMessageBoxA = ::MessageBoxA;  

3) 定义截获函数并编写代码,用于替换目标函数。

4) 调用DetourTransactionBegin开始一次Detours事务。

5) 对进程中每个可能调用到目标函数的线程,都需要使用DetourUpdateThread加入到update队列中。这是因为拦截时修改目标函数的前几个字节,如果某个线程刚好执行到这几个字节的位置时,粗暴的修改掉会造成该线程出现异常。Detours事务处理时,会先枚举并暂停update队列中所有线程,获取它们的指令指针,如果发现这种情况,则将指令指针修改到跳板代码的对应字节上。这样就避免出现崩溃的问题。

6) 对每个需要拦截的函数,调用DetourAttach加入到事务列表中。

7) 调用DetourTransactionCommit进行实际的拦截操作。

解除拦截的操作和上面的流程基本一样,只是第6步改为调用DetourDetach函数。另外,Detours还包含一系列其他函数,如果需要使用的话,可以参考Detours安装目录下的示例。

最后,在DLL的加载事件加入拦截操作函数,在卸载事件中加入解除拦截的操作函数,把它编译成ApiHook.dll。

总体来说,Detours库的代码是非常稳定的,但是如果使用方法不对,会造成一些问题。有下面一些地方需要特别注意:

1) 一定要枚举线程并调用DetourUpdateThread函数。否则可能出现很低几率的崩溃问题,这种问题很难被检查出来。

2) 如果拦截函数在DLL中,那么绝大多数情况下不能在Unhook之后卸载这个DLL,或者卸载存在造成崩溃的危险。因为某些线程的调用堆栈中可能还包含Hook函数,这时卸载掉DLL,调用堆栈返回到Hook函数时内存位置已经不是合法的代码了。

3) Detours库设计时并没有考虑到卸载的问题,这是因为钩子的卸载本身是不安全的。当Detours库代码存在于DLL中的时候,即使Unhook了所有函数,清理了所有自己使用到的函数,还是会占用一些内存。卸载这个DLL会造成内存泄露,特别是反复的进行加载DLL->Hook->Unhook->卸载DLL的过程,会让这个问题变得非常严重。

4) 有一些非常短的目标函数是无法Hook的。因为jmp指令需要占用一定空间,有些函数太过短小,甚至不够jmp指令的长度,自然是没有办法Hook掉的。

5) Detours不支持9x内核的Windows系统。因为9x内核下的内存模型和NT内核下有非常大的差别。

2、将拦截DLL注入到目标应用程序中

    为了将ApiHook.dll注入到MessageBoxApp.exe中,这需要在MessageBoxApp.exe中加入.detours节。把ApiHook.dll以及Detours库中的detoured.dll拷贝到MessageBoxApp.exe所在目录(或者也可以将它们拷贝到system32目录等地方)。也就是我们在运行MessageBoxApp.exe时要确保能访问到这些DLL。我们使用Detours自带的setdll.exe重写二进制可执行文件,只要使用命令setdll /d:ApiHook.dll MessageBoxApp.exe即可,在MessageBoxApp.exe中加入一个新的.detours节。这样再运行修改后的MessageBoxApp.exe即可看到拦截的结果。我们使用depends.exe观察MessageBoxApp.exe的变化,可以看到MessageBoxApp.exe加入了对ApiHook.dll的依赖关系。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值