运用Detours库hook API(原理是改写函数的头5个字节)
一、Detours库的来历及下载:
Detours库类似于WTL的来历,是由Galen Hunt and Doug Brubacher自己开发出来,于99年7月发表在一篇名为《Detours: Binary Interception of Win32 Functions.》的论文中。基本原理是改写函数的头5个字节(因为一般函数开头都是保存堆栈环境的三条指令共5个字节:8B FF 55 8B EC)为一条跳转指令,直接跳转到自己的函数开头,从而实现API拦截的。后来得到MS的支持并在其网站上提供下载空间:
目前最新的版本是:Detours Express 2.1。
二、Detours的使用准备:
Detours库是以源码形式提供的,这给我们的使用带来极大的方便。你可以选择把它编译成库、也可以直接把源码加入工程……形式使用。农夫采取的方法是编译成库后使用的。编译库的方法很简单,下载包中已经制作好了makefile,我们只须直接用vc下的nmake工具直接编译即可。鉴于前段时间在网上看见有部分朋友对此也存疑惑,农夫在此“浪费”一下空间,详细解说一下编译的过程(括号中为本人的例子):
1、运行你下载的安装包,把文件解压到磁盘上
此处建议您把解压后的src文件夹拷贝到VC的安装目录的VC98子目录下(D:/SDK/6.0/VC98)。对于像我一样使用库的方式会有好处,稍后即讲:)。
2、编译并设置开发环境
在你刚才拷贝过去的src文件夹下建立一个*.bat文件,里面填上“../bin/nmake”内容后保存即可。运行该批处理文件,恭喜您:库已经编译完成,唯一要做的是要把../bin/Detoured.dll拷贝到您的系统目录下。现在您的工程里面包含如下文件即可运用Detours库来进行开发了:
#include <detours.h>
#pragma comment(lib, "detours.lib")
#pragma comment(lib, "detoured.lib")
对于没有把src文件拷贝过来的朋友,也不用着急。bat文件中把路径用全路径即可进行编译。不过你除了拷贝.dll文件外,还得要把.lib、.h文件拷贝到VC目录下,或者在你的VC环境中设置这些文件的包含路径,才可正常使用VC进行开发。看,是不是要麻烦些?
另外的建议:在Detours.h文件中定义一个函数指针类型,到用的时候您就知道会很方便了:
typedef LONG (WINAPI* Detour)(PVOID*, PVOID);
三、几个重要的函数:
1、DetourAttach & DetourDetach
这两个函数就是实际实现API挂钩的(改写头5个字节为一个跳转指令),前一个实现API拦截,后一个为在不需要的时候恢复原来的API。
第一个参数为自己定义的一个用于保存原来系统API的函数,该函数就相当于您没挂钩时的API。农夫习惯于在原有API的基础上加以“Sys”前缀来命名;
第二个参数为自己拦截API的功能函数,您想干什么“坏事”都是在这个函数中实现的。农夫习惯于在原有API的基础上加以“Hook”前缀来命名。
2、DetourCreateProcessWithDll
该函数是在以DLL注入方式拦截API时使用的,它其实就是封装“CreateProcess”,以“CREATE_SUSPEND”方式创建进程,然后修改IAT,把Detoured.dll和您的*.dll插入到它的导入表,然后再启动进程。所以它的参数就是在普通的CreateProcess基础上增加了两个DLL的路径参数,最后一个参数为创建进程的函数指针,默认为CreateProcessA!这点要特别注意:如果您的程序拦截了该函数,而在HookCreateProcessA中又调用DetourCreateProcessWithDll函数的话,一定要在此传入SysCreateProcessA,否则您的程序就会递归调用了,当心您的程序崩溃!至于为何要这么调用?呵呵,问我干嘛?:)
当然其它的API也很有用,不过对于开发者来说,这三个最重要!
四、开发实例:
随源码有一个帮助文档,上面列举了很多例子:包含普通的API、类成员函数、COM接口、DLL方式注入……。包含了我们的大多应用领域。
下面举个拦截CreateFileA函数的例子。该例子将所有创建的文件移动到指定目录下(晕,第一次使用,怎么不能插入C++代码?):
1、定义保存系统原来函数的函数SysCreateProcessA:(听起来有点拗口)
static HANDLE (WINAPI* SysCreateFileA)( LPCTSTR lpFileName, // pointer to name of the file
DWORD dwDesiredAccess, // access (read-write) mode
DWORD dwShareMode, // share mode
LPSECURITY_ATTRIBUTES lpSecurityAttributes, // pointer to security attributes
DWORD dwCreationDisposition, // how to create
DWORD dwFlagsAndAttributes, // file attributes
HANDLE hTemplateFile // handle to file with attributes to copy
) = CreateFileA;
2、编写自己的功能函数:
HANDLE WINAPI HookCreateFileA( LPCTSTR lpFileName, // pointer to name of the file
DWORD dwDesiredAccess, // access (read-write) mode
DWORD dwShareMode, // share mode
LPSECURITY_ATTRIBUTES lpSecurityAttributes, // pointer to security attributes
DWORD dwCreationDisposition, // how to create
DWORD dwFlagsAndAttributes, // file attributes
HANDLE hTemplateFile // handle to file with attributes to copy
)
{
char chDestFile[256];
strcpy(chDestFile, lpFileName);
if( strstr(lpFileName, "////.//") != NULL ) // 放过设备
{
// 创建的普通文件全部转到D盘去,这里没考虑是“读”访问
char *p = strrchr(lpFileName, '//');
if( p++ == NULL )
{
p = lpFileName;
}
sprintf(chDestFile, "D://%s", p);
}
// 创建文件,注意这里不可以再调用CreateFileA,否则您就递归调用了!取而代之的应该是SysCreateFileA!!!!
return SysCreateFileA(chDestFile, .....); // 后面的参数照搬下来就可以了
}
3、挂钩,用自己的函数替换系统API:
DetourAttach(&(PVOID&)SysCreateFileA, HookCreateFileA);
恢复时用DetourDetach即可。
这下运行您的程序,发现所有用CreateFileA创建的新文件都被转移到D盘下了。
五、几个问题:
1、字节编码:
很多Win32函数都有多字节A版和宽字符W版,之所以平时没有附加A或W后缀,那是因为编译器已经帮我们做了这个工作。但在汇编惜字节如金的条件下,如果有两种版本,请务必明确指出,不要用CreateFile这种函数;
2、应用对象:
该库适合于初学者在RING3下对大多数API的拦截。对于那些逆向高手来说,这个简直不值一提;
3、发布:
由于该库并没有包含在MS 的SDK中,所以要随程序一块打包Detoured.dll。当然如果您是直接用源码加入工程编译的则可免去这个文件;
4、拦截DLL参数设置:
拿上面CreateFile函数来说,假如我是想在文件名称符合特定条件下才将其转移到D盘上,比如当文件类型为TXT文件时才转移。我们可以把盘符“D”及文件类型“TXT”直接写死在程序里面。这样的话,假如有其它程序是把“PDF”文件放在F盘不是又要重写一个?
不要以为加一个接口就可以解决。如是,祝贺您步入了农夫当初的歧途:)!其实要传这个参数进去的实质是进程间通信问题。本人采取的是FileMapping,改写了一下Detours的源码。当然其它进程间通信方式也是可以的。
5、拦截DLL必须导出一个函数
一般搞个空函数就可以了。如果没有任何导出函数,您辛苦编写的DLL将无法工作,还可能为此花上一大堆时间去排查。像如下声明一个就行了:
////////////////////////////////////////////////////////////////////////////////
// Must at least ONE export function:
__declspec(dllexport) void ExportFunc(void)
{
}
六、后记
乡村野夫,恍惚于世。本应扶犁,贸入IT。
三十而立,一事无成。慨殇岁逝,辗转反侧。
写文静心,闲以思远。悠悠我祖,自爱陶潜。
拙作开篇,文中如有不当/错误之处,烦请各位朋友留下您宝贵的笔墨。
======================
初版写了很久怎么都不见??????
转载于:http://blog.csdn.net/vcplayer/article/details/2681758
http://blog.csdn.net/chence19871/article/details/10372695
运用Detours库hook API(原理是改写函数的头5个字节)的更多相关文章
- 《逆向工程核心原理》——通过调试方式hook Api
1.附加目标进程, 2.CREATE_PROCESS_DEBUG_EVENT附加事件中将目标api处设置为0xcc(INT 3断点) 3.EXCEPTION_DEBUG_EVENT异常事件中,首先判断 ...
- HOOK相关原理与例子
消息HOOK 原理: 1. 用户输入消息,消息被放到系统消息队列. 2. 程序发生了某些需要获取输入的事件,就从系统消息队列拿出消息放到程序消息队列中. 3. 应用程序检测到有新的消息进入到程序消息队 ...
- [Effective JavaScript 笔记]第6章:库和API设计--个人总结
前言 又到了一章的总结,这章里的内容.是把我从一个代码的使用者,如何换位成一个代码的编写者.如何让别人用自己的代码更容易,不用去注意太多的无用细节,不用记住冗长的函数名.在使用API时怎样避免使用者会 ...
- 汇编Ring 3下实现 HOOK API
[文章标题]汇编ring3下实现HOOK API [文章作者]nohacks(非安全,hacker0058) [作者主页]hacker0058.ys168.com [文章出处]看雪论坛(bbs.ped ...
- Wordpress解析系列之PHP编写hook钩子原理简单实例
Wordpress作为全球应用最广泛的个人博客建站工具,有很多的技术架构值得我们学习推敲.其中,最著名最经典的编码技术架构就是采用了hook的机制. hook翻译成中文是钩子的意思,单独看这个词我们难 ...
- 使用函数库(JAVA API)
/*使用函数库(JAVA API) * 在JAVA的API里类被封装在一个个的package,要使用package的类之前必须 * 要知道这个类属于哪个package * 引用类方式: * 1.通过i ...
- HOOK API 在多线程时应该注意的问题点
在使用INLINE HOOK API实现对系统API的拦截时,正常情况下并没有太大问题,但一旦涉及到多线程,不管是修改IAT还是JMP,2种方法均会出现不可预料的问题,特别是在HOOK一些复杂的大型系 ...
- HOOK API(四)—— 进程防终止
HOOK API(四) —— 进程防终止 0x00 前言 这算是一个实战吧,做的一个应用需要实现进程的防终止保护,查了相关资料后决定用HOOK API的方式实现.起初学习HOOK API ...
- HOOK API(三)—— HOOK 所有程序的 MessageBox
HOOK API(三) —— HOOK 所有程序的 MessageBox 0x00 前言 本实例要实现HOOK MessageBox,包括MessageBoxA和MessageBoxW,其实现细节与H ...
随机推荐
- php 数组 array_values () array_key()
<?php // array_unique($array) 去除重复 // array_unshif()向数组的顶部追加函数 // array_shif($a,"ss")向数 ...
- CentOS6.5下Mysql数据库的安装与配置
一.mysql简介 说到数据库,我们大多想到的是关系型数据库,比如mysql.oracle.sqlserver等等,这些数据库软件在windows上安装都非常的方便,在Linux上如果要安装数据库,咱 ...
- linux shell--算术运算
求和: 方法一.使用命令替换法: #!/bin/bash read -p 'input number a...' numA read -p 'input number b...' numB #这里有两 ...
- QT---线程间通信
在 Qt 系统中,运行着一个GUI 主事件线程,这个主线程从窗口系统中获取事件,并将它们分发到各个组件去处理.在 QThread 类中有一种从非主事件线程中将事件提交给一个对象的方法,也就是 QThr ...
- 这是一个hibernate 联合主键的例子
package com.bird.entity; import java.io.Serializable; import javax.persistence.Entity; import javax. ...
- Javascript数组操作方法
1.shift:删除原数组第一项,并返回删除元素的值:如果数组为空则返回undefined var a = [1,2,3,4,5]; var b = a.shift(); //a:[2,3,4,5] ...
- Linux fdisk命令参数及用法详解---Linux磁盘分区管理命令fdisk
fdisk 命令 linux磁盘分区管理 用途:观察硬盘之实体使用情形与分割硬盘用. 使用方法: 一.在 console 上输入 fdisk -l /dev/sda ,观察硬盘之实体使用情形. 二.在 ...
- 解决:Incorrect line ending: found carriage return (\r) without corresponding newline (\n)
解决方案: ——clean一下项目,这个方法可以解决 . 此方案经过验证OK
- BestCoder Round #3 A,B
A.预处理出来,0(1)输出. Task schedule Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K ...
- UI设计师不可不知的安卓屏幕知识
不少设计师和工程师都被安卓设备纷繁的屏幕搞得晕头转向,我既做UI设计,也做过一点安卓界面布局,刚好对这块内容比较熟悉,也曾在公司内部做过相关的讲座,在此,我将此部分知识重新梳理出来分享给大家! 1.了 ...