一、导入 Detours 库
Detours 是微软提供的一个开发库,可以简单、高效且稳定的实现 API hook。
Detours 是一个可以在 x86、x64 和 IA64 平台上挂钩任意 win32 函数的程序开发库,它通过在需要进行挂钩的目标函数头部重写内存代码而达到接管函数控制权,进而实现自己功能的目的。除此之外,Detours 还可将任意的 Dll 或数据片段(有效载荷)注入到任意 win32 二进制文件中。
利用 Detours 库挂钩的原理其实很简单,首先我们要搞清楚 Detours 里面的三个概念:
- Target 函数:需要进行挂钩的函数,通常情况下为 Windows API(当然其实任意地址都可以挂钩,传入相应的地址即可)。
- Trampoline 函数:也叫蹦床函数,顾名思义,用来跳转的。由于我们需要在 Target 函数头写入
jmp
指令跳到我们的 Detours 函数,那么就会覆盖头部对应长度的指令,而这部分指令是没有执行的,那么我们要将这部分指令写入到我们创建的蹦床内存,对这段未在 Target 函数中执行的部分头部代码进行执行,最后再跟一个jmp
指令,跳回 Target 函数中剩余的指令继续执行。 - Detours 函数:用来代替 Target 函数,除了实现 Target 函数的功能,还要实现我们自己的功能。
所以 Detours 挂钩的原理就很简单了。首先我们需要在 Target 函数头部写入一个 5 字节的 jmp
指令跳到 Detours 函数,在 Detours 函数中,我们首先要执行 Target 函数的功能,那我们是直接从 Target 函数的头部 jmp
到 Detours 函数的,而且 Target 函数已经被改写了,如果我们在 Detours 函数中调用 Target 函数就会又跳到 Detours 函数,形成死循环。此时 Trampoline 函数就发挥作用了,在将 jmp
指令写入 Target 函数头部之前,将即将被覆盖的汇编指令拷贝到 Trampoline 函数中,最后再跟上一个 jmp
指令,跳转到 Target 剩余的部分继续执行。那么当函数流程跳到 Detours 时,我们就可以调用 Trampoline 函数执行完原函数的全部流程,然后会返回到 Detours 函数,我们就可以执行我们自己的逻辑,可以看看下面的流程图:
所以我们得提前对即将被覆盖的这部分汇编指令拷贝到我们的 Trampoline
函数中,然后在 Trampoline
函数最后跟一个 jmp
指令跳回原函数余下的代码处,
首先在需要挂钩的目标函数头部写入一个 5 字节的 jmp
指令,
直接对需要挂钩的目标函数前 5 个字节写入一个 jmp 指令,
首先,我们要想挂钩其他进程中的函数,我们可以新建一个 Dll 动态链接库工程,将需要挂钩的功能写到 Dll 中,然后我们将这个 Dll 注入到目标进程,即可实现跨进程挂钩的功能。
新建好 Dll 工程后,我们就可以导入 Detours 库了,我们可以直接去 github 上下载:
https://github.com/microsoft/Detours
下载完之后我们将其中的 Detours 文件夹导入工程,如下图所示:
注:这个 DetoursHook.cpp 和 DetoursHook.h 是自己新建的用于实现 Detours 功能的文件。
选中所有导入的 cpp 后缀文件名文件(包括自己建立的),然后 右键 -> 属性 -> C/C++ -> 预编译头 -> 不使用预编译头(至于预编译头的作用,不懂的朋友可以去了解了解)。
然后右键 uimports.cpp 文件 -> 属性 -> 常规 -> 从生成中排除 -> 是,将该文件在编译中排除。
此时我们就完成了 Detours 库的导入,直接对项目进行编译即可。