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

    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, &apos;//&apos;);
      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

  • 相关阅读:
    7大python 深度学习框架的描述及优缺点绍
    nodejs 和 js
    python操redis
    python ConfigParser 的小技巧
    RHEL 7.3修改网卡命名规则为ethX
    redhat7.3配置163 yum源
    分区脚本(fdisk)
    linux之sed用法
    linux awk命令详解
    Python 装饰器学习
  • 原文地址:https://www.cnblogs.com/findumars/p/5636507.html
Copyright © 2020-2023  润新知