5

封装Detours用于Python中x64函数hook - Python成长路

 8 months ago
source link: https://www.cnblogs.com/kanadeblisst/p/17922099.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

Detours

代码仓库: https://github.com/microsoft/Detours

x64写一个任意地址hook要比x86麻烦的多,所以这里直接封装框架来用于x64的hook。

Detours是微软发布的一个API hook框架,同时支持x86和x64,看文档说也支持ARM和ARM64的Windows。

Detours翻了下github,并没有发现什么编译文档,就只有README里面有这么一段话:

1914604-20231222175106317-995951433.png

大概意思是说打开visual studio的命令行,然后切换到源码目录,执行nmake就能编译,测试除了一个小问题确实是可以编译成功。

1914604-20231222175106584-1944194802.png

visual studio的命令行在开始菜单里打开,上面两个是x86的,下面两个是x64的,至于x64和x86_x64有啥区别我就不清楚了,因为测试编译的时候没什么不一样的,就懒得去搜了。

编译的时候有一个错误: 'sn' 不是内部或外部命令,也不是可运行的程序

1914604-20231222175107474-1954375634.png

搜索发现这是一个秘钥管理和签名验证的工具,而visual studio安装完后就已经有了,那就是没加入到环境变量里,用everything搜索一下,把这个路径添加到环境变量。我就临时用set命令来设置环境变量

1914604-20231222175107873-1216075822.png

如果要编译64位就打开64位的命令行,
set path=C:\Program Files (x86)\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4.8 Tools\x64;%path%

nmake或者nmake all(可以从cmake文件里看到,还有nmake cleannmake test等)

1914604-20231222175108317-1024984555.png

这样就编译成功了,然后就会在bin.X64和lib.X64生成相应的文件,需要的是lib.X64下面的lib库

怎么编译Debug版本

这样编译出来的版本应该是Release版本,因为没有pdb文件,看了下cmake文件里的信息,指定Debug版本的变量是DETOURS_CONFIG, 而指定是x86、x64、arm的变量是DETOURS_TARGET_PROCESSOR

!IF "$(DETOURS_CONFIG)" == "Debug"
DETOURS_DEBUG=1
!ELSE
DETOURS_DEBUG=0
!ENDIF

那么只需要在编译之前执行下set DETOURS_CONFIG=Debug就可以编译成Debug版本的了,会生成一个lib.X64Debug目录,里面编译出来的lib就有了pdb文件

编译成dll

Detours的使用很简单,几行代码就行了,srcFunc是hook的函数指针的指针,注意这是二级指针(PVOID就是void *),具体为什么要定义二级指针看下面的解释。newFunc是新函数的函数指针,在c++里的话,可以直接传函数名。

#include "detours.h"

DWORD DetourHookFunction(PVOID* srcFunc, PVOID newFunc) {
	DetourTransactionBegin();
	DetourUpdateThread(GetCurrentThread());
	DetourAttach(srcFunc, newFunc);
	DetourTransactionCommit();
	return 0;
}

DWORD DetourUnHookFunction(PVOID* srcFunc, PVOID newFunc) {
	DetourTransactionBegin();
	DetourUpdateThread(GetCurrentThread());
	DetourDetach(srcFunc, newFunc);
	DetourTransactionCommit();
	return 0;
}

为了避免大家还不知道,我说一下怎么引入头文件和lib库

引入外部头文件

如果就想Detours就两个头文件,你可以直接添加到项目里,如果头文件比较多的话,放到dllmain.cpp目录下,然后在右键属性里,配置属性->C/C++->常规->附加包含目录添加这个头文件目录,我这里用$(ProjectDir)来表示项目的目录, 你也可以添加绝对路径。

注意上面配置(C)选所有配置,平台(P)选所有平台,避免每个配置都要添加一遍

1914604-20231222175108614-764489841.png

lib库则是在链接器->常规->附加库目录里添加

1914604-20231222175108869-109827803.png

你可以在输入里填lib库的名称(detours.lib)

1914604-20231222175109120-160754541.png

不过我更喜欢在代码里用#pragma comment(lib, "detours.lib")来引入lib库,因为这样可以根据宏来分别引入Debug还是Release的lib

#ifdef _DEBUG
#pragma comment(lib, "detours.lib")
#else
#pragma comment(lib, "detoursd.lib")
#endif

也可以判断是x86还是x64

#ifdef _WIN64
#pragma comment(lib, "detours64.lib")
#else
#pragma comment(lib, "detours32.lib")
#endif

也可以两个宏都判断一下。

hook函数为啥要定义成二级指针

我为啥要定义成二级指针?因为DetourAttach函数就是传的二级指针,它的定义如下:

LONG WINAPI DetourAttach(_Inout_ PVOID *ppPointer,
                         _In_ PVOID pDetour);

为啥DetourAttach要把它定义成二级指针? 开始我也不理解这个问题,直到我想在Python里调用原函数,发生了无限递归的异常。

为啥C++写的代码不会触发无限递归,它同样是用的函数指针来调用,要想知道原因只能自己使用x64dbg调试看看。

经过漫长的调试发现,我传进去的ppPointer指针指向的值会被修改,它不在指向原函数(被hook函数),而是指向Detours新构建的一个函数指针,这也就能解释为啥不会无限递归了

这里再接上【Python微信机器人】第六七篇: 封装32位和64位Python hook框架实战打印微信日志这篇文章留的一个坑: 如何在新函数里调用原函数。

1914604-20231222175109348-1212915020.png

c_log_addr就是我传给DetourAttach的第一个参数ppPointer,我通过调用Detours修改后的函数指针也就是c_log_addr.value就可以避免无限递归的问题

你可以在hook前和hook后打印下c_log_addr.value的值看一下,肯定是不一样的,

Python使用Detours

这个就看【Python微信机器人】第六七篇: 封装32位和64位Python hook框架实战打印微信日志这篇文章了,里面说了怎么用Detours的dll hook日志


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK