相关文章推荐

Detours是一个软件包,用于在应用程序下重新路由(拦截)Win32 API。 [Detours]

二、Detours使用

我们首先需要编译指定的库,如果我们需要拦截32位程序下的函数,就编译x86版本,如果用在64位下,则编译x64版本。这个编译就不说明了。

2.1、主要接口说明

主要使用到如下的接口:

1、DetourAttach&DetourDetach

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

前一个接口用于将拦截函数附加到目标函数,后一个接口用于取消目标函数的路由。

参数说明:

pp Pointer :指向将附加到的目标指针的指针(地址)。

pDetour :指向拦截函数的指针(地址)。

如果成功,则返回 NO_ERROR ;否则,返回错误代码。

在使用这两个接口前,需要调用下面的前置接口和提交接口

2、DetourTransactionBegin

3、 DetourUpdateThread

4、DetourTransactionCommit

2.2、代码示例

//附加拦截函数
void StartHook() {
	//开始事务
	DetourTransactionBegin();
	//更新线程信息
	DetourUpdateThread(GetCurrentThread());
	//将拦截函数附加到原函数的地址上
	DetourAttach(&(PVOID&)pfnOld, pfnNew);
	//结束事务
	DetourTransactionCommit();
//解除拦截函数
void EndHook() {
	//开始事务
	DetourTransactionBegin();
	//更新线程信息 
	DetourUpdateThread(GetCurrentThread());
	//将拦截函数从原函数的地址上解除
	DetourDetach(&(PVOID&)pfnOld, pfnNew);
	//结束事务
	DetourTransactionCommit();

三、配合DLL注入使用Detours

Detours可以拦截我们想要拦截的函数,并获取或者修改函数调用信息,一般我们会编写一个dll,在dllmain中attach和detach我们的拦截函数,从而在目标进程加载我们dll时,拦截目标函数,在卸载dll时,恢复目标函数。那么远程进程注入,是一个不错的选择,可以在目标进程运行时,注入调试库,不影响目标进程的运行。DLL注入不是本章重点,所以,此处使用最简单的注入方式,也就是远程线程注入方式(仅学习使用,请勿用于非法用途,且这种方式也是最容易被发现的注入方式)。

我写了一个简单的dll注入+Detours拦截指定函数的源码(vs2022),有需要的可以下载参考下

GitHub - Prophecy2015/DLLInject

其中DLLInject是一个MFC编写的dll注入的工具,功能仅仅是向目标进程注入dll用的,需要使用管理员权限运行,不过,由于是注入工具,会被系统报病毒威胁。

TestAddDLL就是使用Detours编写的拦截Add方法的调试库

TestApp是持续调用Add方法的控制台程序,使用DLLInject向该程序注入TestAddDLL,即可打印拦截函数的内容。

3.1、找到拦截函数地址

要通过远程注入,拦截指定函数,首先就需要找到指定函数在指定进程加载后的虚拟内存空间地址,这样才能正确调用DetourAttach函数,毕竟该函数第一个参数就是待拦截的函数的地址。寻找函数地址的方法有很多,上述GitHub源码,使用了两种途径获取函数地址

3.1.1、通过导出表,查找导出函数

这种方式,适用于被导出的函数接口,这种函数接口,可以在PE文件的导出表中,找到对应的RVA,从而计算出VA地址,无需依赖dbghelp.dll接口就可以实现。

可以参考GetExportFunctionsVa函数的实现,这里涉及到对PE文件格式的解析,有兴趣的可以参考下我学习pe格式时,写的一个PETest工程(https://gitee.com/gaojunhuiwww/PETest.git),纯学习性质,大神勿喷

PVOID CMisc::GetExportFunctionsVa(const char* szModuleName, const char* szFuncName) HMODULE hMod = ::GetModuleHandleA(szModuleName); if (hMod == NULL) DLL_TRACE(_T("Can not find %s!"), szModuleName); return NULL; DWORD dwFuncRva = GetExportFunctionsRva(hMod, szFuncName); if (dwFuncRva == 0) DLL_TRACE(_T("Can not find %s in %s!"), szFuncName, szModuleName); return NULL; DLL_TRACE(_T("%s!%s : %llX!"), szModuleName, szFuncName, (PVOID)((PBYTE)hMod + dwFuncRva)); return (PVOID)((PBYTE)hMod + dwFuncRva); DWORD CMisc::GetExportFunctionsRva(HMODULE hModule, const char* strFuncName) // 获取ExportsTableRva DWORD dwExportTableRva = 0; PBYTE pByte = (PBYTE)hModule; PBYTE pTmp = pByte; if (IMAGE_DOS_SIGNATURE == *(WORD*)pTmp) //DOS头 IMAGE_DOS_HEADER* pDosHeader = (IMAGE_DOS_HEADER*)pTmp; pTmp += pDosHeader->e_lfanew; if (IMAGE_NT_SIGNATURE != *(DWORD*)(PBYTE)pTmp) return 0; pTmp += sizeof(DWORD); PIMAGE_FILE_HEADER pPEHeader = (PIMAGE_FILE_HEADER)pTmp; pTmp += sizeof(IMAGE_FILE_HEADER); // opt tou if (IMAGE_NT_OPTIONAL_HDR32_MAGIC == *(WORD*)(PBYTE)pTmp) // 32位头 dwExportTableRva = ((PIMAGE_OPTIONAL_HEADER32)pTmp)->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress; else if (IMAGE_NT_OPTIONAL_HDR64_MAGIC == *(WORD*)(PBYTE)pTmp) // 32位头 dwExportTableRva = ((PIMAGE_OPTIONAL_HEADER64)pTmp)->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress; PIMAGE_EXPORT_DIRECTORY pExportDir = (PIMAGE_EXPORT_DIRECTORY)((PBYTE)pByte + dwExportTableRva); for (int i = 0; i < pExportDir->NumberOfNames; i++) std::string strName = (char*)((PBYTE)pByte + *(DWORD*)((PBYTE)pByte + pExportDir->AddressOfNames + i * sizeof(DWORD))); if (strName == strFuncName) WORD wOrdinal = *(WORD*)((PBYTE)pByte + pExportDir->AddressOfNameOrdinals + i * sizeof(WORD)); if (wOrdinal < pExportDir->NumberOfFunctions) return *(DWORD*)((PBYTE)pByte + pExportDir->AddressOfFunctions + wOrdinal * sizeof(DWORD)); return 0;

3.1.2、通过dbghelp接口查询指定函数

这种方式,只要你有指定模块的pdb文件,你就可以找到该模块的大部分函数的地址,inline和被优化的函数除外,也包括了上诉的导出表函数。不过需要依赖dbghelp.dll。

可以参考GetFunctionsVaFromSymbols函数的实现

PVOID CMisc::GetFunctionsVaFromSymbols(PCTSTR szModuleName, PCTSTR szFunctionName, PCTSTR szSymPath/* = nullptr*/) HMODULE hMod = 0; HANDLE hProcess = 0; DWORD64 BaseOfDll = 0; PIMAGEHLP_SYMBOL pSymbol = NULL; PVOID pRet = NULL; DWORD Options = SymGetOptions(); Options = Options | SYMOPT_DEBUG; SymSetOptions(Options); if (szModuleName) hMod = GetModuleHandle(szModuleName); if (hMod == 0) DLL_TRACE(_T("Cannot find module %s"), szModuleName); return NULL; hProcess = GetCurrentProcess(); BOOL bRet = SymInitialize(hProcess, 0, TRUE); if (FALSE == bRet) DLL_TRACE(_T("SymInitialize error ...")); break; TCHAR SymbolPath[256]; GetCurrentDirectory(sizeof(SymbolPath) / sizeof(TCHAR), SymbolPath); if (nullptr != szSymPath) _tcscat_s(SymbolPath, _T(";")); _tcscat_s(SymbolPath, szSymPath); _tcscat_s(SymbolPath, _T(";")); _tcscat_s(SymbolPath, g_szPDBPath); SymSetSearchPath(hProcess, SymbolPath); TCHAR FileName[256]; GetCurrentDirectory(sizeof(FileName) / sizeof(TCHAR), FileName); _tcscat_s(FileName, _T("\\")); _tcscat_s(FileName, szModuleName); BaseOfDll = SymLoadModuleEx(hProcess, NULL, FileName, NULL, (DWORD64)hMod, 0, NULL, 0); if (BaseOfDll == 0) DLL_TRACE(_T("SymLoadModule %s error code:%d"), FileName, GetLastError()); break; ULONG64 buffer[(sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(TCHAR) + sizeof(ULONG64) - 1) / sizeof(ULONG64)]; PSYMBOL_INFO pSym = (PSYMBOL_INFO)buffer; pSym->SizeOfStruct = sizeof(SYMBOL_INFO); pSym->MaxNameLen = MAX_SYM_NAME; if (TRUE == SymFromName(hProcess, szFunctionName, pSym)) pRet = (PVOID)pSym->Address; DLL_TRACE(_T("%s!%s: %llX"), szModuleName, szFunctionName, pRet); DLL_TRACE(_T("Can not find symbol %s!%s"), szModuleName, szFunctionName); } while (false); if (BaseOfDll != 0) BOOL bRet = SymUnloadModule(hProcess, BaseOfDll); if (bRet == FALSE) DLL_TRACE(_T("SymUnloadModule Failed! err:%d"), GetLastError()); BaseOfDll = 0; SymCleanup(hProcess); return pRet; 运行完成后可以看到Detours里面的src文件夹下面有detours.h与detours.cpp,在lib.x64文件夹下面有detours.lib,我们后续使用Detours就需要这几个文件。注意,这里使用这几个文件的需要将文件复制到项目下面来,打开你的项目文件,确保下面有这几个文件,因为vs添加文件的话是不会将文件复制过来的(踩坑之一)。这个时候需要先运行vs中的一个bat文件,我的路径如下,直接将这个文件拖入cmd命令窗口中。下载的时候记住你下载的位置,默认·下载的话一般在这里面。 Microsoft Research Detours是一款强大的Windows API监控与拦截工具包,被众多独立软件开发商和微软内部产品团队广泛采用。作为一款开源软件,Detours采用MIT许可证发布,为开发者提供了灵活的API调用监控、拦截与增强能力,是Windows平台下系统级编程的必备工具。 ## 🚀 什么是Detours?它能做什么? Detours本质上是一个用于监控和 ins 开发环境,WIN10 64bit, VS2022 首先在GITHUB下载源码。GitHub - microsoft/Detours: Detours is a software package for monitoring and instrumenting API calls on Windows. It is distributed in source code form.Detours is a software package for monitor... Detours 是微软开发的一个强大的Windows API钩子库,用于监视和拦截函数调用。它广泛应用于微软产品团队和众多独立软件开发中,旨在无需修改原始代码的情况下实现函数拦截和修改。Detours 在调试、监控、日志记录和性能分析等方面表现出色,已成为开发者的重要工具。本章将指导读者编译并使用Detours库,通过实现一个简单的弹窗替换功能,帮助读者熟悉该库的使用技巧。 Detours 是Microsoft开发一个库,下载地址http://research.microsoft.com/en-us/projects/detours/,它具有两方面的功能: 1 拦截x86机器上的任意的win32 API函数。 2 插入任意的数据段到PE文件中,修改DDL文件的导入表。 Detours库可以拦截任意的API调用,拦截代码是在动态运行时加载的。Detours替换目标API最前面的几条指令,使其无条件的跳转到用户提供的拦截函数。被替换的API函数的前几条指令被保存到tram  Detours是微软开发的一个函数库,可用于捕获系统API。在用其进行程序开发之前,得做一些准备工作:一.下载Detours     在http://research.microsoft.com/sn/detours 可免费下载Detours,当前的最新版本是Detours Express 2.1 is available for immediate download under 1.5版本编译,用vs2003建一个win32工程,选lib项目。然后把所有的源文件加入进来,编译就可以了。2.1版本编译,同上,但可能出错,fatal error C1189: #error :  Must define one of DETOURS_X86, DETOURS_X64, or DETOURS_IA64                     在引用Detours的头文件之前补      在http://research.microsoft.com/sn/detours 可免费下载Detours,当前的最新版本是 Detours Express 2.1 is available for immediate download un detours是微软提供的一套工具,主要用于win32 API的拦截。 准备工作(环境) 首先下载detours的资源,地址:https://github.com/microsoft/detours 下载到本地后解压至任意文件夹; 打开cmd终端进到这个文件夹下,键入nmake; 编译完成后: 新建一个工程,将include中的detours.h移动至工程文件下; 将lib.X64(X86也有对应目录)下的detours.lib移动至工程文件下; 示例代码: #include &l 原文地址:http://www.codeproject.com/Articles/30140/API-Hooking-with-MS-Detours 在这篇文章里,我将要介绍API拦截技术的相关理论和实现方式。API拦截是一项强大的技术,他让你可以拦截某些函数,重定位到自定义的函数上。在将控制权交给原始API之前,你可以在这个自定义的函数里做任何想做的事。 本文中,我将讨论API拦 Detours 是一个用于在 ARM, ARM64, X86, X64 和 IA64 机器上拦截二进制函数的库。 Detours 最常用来拦截应用程序中的 win32 api 调用,比如添加调试工具。 拦截代码在运行时动态应用。 Detours 将目标函数的前几个指令替换为无条件跳转到用户提供的 detour 函数 它与WriteProcessMemory 有所不同 WritePro... 一般来说,使用Detours的代码都具有固定的模式。Detours 1.5和Detours 2.1的接口函数变了很多,这里按照2.1版本对基本的使用方法进行说明。常用的函数有下面几个: DetourTransactionBegin():开始一次截获或者解除截获过程。 DetourUpdateThread():列入一个在DetourTransaction过程中要进行update的线程。这个函数的 Detours是微软开发的一个函数库,可用于捕获系统API。在用其进行程序开发之前,得做一些准备工作:一.下载Detours 在http://research.microsoft.com/sn/detours 可免费下载Detours 二.安装Detours 一路NEXT 三.生成Detours库 在安装后的文件夹下找不到直接可以拿来用的LIB文件 Microsoft Research Detours Package概述 Detours是一个用于在ARM, ARM64, X86, X64和IA64机器上拦截二进制函数的库。Detours最常用来拦截应用程序中的Win32 api调用,比如添加调试工具。拦截代码在运行时动态应用。Detours将目标函数的前几个指令替换为无条件跳转到用户提供的detour函数。来自目标函数的指令被放置在蹦床上。蹦床的地址放在目标指针中。detour函数可以替换目标函数,也可以通过目标指针作为子例程调用目标...
 
推荐文章