detours介绍与使用

Detours 是Microsoft开发的一个库,下载地址http://research.microsoft.com/en-us/projects/detours/,它具有两方面的功能:

1 拦截x86机器上的任意的win32 API函数

2 插入任意的数据段到PE文件中,修改DDL文件的导入表

Detours库可以拦截任意的API调用,拦截代码是在动态运行时加载的。Detours替换目标API最前面的几条指令,使其无条件的跳转到用户提供的拦截函数。被替换的API函数的前几条指令被保存到trampoline 函数(就是内存中一个数据结构)中。trampoline保存了被替换的目标API的前几条指令和一个无条件转移,转移到目标API余下的指令。

当执行到目标API时,直接跳到用户提供的拦截函数中执行,这时拦截函数就可以执行自己的代码了。当然拦截函数可以直接返回,也可以调用trampoline(蹦床,跳床)函数,trampoline函数将调用被拦截的目标API,目标API调用结束后又会放回到拦截函数。下图就是Detours API拦截的逻辑流程:

Detours API 拦截原理:在汇编层改变目标API出口和入口的一些汇编指令。这里略过。

Detours API 拦截技术的使用方法

先贴一个例子:

#include <windows.h>  
#include <detours.h>  
  
// 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)  
{  
    TrueSleep(dwMilliseconds);  
}  
// 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 (dwReason == DLL_PROCESS_ATTACH) {  
        DetourTransactionBegin();  
        DetourUpdateThread(GetCurrentThread());  
        DetourAttach(&(PVOID&)TrueSleep, TimedSleep);  
        DetourTransactionCommit();  
    }  
    else if (dwReason == DLL_PROCESS_DETACH) {  
        DetourTransactionBegin();  
        DetourUpdateThread(GetCurrentThread());  
        DetourDetach(&(PVOID&)TrueSleep, TimedSleep);  
        DetourTransactionCommit();  
    }  
    return TRUE;  
}  

大家都知道,API HOOK都是写到DLL中的,Detours也不例外。这个例子是要hook Sleep函数,首先用TrueSleep这个函数指针保持真正的Sleep的地址。然定义一个自己的伪Sleep函数叫做TimedSleep,在这个函数中你可以做任意你想做的事情。在这个DLL被加载的时候,即DLL_PROCESS_ATTACH的时候,调用Detours函数DetourAttach(&(PVOID&)TrueSleep, TimedSleep)使用TimedSleep替换了TrueSleep。DetourTransactionBegin(),DetourUpdateThread()在Attach和Dettach之前都要调用这个函数,就是套路。最后在DLL_PROCESS_DETACH的时候解除对Sleep的hook。就是unhook。

Detours 修改PE文件的方法。本人没有用过,就不讲了。

=========================================================================================

Detours是微软开发的一个函数库,可用于捕获系统API(Windows API)。在用其进行程序开发之前,得做一些准备工作:

一、下载Detours
     在 http://research.microsoft.com/sn/detours  可免费下载Detours
二、安装Detours
        一路NEXT
三、生成Detours库
        在安装后的文件夹下找不到直接可以拿来用的LIB文件,但是却有SRC文件(在**\Microsoft Research\Detours Express 2.1\src下)。该文件夹下还有Makefile,可以直接用来生成库。
        将Detours路径下的SCR文件夹拷贝到**\Microsoft Visual Studio 9.0\VC路径下,注意是整个文件夹(其它版本VC自己照着复制)
        在system32目录找到cmd右键以管理员身份运行,切换至 c:\Program Files\Microsoft Visual Studio 9.0\VC\bin目录运行vcvars32.bat
        切换到\Microsoft Visual Studio9.0\VC\SRC,然后输入..\bin\nmake指令,编译成功后在\Microsoft Visual Studio9.0\VC\Lib文件下就能找到detoured.lib与detours.lib文件了。使用时直接将头文件和lib文件拷贝到自己工程目录下即可。使用命令是DOS窗口不要换成新建,貌似vcvars32.bat会为当前回话做一些环境变量。

来看几个关键函数:

在Detours库中,驱动detours执行的是函数

LONG DetourAttach(  
    PVOID * ppPointer,  
    PVOID pDetour  
);  

这个函数的职责是挂接目标API,函数的第一个参数是一个指向将要被挂接函数地址的函数指针,第二个参数是指向实际运行的函数的指针,一般来说是我们定义的替代函数的地址。但是,在挂接开始之前,还有以下几件事需要完成:
需要对detours进行初始化:DetourTransactionBegin()
需要更新进行detours的线程:DetourUpdateThread(GetCurrentThread())
在这两件事做完以后,detour函数才是真正地附着到目标函数上。
在此之后,调用DetourTransactionCommit()是detour函数起作用并检查函数的返回值判断是正确还是错误。

想把HOOK的函数改回來则可以使用

LONG WINAPI DetourDetach(  
    PVOID *ppPointer,  
    PVOID pDetour
)  

参数与DetourAttach相同

附使用简单例子:HOOK MessageBoxW函数(亲测成功,VS2008

// tt3.cpp : 定义应用程序的入口点。
//
#include "stdafx.h"
#include "tt3.h"
#include "detours.h"
#pragma comment(lib, "detours.lib")
//#pragma comment(lib, "detoured.lib")

static int (WINAPI* OLD_MessageBoxW)(HWND hWnd,LPCWSTR lpText,LPCWSTR lpCaption,UINT uType)=MessageBoxW;

int WINAPI NEW_MessageBoxW(HWND hWnd,LPCWSTR lpText,LPCWSTR lpCaption,UINT uType)
{
    //修改输入参数,调用原函数
    int ret=OLD_MessageBoxW(hWnd,L"输入参数已修改---------",L"[测试]",uType);
    return ret;
}

VOID Hook()
{
    DetourRestoreAfterWith();
    DetourTransactionBegin();
    DetourUpdateThread(GetCurrentThread());
    //这里可以连续多次调用DetourAttach,表明HOOK多个函数
    DetourAttach(&(PVOID&)OLD_MessageBoxW,NEW_MessageBoxW);
    DetourTransactionCommit();
}

VOID UnHook()
{
    DetourTransactionBegin();
    DetourUpdateThread(GetCurrentThread());
    //这里可以连续多次调用DetourDetach,表明撤销多个函数HOOK
    DetourDetach(&(PVOID&)OLD_MessageBoxW,NEW_MessageBoxW);
    DetourTransactionCommit();
}

int APIENTRY _tWinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPTSTR lpCmdLine,
int nCmdShow)
{
    MessageBoxW(0,L"正常消息框",L"测试",0);
    Hook();
    MessageBoxW(0,L"正常消息框",L"测试",0);
    UnHook();
    return 0;
}

还有一個DetourCreateProcessWithDll函数,该函数是在以DLL注入方式拦截API时使用的,它其实就是封装“CreateProcess”,以“CREATE_SUSPEND”方式创建进程,然后修改IAT,把Detoured.dll和您的*.dll插入到它的导入表,然后再启动进程。所以它的参数就是在普通的CreateProcess基础上增加了两个DLL的路径参数,最后一个参数为创建进程的函数指针,默认为CreateProcessA,简单的说就是可以在创建进程的時候加载一个dll吧

示例代码:

#undef UNICODE  
#include <cstdio>  
#include <windows.h>  
#include <detours\detours.h>  
int main()  
{     
    STARTUPINFO si;     
    PROCESS_INFORMATION pi;  
    ZeroMemory(&si, sizeof(STARTUPINFO));     
    ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));     
    si.cb = sizeof(STARTUPINFO);     
    char* DirPath = new char[MAX_PATH];     
    char* DLLPath = new char[MAX_PATH]; //testdll.dll     
    char* DetourPath = new char[MAX_PATH]; //detoured.dll   
    GetCurrentDirectory(MAX_PATH, DirPath);     
    sprintf_s(DLLPath, MAX_PATH, "%s\\testdll.dll", DirPath);     
    sprintf_s(DetourPath, MAX_PATH, "%s\\detoured.dll", DirPath);     
    DetourCreateProcessWithDll(NULL, "C:\\windows\\notepad.exe",  
        NULL,NULL, FALSE, CREATE_DEFAULT_ERROR_MODE, NULL, NULL,&si, &pi, DetourPath, DLLPath, NULL);     
    delete [] DirPath;     
    delete [] DLLPath;     
    delete [] DetourPath;     
    return 0;  
}  

当我们需要hook的函数既不是一个标准的WIN32 API,也不是导出函数。这时我们需要把我们的程序和被所要注入的程序同时编译,或者,把函数的地址硬编码

#undef UNICODE  
#include <cstdio>  
#include <windows.h>  
#include <detours\detours.h>  
typedef void (WINAPI *pFunc)(DWORD);  
void WINAPI MyFunc(DWORD);  
pFunc FuncToDetour = (pFunc)(0x0100347C); //Set it at address to detour in                     
//the process  
INT APIENTRY DllMain(HMODULE hDLL, DWORD Reason, LPVOID Reserved)  
{     
    switch(Reason)     
    {     
    case DLL_PROCESS_ATTACH:         
        {             
            DisableThreadLibraryCalls(hDLL);             
            DetourTransactionBegin();             
            DetourUpdateThread(GetCurrentThread());             
            DetourAttach(&(PVOID&)FuncToDetour, MyFunc);             
            DetourTransactionCommit();         
        }         
        break;     
    case DLL_PROCESS_DETACH:         
        DetourTransactionBegin();         
        DetourUpdateThread(GetCurrentThread());         
        DetourDetach(&(PVOID&)FuncToDetour, MyFunc);         
        DetourTransactionCommit();         
        break;     
    case DLL_THREAD_ATTACH:     
    case DLL_THREAD_DETACH:         
        break;     
    }     
    return TRUE;  
}  
void WINAPI MyFunc(DWORD someParameter)  
{     
    //Some magic can happen here
}

========================================================================================================

一、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的支持并在其网站上提供下载空间:

http://research.microsoft.com/research/downloads/Details/d36340fb-4d3c-4ddd-bf5b-1db25d03713d/Details.aspx

        目前最新的版本是: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)
{
}

Detours是微软开发的一个函数库,主要用于动态Hook运行中的程序,其具体介绍参见http://research.microsoft.com/en-us/projects/detours/。

在游戏或外挂分析中,可以利用Detours库提供的接口来动态Hook任意地址,截获函数调用并输出打印信息。

Detours Hook的3个关键概念

要理解Detours Hook,必须先理解Detours中的3个关键概念。

Target函数:即要Hook的目标函数或目标地址。

Trampoline函数:即跳板函数,主要负责保存原始Target函数头的若条指令,并加上一个跳转指令以保持对原始Target函数调用的语义完整性。

Detour函数:即截获Target函数的调用之后,所要执行的自定义函数。

Trampoline函数是由Target函数头加jmp指令组成的。

一旦Target函数被执行,程序将按照Traget→Detour→Trampoline的顺序执行,最后再回到Target函数的执行过程。

Detours Hook引擎

Detours Hook引擎采用上面介绍的Detours Hook机制,经过精心的设计,使这个Hook引擎支持动态Hook几乎任意地址,以方便管理,而不用为了Hook一个地址去增加代码以及重新编译代码(注意:这里的“任意地址”在可以被修改的地址区域内)。

Detours Hook引擎,从涉及的内存结构上看,主要由4个块组成,分别是JMP块、HOOK_INFO块、Trampoline块和HKC块,而从处理函数上看,主要由DispatchHook和ProcessHook组成。

具体细节见<<游戏外挂攻防艺术>>6.4节。

============================================================================================================================

Detours使用说明 【转载】

1 介绍
  Api hook包括两部分:api调用的截取和api函数的重定向。通过api hook可以修改函数的参数和返回值。关于原理的详细内容参见《windows核心编程》第19章和第22章。

2 Detours API hook
"Detours is a library for intercepting arbitrary Win32 binary functions on x86 machines. Interception code is applied dynamically at runtime. Detours replaces the first few instructions of the target function with an unconditional jump to the user-provided detour function. Instructions from the target function are placed in a trampoline. The address of the trampoline is placed in a target pointer. The detour function can either replace the target function, or extend its semantics by invoking the target function as a subroutine through the target pointer to the trampoline."

在Detours库中,驱动detours执行的是函数 DetourAttach(…).

LONG DetourAttach(
    PVOID * ppPointer,
    PVOID pDetour
    );

这个函数的职责是挂接目标API,函数的第一个参数是一个指向将要被挂接函数地址的函数指针,第二个参数是指向实际运行的函数的指针,一般来说是我们定义的替代函数的地址。但是,在挂接开始之前,还有以下几件事需要完成:

需要对detours进行初始化. 
需要更新进行detours的线程
这些可以调用以下函数很容的做到:

DetourTransactionBegin() 
DetourUpdateThread(GetCurrentThread()) 
在这两件事做完以后,detour函数才是真正地附着到目标函数上。在此之后,调用DetourTransactionCommit()是detour函数起作用并检查函数的返回值判断是正确还是错误。

2.1 hook DLL 中的函数

在这个例子中,将要hook winsock中的函数 send(…)和recv(…).在这些函数中,我将会在真正调用send或者recv函数前,把真正说要发送或者接收的消息写到一个日志文件中去。注意:我们自定义的替代函式一定要与被hook的函数具有相同的参数和返回值。例如,send函数的定义是这样的:

int send(
  __in  SOCKET s,
  __in  const char *buf,
  __in  int len,
  __in  int flags
);

因此,指向这个函数的指针看起来应该是这样的:

int (WINAPI *pSend)(SOCKET, const char*, int, int) = send;

把函数指针初始化成真正的函数地址是ok的;另外还有一种方式是把函数指针初始化为NULL,然后用函数DetourFindFunction(…) 指向真正的函式地址.把send(…) 和 recv(…)初始化:

int (WINAPI *pSend)(SOCKET s, const char* buf, int len, int flags) = send;
int WINAPI MySend(SOCKET s, const char* buf, int len, int flags);
int (WINAPI *pRecv)(SOCKET s, char* buf, int len, int flags) = recv;
int WINAPI MyRecv(SOCKET s, char* buf, int len, int flags);

现在,需要hook的函数和重定向到的函数已经定义好了。这里使用 WINAPI 是因为这些函数是用 __stdcall 返回值的导出函数,现在开始hook:

INT  APIENTRY DllMain( HMODULE  hDLL,  DWORD  Reason,  LPVOID  Reserved)
{
     switch (Reason)
     {
         case  DLL_PROCESS_ATTACH:
             DisableThreadLibraryCalls(hDLL);
             DetourTransactionBegin();
             DetourUpdateThread(GetCurrentThread());
             DetourAttach(&( PVOID &)pSend, MySend);
             if (DetourTransactionCommit() == NO_ERROR)
                 OutputDebugString( "send() detoured successfully" );
             break ;
     }
}

它基本上是用上面介绍的步骤开始和结束 —— 初始化,更新detours线程,用DetourAttach(…)开始hook函数,最后调用DetourTransactionCommit() 函数, 当调用成功时返回 NO_ERROR, 失败是返回一些错误码.下面是我们的函数的实现,我发送和接收的信息写入到一个日志文件中:

int  WINAPI MySend(SOCKET s,  const  char * buf,  int  len,  int  flags)
{
     fopen_s(&pSendLogFile,  "C:\\SendLog.txt" ,  "a+" );
     fprintf (pSendLogFile,  "%s\n" , buf);
     fclose (pSendLogFile);
     return  pSend(s, buf, len, flags);
}

int  WINAPI MyRecv(SOCKET s,  char * buf,  int  len,  int  flags)
{
     fopen_s(&pRecvLogFile,  "C:\\RecvLog.txt" ,  "a+" );
     fprintf (pRecvLogFile,  "%s\n" , buf);
     fclose (pRecvLogFile);
     return  pRecv(s, buf, len, flags);
}

2.2hook自定义c 函数

 举例来说明,假如有一个函数,其原型为

int RunCmd(const char* cmd);

如果要hook这个函数,可以按照以下几步来做:

a)     include 声明这个函数的头文件

b)     定义指向这个函数的函数指针,int (* RealRunCmd)(const char*) = RunCmd;

c)     定义detour函数,例如: int DetourRunCmd(const char*);

d)     实现detour函数,如:

int DetourRunCmd(const char* cmd)
{
   //extend the function,add what you want :)
   Return RealRunCme(cmd);
}

这样就完成了hook RunCmd函数的定义,所需要的就是调用DetourAttack   

DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
DetourAttach(&(PVOID&)RealRunCmd, DetourRunCmd);
if(DetourTransactionCommit() == NO_ERROR)
{
   //error
}

2.3 hook类成员函数
Hook类成员函数通过在static函数指针来实现

还是举例说明,假如有个类定义如下:

class CData
{
public:
    CData(void);
    virtual ~CData(void);
    int Run(const char* cmd);
};

现在需要hook int CData::Run(const char*) 这个函数,可以按照以下几步:

a) 声明用于hook的类

class CDataHook
{
public:
    int DetourRun(const char* cmd);
    static int (CDataHook::* RealRun)(const char* cmd);
};

b) 初始化类中的static函数指针

int (CDataHook::* CDataHook::RealRun)(const char* cmd) = (int (CDataHook::*)(const char*))&CData::Run;

c) 定义detour函数  

int CDataHook::DetourRun(const char* cmd)
{
    //添加任意你想添加的代码
    int iRet = (this->*RealRun)(cmd);
    return iRet;
}

e)     调用detourAttach函数   

DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
DetourAttach(&(PVOID&)CDataHook::RealRun, (PVOID)(&(PVOID&)CDataHook::DetourRun));
if(DetourTransactionCommit() == NO_ERROR)
{
    //error
}

2.4 DetourCreateProcessWithDll

使用这个函数相当于用CREATE_SUSPENDED 标志调用函数CreateProcess. 新进程的主线程处于暂停状态,因此DLL能在函数被运行钱被注入。注意:被注入的DLL最少要有一个导出函数. 如用testdll.dll注入到notepad.exe中:

#undef UNICODE
#include <cstdio>
#include <windows.h>
#include <detours\detours.h>
int  main()
{   
     STARTUPINFO si;   
     PROCESS_INFORMATION pi;
     ZeroMemory(&si,  sizeof (STARTUPINFO));   
     ZeroMemory(&pi,  sizeof (PROCESS_INFORMATION));   
     si.cb =  sizeof (STARTUPINFO);   
     char * DirPath =  new  char [MAX_PATH];   
     char * DLLPath =  new  char [MAX_PATH];  //testdll.dll   
     char * DetourPath =  new  char [MAX_PATH];  //detoured.dll 
     GetCurrentDirectory(MAX_PATH, DirPath);   
     sprintf_s(DLLPath, MAX_PATH,  "%s\\testdll.dll" , DirPath);   
     sprintf_s(DetourPath, MAX_PATH,  "%s\\detoured.dll" , DirPath);   
     DetourCreateProcessWithDll(NULL,  "C:\\windows\\notepad.exe" ,
         NULL,NULL, FALSE, CREATE_DEFAULT_ERROR_MODE, NULL, NULL,&si, &pi, DetourPath, DLLPath, NULL);   
     delete  [] DirPath;   
     delete  [] DLLPath;   
     delete  [] DetourPath;   
     return  0;
}

2.5 Detouring by Address
假如出现这种情况怎么办?我们需要hook的函数既不是一个标准的WIN32 API,也不是导出函数。这时我们需要吧我们的程序和被所要注入的程序同事编译,或者,把函数的地址硬编码:

#undef UNICODE
#include <cstdio>
#include <windows.h>
#include <detours\detours.h>
typedef  void  (WINAPI *pFunc)( DWORD );
void  WINAPI MyFunc( DWORD );
pFunc FuncToDetour = (pFunc)(0x0100347C);  //Set it at address to detour in the process

INT  APIENTRY DllMain( HMODULE  hDLL,  DWORD  Reason,  LPVOID  Reserved)
{   
     switch (Reason)   
     {   
     case  DLL_PROCESS_ATTACH:       
         {           
             DisableThreadLibraryCalls(hDLL);           
             DetourTransactionBegin();           
             DetourUpdateThread(GetCurrentThread());           
             DetourAttach(&( PVOID &)FuncToDetour, MyFunc);           
             DetourTransactionCommit();       
         }       
         break ;   
     case  DLL_PROCESS_DETACH:       
         DetourTransactionBegin();       
         DetourUpdateThread(GetCurrentThread());       
         DetourDetach(&( PVOID &)FuncToDetour, MyFunc);       
         DetourTransactionCommit();       
         break ;   
     case  DLL_THREAD_ATTACH:   
     case  DLL_THREAD_DETACH:       
         break ;   
     }   
     return  TRUE;
}

void  WINAPI MyFunc( DWORD  someParameter)
{   
     //Some magic can happen here
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值