detours3.0文档翻译
拦截二进制函数
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
- #include <windows.h>
- #include <detours.h>
- static LONG dwSlept = 0;
- // Target pointer for the uninstrumented Sleep API.
- //
- static VOID (WINAPI * TrueSleep)(DWORD dwMilliseconds) = Sleep;
- // Detour function that replaces the Sleep API.
- //
- VOID WINAPI TimedSleep(DWORD dwMilliseconds)
- {
- // Save the before and after times around calling the Sleep API.
- DWORD dwBeg = GetTickCount();
- TrueSleep(dwMilliseconds);
- DWORD dwEnd = GetTickCount();
- InterlockedExchangeAdd(&dwSlept, dwEnd - dwBeg);
- }
- // DllMain function attaches and detaches the TimedSleep detour to the
- // Sleep target function. The Sleep target function is referred to
- // through the TrueSleep target pointer.
- //
- BOOL WINAPI DllMain(HINSTANCE hinst, DWORD dwReason, LPVOID reserved)
- {
- if (DetourIsHelperProcess()) {
- return TRUE;
- }
- if (dwReason == DLL_PROCESS_ATTACH) {
- DetourRestoreAfterWith();
- DetourTransactionBegin();
- DetourUpdateThread(GetCurrentThread());
- DetourAttach(&(PVOID&)TrueSleep, TimedSleep);
- DetourTransactionCommit();
- }
- else if (dwReason == DLL_PROCESS_DETACH) {
- DetourTransactionBegin();
- DetourUpdateThread(GetCurrentThread());
- DetourDetach(&(PVOID&)TrueSleep, TimedSleep);
- DetourTransactionCommit();
- }
- return TRUE;
- }
拦截目标函数通过与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二进制文件可以很容易恢复:从.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
Related APIs:
DetourCreateProcessWithDllEx, DetourFinishHelperProcess,DetourIsHelperProcess,DetourRestoreAfterWith.
Related Samples
Simple, Simple, Slept, Traceapi, Tracebld, Tracelnk, Tracemem,Tracereg,Traceser,Tracetcp,Tryman.
detours3.0文档翻译的更多相关文章
- Detours3.0 文档翻译
http://blog.csdn.net/buck84/article/details/8289991 拦截二进制函数 Detours库能够在执行过程中动态拦截函数调用.detours将目标函数前几个 ...
- WIN7下VS2008生成Detours3.0
Detours是微软开发的一个函数库,可用于捕获系统API.在用其进行程序开发之前,得做一些准备工作: 一.下载Detours 在http://research.microsoft.com ...
- 使用detours实现劫持
第一步:下载detours3.0,安装detours 第二步:构建库文件,nmake编译 第三步:包含库文件和头文件 #include "detours.h" //载入头文件 #p ...
- Detours信息泄漏漏洞
v\:* {behavior:url(#default#VML);} o\:* {behavior:url(#default#VML);} w\:* {behavior:url(#default#VM ...
- Detours修改段属性漏洞
v:* { } o:* { } w:* { } .shape { }p.MsoNormal,li.MsoNormal,div.MsoNormal { margin: 0cm; margin-botto ...
- Detours改动段属性漏洞
v\:* {behavior:url(#default#VML);} o\:* {behavior:url(#default#VML);} w\:* {behavior:url(#default#VM ...
- detours编译与windows下makefile学习
1.编译 windows环境命令行编译很少用,detours需要使用命令行编译,刚好试试,过程如下: 1.为了能够在所有目录中使用nmake命令,需要设置环境变量Path D:\Program Fil ...
- detours学习
最近学习detours3.0,总结下学习过程,给后来学习者一点参考,也便于自己以后复习 首先应该知道detours可以干什么,学习之前最好看一下detours文档,这个文档很简单,只有4篇文章,相对比 ...
- ZAM 3D 制作简单的3D字幕 流程(二)
原地址:http://www.cnblogs.com/yk250/p/5663907.html 文中表述仅为本人理解,若有偏差和错误请指正! 接着 ZAM 3D 制作简单的3D字幕 流程(一) .本篇 ...
随机推荐
- Robot Framework:环境安装
Windows Python2.7 前置条件:安装python2.7,下载地址:https://www.p ...
- 屏幕尺寸,分辨率,PPI,像素之间的关系
什么是屏幕尺寸? 华为荣耀7的尺寸是5.2英寸.这个5.2英寸是手机屏幕对角线的长度. 1英寸(inch)=2.54厘米(cm) 什么是分辨率? 华为荣耀7的分辨率是1920PX*1080PX.像素是 ...
- luoguP2590 [ZJOI2008]树的统计 [树链剖分] [TLE的LCT]
题目描述 一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w. 我们将以下面的形式来要求你对这棵树完成一些操作: I. CHANGE u t : 把结点u的权值改为t II. QMAX u ...
- 解决(Missing artifact com.oracle:ojdbc14:jar:11.2.0.4.0)
maven项目检索时报Missing artifact com.oracle:ojdbc14:jar:11.2.0.4.0 经过查阅资料知道原因为: Oracle 的 ojdbc.jar 是收费的,M ...
- python Pool并行执行
# -*- coding: utf-8 -*- import time from multiprocessing import Pool def run(fn): #fn: 函数参数是数据列表的一个元 ...
- linux开机故障解决方法
无法进grub方法1光盘或者网络引导进入Rescue切换原机系统 chroot /mnt/sysimage/ 安装grub grub-install /dev/sda 方法2 直接命令 grub-in ...
- caller.arguments.callee.eval
------------------------------------ 1.函数的调用方式,与this的指向问题,原型对象中的this 2.对象创建的几种方式! 3.str.replace 页面初始 ...
- 20140730 word标题样式 数组
1.word 标题四, 右键更新 自己也可以新建标题样式 2.数组 连续内存,空间复杂度高(即使数组存在一个元素,占据的空间的大小不变),时间复杂度低(0(1)访问),内存分配一次性完成
- Java 序列化和反序列化(二)Serializable 源码分析 - 1
目录 Java 序列化和反序列化(二)Serializable 源码分析 - 1 1. Java 序列化接口 2. ObjectOutputStream 源码分析 2.1 ObjectOutputSt ...
- redis 部署方式及常见特性
单机部署 redis的单机部署 如何保证redis的高并发和高可用? redis的主从复制原理?redis的哨兵原理? redis单机能承载多高并发?如果单机扛不住如何扩容扛更多的并发? redis会 ...