http://blog.csdn.net/buck84/article/details/8289991

拦截二进制函数

Detours库能够在执行过程中动态拦截函数调用。detours将目标函数前几个指令替换为一个无条件跳转,跳转到用户定义的detour函数。被拦截的函数保存在trampoline函数中。trampoline保存了目标函数移除的指令和一个无条件跳转,能够跳转到目标函数的执行体部分(未被移除的部分)。

当运行到目标函数的时候,直接跳转到用户提供的detours拦截函数。拦截函数開始运行自己的代码。

detour函数能够直接返回或调用trampoline函数,将流程返回到拦截前。当目标函数运行完以后,再将控制交给detour函数。detour函数运行适当的代码返回。下图分别表示没有拦截和拦截以后的运行流程:

detours库通过在目标进程二进制映像中写入指令进行拦截。

对于目标函数。detours实际上写入两个函数。目标函数和trampoline函数,以及一个函数指针pointer(怀疑文档中有错误)。trampoline函数由detours动态分配。拦截之前,trampoline仅仅包括一条跳转到目标函数的语句。拦截以后。trampoline包括目标函数的初始几条语句和跳转到目标函数剩余内容的跳转指令。

目标指针最初被初始化为指向目标函数。

用detour依附(attach)到目标函数以后。目标指针就被改动为指向trampoline函数。当detour从目标函数分离(detach)以后,目标指针像開始一样指向目标函数。

上图展示了detours拦截过程。为了拦截目标函数,首先为动态trampoline函数分配内存(假设没有静态的trampoline),然后改动目标函数和trampoline为可写。

拦截的第一步,detours从目标函数中复制至少5字节指令到trampoline(足够一条无条件跳转指令)。假设目标函数小于5字节,detours退出并返回一个错误码

复制指令的过程中,detours採用了一种简单的表格驱动反汇编器。detours在trampoline最后加入一条跳转命令,跳转到目标函数第一条没有被复制的指令处。detours在目标函数的第一条指令处写入一条无条件跳转指令,跳转到detour函数中。最后,detours将目标函数和trampoline函数恢复为原始状态,然后通过调用借口FlushInstructionCache刷新cpu指令缓存。

使用Detours

为了detour目标函数,须要一个指向目标函数的指针和一个detour函数。为了可以正确拦截目标函数,detour函数和目标指针的调用规则须要一致,包含參数和调用规则。调用规则一致确保寄存器能正确保存。detour和目标函数的栈可以合理分配。

以下的代码描写叙述了detours库的用法,用户必须包括头文件detours.h,连接过程包括库detours.lib

  1. #include <windows.h>
  2. #include <detours.h>
  3. static LONG dwSlept = 0;
  4. // Target pointer for the uninstrumented Sleep API.
  5. //
  6. static VOID (WINAPI * TrueSleep)(DWORD dwMilliseconds) = Sleep;
  7. // Detour function that replaces the Sleep API.
  8. //
  9. VOID WINAPI TimedSleep(DWORD dwMilliseconds)
  10. {
  11. // Save the before and after times around calling the Sleep API.
  12. DWORD dwBeg = GetTickCount();
  13. TrueSleep(dwMilliseconds);
  14. DWORD dwEnd = GetTickCount();
  15. InterlockedExchangeAdd(&dwSlept, dwEnd - dwBeg);
  16. }
  17. // DllMain function attaches and detaches the TimedSleep detour to the
  18. // Sleep target function.  The Sleep target function is referred to
  19. // through the TrueSleep target pointer.
  20. //
  21. BOOL WINAPI DllMain(HINSTANCE hinst, DWORD dwReason, LPVOID reserved)
  22. {
  23. if (DetourIsHelperProcess()) {
  24. return TRUE;
  25. }
  26. if (dwReason == DLL_PROCESS_ATTACH) {
  27. DetourRestoreAfterWith();
  28. DetourTransactionBegin();
  29. DetourUpdateThread(GetCurrentThread());
  30. DetourAttach(&(PVOID&)TrueSleep, TimedSleep);
  31. DetourTransactionCommit();
  32. }
  33. else if (dwReason == DLL_PROCESS_DETACH) {
  34. DetourTransactionBegin();
  35. DetourUpdateThread(GetCurrentThread());
  36. DetourDetach(&(PVOID&)TrueSleep, TimedSleep);
  37. DetourTransactionCommit();
  38. }
  39. return TRUE;
  40. }

拦截目标函数通过与detour交互,调用DetourAttach实现。与detour的交互通过调用DetourTransactionBegin和DetourTransactionCommit实现。

DetourAttach包括2个參数:目标函数指针的地址和detour函数地址。

目标函数不能直接作为參数传入。由于须要传入一个目标指针。

交互过程中DetourUpdateThread更新全部线程。确保全部拦截点都能正确更新。

DetourAttach为调用目标函数分配并准备好一个trampoline。

detour执行以后,目标函数和trampoline会被重写。目标指针被更新。指向trampoline函数。

一旦目标函数被detour,目标函数的调用会被转到detour函数。目标函数通过trampoline被运行的时候。detour函数将參数复制过来,由于如今目标函数变成了detour函数的一个子程序。

要想移除拦截。能够调用detoursDetach。与DetourAttach类似,DetourDetach包括两个參数:目标函数指针地址和detour函数指针。函数运行以后。目标函数被重写为其原来的状态。trampoline函数被删除,目标函数指针恢复为原来的目标函数。

假设须要拦截的程序没有源码。detour函数须要打包为一个dll。

将dll载入到一个新的进程中。进程启动的时候调用DetourCreateProcessWithDllEx载入dll。

假设通过调用DetourCreateProcessWithDllEx插入dll,DllMain函数必须调用DetourRestoreAfterWith函数。假设希望dll可以在32位和64为机器上使用,DllMain必须调用DetourIsHelperProcess函数。

Dll必须导出DetourFinishHelperProcess函数.

注意:微软不保证或支持不论什么被改动的微软或第三方的代码,无论是採用detour改动还是其他方式改动。

detours自带样例withdll採用DetourCreateProcesswithDllEx函数启动一个新进程加载一个命名dll

Payloads和DLL导入编辑

除了连接和分离detours函数,detours包还提供了注入其它数据段的API,如二进制文件,或改动dll导入表,叫做payloads。Detours中的二进制改动API是全然可逆的,Detours在二进制中保存了恢复信息。使得全部的改动都能够还原。

windowsPE格式的二进制文件结构如上图所看到的。PE格式的windows二进制文件时COFF格式(通用文件格式)的一个扩展。

windows二进制文件包括一个DOS兼容的头,PE头。包括代码的text段,包括初始化数据的data段,包括导入的dll和函数的导入表,包括代码导出函数的导出表,调试信息。二进制文件必须包括两个头,其他的段都是可选的。

为了改动windows二进制文件,Detours创建了一个.detours段,在导出表和调试符号中间,如上图所看到的。windows二进制文件必须把调试符号放在最后。

新的段包括一个detours头。和原始PE头的一份拷贝,假设改动导入表,detours创建一个新的导入表,将其放在复制的PE头后面,然后改动原始的PE头,将其指向新的导入表。最后,Detours在.detours段的最后写入用户的payloads,然后加上调试信息完毕文件。

改动后的windows二进制文件能够非常easy恢复:从.detours段中恢复PE头。移除.detours段。上图表示的是Detours改动过的windows二进制文件格式。

创建一个导入表有2个目的。首先是保持原始的导入表不变,以便以后恢复文件,其次,新建的导入表包括重命名的导入DLL和函数,或者是整个dll和函数。比如。detours保的样例中setdll.exe这个程序。讲一个用户dll插入到目标二进制程序中。因为新的导入表在应用程序中第一个位置。所以用户的dll在程序中会首先被运行。

Detours提供了非常多实用接口。包含编辑导入表(DetourBinaryEditImports)。加入payloads(DetourBinarySetPayload)。枚举payloads(DetourBinaryEnumeratePayloads),移除payloads(DetourBinaryPurgePayloads)。DetourEnumerateModules能够枚举一个地址空间中的二进制文件。DetourFindPayload能够定位二进制文件里映射的payloads。每个payload通过一个128位的guid表示。

payloads能够将程序配置数据注入到二进制程序中。

DetourCopyPayloadToProcess能够直接将Payloads拷贝到目标进程

Detour 32位和64位进程

注意:仅仅有专业版的Detours支持64位程序。非商业版,express版本号仅仅支持32位x86系统

detours最常见的使用情况是在不改动原始二进制程序的情况下的改变函数运行情况。这时。用户提供的detour函数打包到一个dll中,在程序运行開始的时候调用DetourCreateProcesswithDll载入该dll。父进程调用DetourCreateProcesswithDll,通过插入一个导入表来改变程序内存中的拷贝。新的插入表使得系统在程序開始的时候,程序逻辑代码还没有运行的时候载入dll。这样deoturDLL就能够hook目标进程中的目标函数。

在64位的处理器上。windows支持32位或64位的应用程序。

为了支持32位或64位程序。须要创建32位和64位的detourDLL。

调用DetourCreateProcessWithDll的地方须要改为DetourCreateProcessWithDllEx。DetourCreateProcessWithDllEx会依据系统选择合适的Dll来注入目标程序。

须要这样做:

为了在一个系统上支持32位和64位程序,须要创建2个DLL。一个包括32位代码,还有一个包括64位代码。

两个DLL放在同一个文件夹中而且起同样的名字。并加上对应的后缀“32”和“64”,比方foo32.dll和foo64.dll。

调用DetourCreateProcessWithDllEx来启动一个包括对应DLL的进程。另外,你的DLL须要:

1.导出DetourFinishHelperProcess

2.在DllMain中调用DetourIsHelperProcess。假设DetourIsHelperProcess返回TRUE。则立即返回TRUE。

3.通过调用DetourCreateProcessWithDllEx而不是DetourCreateProcessWithDll来创建新的进程。

工作原理

假设目标进程跟dll的父进程同为32位或同为64位,DetourCreateProcessWithDllEx执行过程类似DetourCreateProcessWithDll。

假设父进程与目标进程不同,一个是32位,一个是64位,DetourCreateProcessWithDllEx会创建一个辅助进程。将DLL载入到rundll32.exe进程,然后调用DetourFinishHelperProcess。这个API通过使用正确的32位或64位代码来修补导入表。

应用演示样例

以下測试辅助进程,首先在32位环境中编译Detours样例。然后在64位环境中编译64位样例。然后进入样例中\tryman文件夹,在64位环境中输入"nmake size64",这样能够递归执行进程。包含32位和64位进程。

附注

关于rundll32.exe,请參考http://support.microsoft.com/kb/164787

Detours3.0 文档翻译的更多相关文章

  1. detours3.0文档翻译

    拦截二进制函数 Detours库可以在运行过程中动态拦截函数调用.detours将目标函数前几个指令替换为一个无条件跳转,跳转到用户定义的detour函数.被拦截的函数保存在trampoline函数中 ...

  2. WIN7下VS2008生成Detours3.0

    Detours是微软开发的一个函数库,可用于捕获系统API.在用其进行程序开发之前,得做一些准备工作: 一.下载Detours       在http://research.microsoft.com ...

  3. 使用detours实现劫持

    第一步:下载detours3.0,安装detours 第二步:构建库文件,nmake编译 第三步:包含库文件和头文件 #include "detours.h" //载入头文件 #p ...

  4. Detours信息泄漏漏洞

    v\:* {behavior:url(#default#VML);} o\:* {behavior:url(#default#VML);} w\:* {behavior:url(#default#VM ...

  5. Detours修改段属性漏洞

    v:* { } o:* { } w:* { } .shape { }p.MsoNormal,li.MsoNormal,div.MsoNormal { margin: 0cm; margin-botto ...

  6. Detours改动段属性漏洞

    v\:* {behavior:url(#default#VML);} o\:* {behavior:url(#default#VML);} w\:* {behavior:url(#default#VM ...

  7. detours编译与windows下makefile学习

    1.编译 windows环境命令行编译很少用,detours需要使用命令行编译,刚好试试,过程如下: 1.为了能够在所有目录中使用nmake命令,需要设置环境变量Path D:\Program Fil ...

  8. detours学习

    最近学习detours3.0,总结下学习过程,给后来学习者一点参考,也便于自己以后复习 首先应该知道detours可以干什么,学习之前最好看一下detours文档,这个文档很简单,只有4篇文章,相对比 ...

  9. ZAM 3D 制作简单的3D字幕 流程(二)

    原地址:http://www.cnblogs.com/yk250/p/5663907.html 文中表述仅为本人理解,若有偏差和错误请指正! 接着 ZAM 3D 制作简单的3D字幕 流程(一) .本篇 ...

随机推荐

  1. Linux 之 Xunsearch(2)

    Linux 之 Xunsearch(2) 参考教程:[千峰教育] Xunsearch的项目配置文件: 基本说明: (1)项目配置是一个项目的核心灵魂,非常重要,通常保存为.ini文件, 通常存储在/u ...

  2. WKWebView与js交互中产生的内存泄漏

    最近开发中突然发现富文本帖子详情内存没有释放掉,找了好久问题都没找到,终于今天发现了问题,先上一点代码片段 WKWebViewConfiguration *configuration = [[WKWe ...

  3. 牛客网 Wannafly挑战赛9 A.找一找-数据处理

    好几天没好好学习了(咸鱼晒干了) 把稍微没那么咸鱼的几天前的一场牛客网的比赛稍微看了一下,菜的要死,这一场大数的比较多,都死了. A.找一找 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C ...

  4. 两种const函数

    有两种const函数,声明如下:1.const T func();2.T func() const;第一种表示返回的是const的类型,也即返回的值不能作为左值,楼主懂的.第二种表示该成员函数不能修改 ...

  5. 通配符、正则表达式、python去重

    1.linux通配符 *:代表所有字符(0到多个); ?:代表一个字符; ;:连续不同命令之间的分隔符; #:配置文件注释; |:管道; ~:当前用户的家目录; -:上一次所在的路径; $:变量前面需 ...

  6. luogu P3808 【模板】AC自动机(简单版)

    题目背景 这是一道简单的AC自动机模板题. 用于检测正确性以及算法常数. 为了防止卡OJ,在保证正确的基础上只有两组数据,请不要恶意提交. 管理员提示:本题数据内有重复的单词,且重复单词应该计算多次, ...

  7. CompletionService 与 ExecutorService 获取任务执行结果时的区别

    CompletionService 与 ExecutorService 之间的区别 在讨论二者之间的区别之前,先交待一下背景. 看了ElasticSearch Transport模块的源码,里面充满了 ...

  8. filter和spring 的interceptor都是单例的,都不是线程安全的

    Filter 是在 Servlet 容器启动时就初始化的,因此可以认为是以单例对象存在的,如果一个请求线程对其中的成员变量修改的话,会影响到其他的请求线程,因此认为是多线程不安全的.

  9. DevExpress控件GridControl使用 z

    设置选中行的背景色.而不改变前景色. EnableAppearanceFocusedCell = False, EnableAppearanceFocusedRow = False private v ...

  10. Android-->状态栏高度,导航栏高度,Window高度,DecorView高度,heightPixels

    1:DecorView的高度 DecorView的高度代表的是: 整个装饰窗口的高度, 这个高度包括:状态烂的高度和导航栏的高度.(状态栏和导航栏通常叫做装饰窗口, 而ActionBar不属于装饰窗口 ...