Detour hook库是经过微软认证的一个开源HOOK库,今天找资料发现了这个东西,特来体验一下,弄了很久找了很多资料才弄好,大部分都是教使用,没有教怎么一步一步安装,另外我只成功了X86的LIB生成,X64的不会,有会的可以回帖
首先先打开GitBub地址:https://github.com/Microsoft/Detours
进去以找到一个绿绿的按钮,上面写着clone or download,如果找不到 请在浏览器ctrl+F 查找这3个单词
下载完以后得到Detours-master文件夹,然后放到VS的安装目录,比如我的VS2015是放在D:\Program Files (x86)\Microsoft Visual Studio 14.0\Common7\IDE\devenv.exe
那么我就将文件放在D:\Program Files (x86)\Microsoft Visual Studio 14.0\
这个时候打开
我的VS只有这个,没有别的教程中的X64位,导致我只能生成X86版本,另外用CMD和PowerShell都无法生成,只能用这个,有会的大佬可以教一下
打开以后输入pushd D:\Program Files (x86)\Microsoft Visual Studio 14.0\Detours-master
按一下回车
再输入 nmake
再按一下回车
这个时候会在目录下多出3个文件夹
这个时候新建一个WIN32控制台,我实在不明白为什么C++会区分MFC项目和Win32项目,两个合为一个不好么?
然后记下我们的项目地址是C:\Users\Administrator\Documents\Visual Studio 2015\Projects\ConsoleApplication1,因为我名字取的是ConsoleApplication1,所以就是这个文件夹
然后就是空项目
这个时候就点完成,然后把我们的三个文件夹复制到这个C:\Users\Administrator\Documents\Visual Studio 2015\Projects\ConsoleApplication1项目地址
然后在头文件这里--右键---添加--现有项
导入我们include文件夹中的3个头文件,有多少个就添加多少个,我这里是三个
然后在我们的源文件这里--右键--新建项--C++文件,用来写我们自己的代码
然后在源CPP文件中写代码
[C++] 纯文本查看 复制代码 #include <iostream> //添加这个头文件,用来在控制台显示内容,也就是cout的头文件
#include <Windows.h> //这个是windows库,可以调用API
#include "../include/detours.h" //这个就是加载当前工程目录下的include文件夹中的detours.h头文件,这里是声明,注意的是一定要用/符号不能用\符号表示目录文件夹,因为\后面的字符会被转义
using namespace std; //使用std空间,因为cout就是在这个命名空间里面
#pragma comment(lib, "../lib.X86/detours.lib") //这个就是加载lib静态库,这里应该是实现,至少我是这么理解,声明在头文件,实现在lib库,不对请指正
static int (WINAPI *OldMessageBoxW)(HWND, LPCWSTR, LPCWSTR, UINT) = MessageBoxW; //这里是声明一个API函数,不是很能理解为什么要加static,然后写法是如此的,看不懂
int WINAPI NewMessageBoxW(_In_opt_ HWND hWnd, _In_opt_ LPCWSTR lpText, _In_opt_ LPCWSTR lpCaption, _In_ UINT uType) //这个就好理解了,这个是我们自定义的API函数,然后他把第二个参数的内容修改成了“经过修改的MessageBox”
{
return OldMessageBoxW(hWnd, L"经过修改的MessageBox", lpCaption, uType); //这里就是调用了,因为从HOOK的API头跳到我们自定义的函数头,总不能什么都不干吧?所以要调用他
}
void Hook() //这里是HOOK的实现,反正不是很能看得懂
{
int error = DetourTransactionBegin();
if (error != NO_ERROR)
{
cout << ("DetourTransactionBegin Error\r\n");
}
error = DetourUpdateThread(GetCurrentThread());
if (error != NO_ERROR)
{
cout << ("DetourUpdateThread Error\r\n");
}
error = DetourAttach(&(PVOID&)OldMessageBoxW, NewMessageBoxW);
if (error != NO_ERROR)
{
cout << ("DetourAttach Error\r\n");
}
error = DetourTransactionCommit();
if (error != NO_ERROR)
{
cout << ("DetourTransactionCommit Error\r\n");
}
}
int main() //Main 函数不用多解释了吧?程序运行必经之路
{
MessageBoxW(nullptr, L"Test", L"Tips", MB_OK); //先未HOOK调用,发现是正常的提示test
Hook(); //然后调用HOOK函数
MessageBoxW(nullptr, L"Test", L"Tips", MB_OK); //接着再调用一次,发现内容有所变化
system("pause"); //让控制台窗口暂停,否则会一闪而过看不到任何内容哟
return 0;
}
然后我们在OD中,看一下他的实现,分析一下原理,找到main函数
然后F2下断后F9运行,F8往下走
然后我们看分析
F7跟进这个call,发现将API头部的5个字节改了
继续F8跟着走
重点是这个call里面的内容
最后我们看这个JMP跳转的位置
这下原理就明白了,他首先把参数推栈,接着call调用补码,最后跳回到未修改的第6个字节的地址这个位置,因为前5个字节已经被破坏了,思路还是很不错的,跳到原函数执行完毕以后的代码就是处理堆栈了。
优点:免去频繁挂钩导致安全以及效率问题,我们传统的inline hook是跳到我们自定义的函数当中,还需要先把5个字节恢复才能调用API,这个的话是不需要的恢复的,因为他在自定义函数当中已经补码过了。
缺点:容易被检测挂钩,没有恢复,这个其实算小问题,可以自己脱钩的,我想应该提供了脱钩函数,虽然我不知道怎么用。 |