使用微软Detours库进行模块枚举

2024-08-21 01:44

本文主要是介绍使用微软Detours库进行模块枚举,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

Detours 是微软开发的一个强大的 Windows API 钩子库,用于监视和拦截函数调用。它广泛应用于微软产品团队和众多独立软件开发中,旨在无需修改原始代码的情况下实现函数拦截和修改。Detours 在调试、监控、日志记录和性能分析等方面表现出色,已成为开发者的重要工具。本章将指导读者运用 Detours 库实现模块查询与枚举功能,帮助读者熟悉该库的使用技巧。

DetourFindFunction

该函数的主要功能是通过模块名称和函数名称来获取函数的地址,这对于在运行时动态加载模块并查找函数地址非常有用。

函数原型

其中参数一用于指定函数的模块名称、参数二则用于指定要查找的函数名称。

PVOID DetourFindFunction(_In_ LPCSTR pszModule,_In_ LPCSTR pszFunction
);

我们可以通过使用 DetourFindFunction 获取自身进程内的 GetProcAddress 函数地址,并将其存储在 MyGetProcAddress 函数指针中。然后使用 LoadLibraryA 加载指定的动态链接库,并通过 MyGetProcAddress 函数指针获取任意模块中的函数地址。

使用示例
#include <windows.h>
#include <iostream>
#include "detours.h"#pragma comment(lib,"detours.lib")typedef FARPROC(WINAPI *GetProcAddress_t)(HMODULE hModule, LPCSTR lpProcName);int main(int argc, char *argv[])
{// 查找 kernel32.dll 中的 GetProcAddress 函数地址PVOID pFuncAddr = DetourFindFunction("kernel32.dll", "GetProcAddress");if (pFuncAddr == NULL){return 0;}std::cout << "GetProcAddress address: " << pFuncAddr << std::endl;// 将找到的地址转换为函数指针GetProcAddress_t MyGetProcAddress = (GetProcAddress_t)pFuncAddr;// 使用找到的函数指针HMODULE hModule = LoadLibraryA("user32.dll");if (hModule != NULL){// 查找模块中弹窗函数地址FARPROC pMessageBoxA = MyGetProcAddress(hModule, "MessageBoxA");if (pMessageBoxA != NULL){// 输出弹窗地址std::cout << "MessageBoxA address: " << pMessageBoxA << std::endl;}FreeLibrary(hModule);}system("pause");return 0;
}

DetourCodeFromPointer

该函数的主要功能是处理可能的代码跳转或包装指针,并返回实际的代码入口点。这在处理被包装或钩子的代码时特别有用,因为它可以跳过钩子或包装层,直接获取原始代码的地址。

函数原型

其中参数一用于指定指向代码的指针,参数二则用于接收指向全局数据的指针。

PVOID DetourCodeFromPointer(_In_ PVOID pPointer,_Out_opt_ PVOID* ppGlobals
);
使用示例
#include <windows.h>
#include <iostream>
#include "detours.h"#pragma comment(lib,"detours.lib")// 一个示例函数
void SampleFunction()
{std::cout << "SampleFunction called." << std::endl;
}int main(int argc, char *argv[])
{// 获取 SampleFunction 的地址PVOID pFuncAddr = (PVOID)&SampleFunction;// 获取实际的代码入口点PVOID pCodeAddr = DetourCodeFromPointer(pFuncAddr, NULL);// 输出地址std::cout << "Original Function Address: " << pFuncAddr << std::endl;std::cout << "Code Entry Point Address: " << pCodeAddr << std::endl;system("pause");return 0;
}

DetourCopyInstruction

该函数的主要功能是拷贝给定地址的机器指令到目标地址,并处理指令中的相对地址(如跳转、调用)。这在实现代码拦截、跳转或重定向时非常有用,特别是在需要精确控制指令级别的操作时。

函数原型

其中参数一用于指定目标地址(即将指令拷贝到的地址),参数二用于存储指令的额外数据池地址,参数三用于指定源地址(即要拷贝的指令的地址),参数四用于接收指令中目标地址(跳转或调用的目标地址)的指针,参数五用于接收指令中额外数据大小的指针。

PVOID DetourCopyInstruction(PVOID pDst,PVOID *ppDstPool,PVOID pSrc,PVOID *ppTarget,LONG *plExtra
);
使用示例
#include <windows.h>
#include <iostream>
#include "detours.h"#pragma comment(lib,"detours.lib")// 一个示例函数
void SampleFunction()
{std::cout << "SampleFunction called." << std::endl;
}int main(int argc, char *argv[])
{// 获取 SampleFunction 的地址PVOID pSrc = (PVOID)&SampleFunction;// 创建一个缓冲区用于存储拷贝的指令BYTE buffer[16] = { 0 };PVOID pDst = buffer;// 调用 DetourCopyInstruction 拷贝指令PVOID pNext = DetourCopyInstruction(pDst, NULL, pSrc, NULL, NULL);// 输出结果std::cout << "Source Address: " << pSrc << std::endl;std::cout << "Next Instruction Address: " << pNext << std::endl;std::cout << "Copied Instructions: ";for (int i = 0; i < 16; i++){std::printf("%02X ", buffer[i]);}std::cout << std::endl;system("pause");return 0;
}

DetourSetCodeModule

该函数的主要功能是设置指定代码模块的范围,以便 Detours 可以正确地处理代码拦截和重定向。这在多模块应用程序中非常有用,因为它允许你精确控制哪些代码可以被拦截或重定向。

函数原型

其中参数一用于指定要设置的代码模块的句柄,参数二则是一个布尔值,如果为 TRUE,表示仅限于该模块中的引用;如果为 FALSE,表示不限制引用。

BOOL WINAPI DetourSetCodeModule(HMODULE hModule,BOOL fLimitReferencesToModule
);

通过这些步骤,你可以使用 DetourSetCodeModule 设置代码模块的范围,从而精确控制哪些代码可以被 Detours 拦截或重定向。

使用示例
#include <windows.h>
#include <iostream>
#include "detours.h"#pragma comment(lib,"detours.lib")int main(int argc, char *argv[])
{// 获取当前进程的主模块句柄HMODULE hModule = GetModuleHandle(NULL);// 设置代码模块的范围BOOL result = DetourSetCodeModule(hModule, TRUE);if (result){std::cout << "Successfully set code module." << std::endl;}else{std::cerr << "Failed to set code module." << std::endl;return 1;}system("pause");return 0;
}

DetourGetContainingModule

该函数的主要功能是查找包含指定地址的模块的句柄。这在进行代码拦截和重定向时非常有用,因为它允许你确定特定函数或代码段所在的模块。

函数原型

该函数仅需要传入一个参数,即一个指向内存地址的指针,表示要查找其所属模块的地址。

HMODULE WINAPI DetourGetContainingModule(PVOID pvAddr);
使用示例
#include <windows.h>
#include <iostream>
#include "detours.h"#pragma comment(lib,"detours.lib")// 一个示例函数
void SampleFunction()
{std::cout << "SampleFunction called." << std::endl;
}int main(int argc, char *argv[])
{// 获取 SampleFunction 的地址PVOID pFuncAddr = (PVOID)&SampleFunction;// 调用 DetourGetContainingModule 获取包含该地址的模块句柄HMODULE hModule = DetourGetContainingModule(pFuncAddr);if (hModule != NULL){// 获取模块文件名char moduleName[MAX_PATH] = { 0 };if (GetModuleFileNameA(hModule, moduleName, sizeof(moduleName))){std::cout << "Module containing SampleFunction: " << moduleName << std::endl;}else{std::cerr << "Failed to get module file name." << std::endl;}}else{std::cerr << "Failed to find containing module." << std::endl;return 1;}system("pause");return 0;
}

DetourEnumerateModules

该函数的主要功能是遍历当前进程中的所有模块,通过反复调用该函数并传入上一个模块的句柄,你可以枚举当前进程中的所有模块。

函数原型

该函数仅需要传入一个参数,即上一个模块的句柄。如果是第一次调用该函数,应传入 NULL

HMODULE WINAPI DetourEnumerateModules(HMODULE hModuleLast);

该函数通常可配合 DetourGetEntryPointDetourGetModuleSize 一起使用,通过三个函数的配合,则可获取到当前进程中模块名、模块入口点及模块大小信息。

使用示例
#include <windows.h>
#include <iostream>
#include "detours.h"#pragma comment(lib,"detours.lib")int main(int argc, char *argv[])
{HMODULE hModule = NULL;// 枚举当前进程中的所有模块while ((hModule = DetourEnumerateModules(hModule)) != NULL){// 获取模块文件名char moduleName[MAX_PATH] = { 0 };if (GetModuleFileNameA(hModule, moduleName, sizeof(moduleName))){std::cout << "Module: " << moduleName << std::endl;}// 调用 DetourGetEntryPoint 获取模块的入口点地址PVOID pEntryPoint = DetourGetEntryPoint(hModule);if (pEntryPoint != NULL){std::cout << "Entry point address: " << pEntryPoint << std::endl;}// 调用 DetourGetModuleSize 获取模块的大小DWORD moduleSize = DetourGetModuleSize(hModule);if (moduleSize != 0){std::cout << "Module size: " << moduleSize << " bytes." << std::endl;}}system("pause");return 0;
}

DetourEnumerateExports

该函数的主要功能是枚举指定模块中的所有导出函数,并对每个导出函数调用指定的回调函数。回调函数可以用于处理或操作每个导出函数。

函数原型

其中参数一用于指定要枚举的模块的句柄,参数二用于传递给回调函数的上下文指针,可以是任何类型的数据,通常用于传递状态信息。参数三则指向回调函数的指针,该回调函数在每个导出函数上调用。

BOOL WINAPI DetourEnumerateExports(HMODULE hModule,PVOID pContext,PF_DETOUR_ENUMERATE_EXPORT_CALLBACK pfExportCallback
);

在回调函数中,参数一用于传递给 DetourEnumerateExports 的上下文指针。参数二指定导出函数的序号。参数三指定导出函数的名称。参数四指定导出函数的地址。

typedef BOOL (CALLBACK *PF_DETOUR_ENUMERATE_EXPORT_CALLBACK)(PVOID pContext,ULONG nOrdinal,LPCSTR pszName,PVOID pCode
);
使用示例
#include <windows.h>
#include <iostream>
#include "detours.h"#pragma comment(lib,"detours.lib")// 回调函数,用于处理每个导出函数
BOOL CALLBACK ExportCallback(PVOID pContext, ULONG nOrdinal, LPCSTR pszName, PVOID pCode)
{std::cout << "Ordinal: " << nOrdinal << ", Name: " << (pszName ? pszName : "(unnamed)") << ", Address: " << pCode << std::endl;return TRUE;
}int main(int argc, char *argv[])
{// 获取当前进程的主模块句柄HMODULE hModule = GetModuleHandle(NULL);if (hModule == NULL){std::cerr << "Failed to get module handle." << std::endl;return 1;}// 调用 DetourEnumerateExports 枚举导出函数if (!DetourEnumerateExports(hModule, NULL, ExportCallback)){std::cerr << "Failed to enumerate exports." << std::endl;return 1;}system("pause");return 0;
}

DetourEnumerateImports

该函数的主要功能是枚举指定模块中的所有导入函数,并对每个导入模块和导入函数调用指定的回调函数。回调函数可以用于处理或操作每个导入模块和导入函数。

函数原型

参数一用于指定要枚举的模块句柄,参数二指定回调函数上下文指针,参数三指定回调函数指针(该回调函数在每个导入模块上调用),参数四指定回调函数指针(该回调函数在每个导入函数上调用)。

BOOL WINAPI DetourEnumerateImports(HMODULE hModule,PVOID pContext,PF_DETOUR_IMPORT_FILE_CALLBACK pfImportFileCallback,PF_DETOUR_IMPORT_FUNC_CALLBACK pfImportFuncCallback
);

在文件回调函数中,参数一用于传入上下文指针,参数二传递模块名称。

typedef BOOL (CALLBACK *PF_DETOUR_IMPORT_FILE_CALLBACK)(PVOID pContext,LPCSTR pszFile
);

在函数回调函数中,参数一用于传入上下文指针,参数二为导入函数的序号,参数三为导入函数的名称,参数四为指向导入函数地址的指针。

typedef BOOL (CALLBACK *PF_DETOUR_IMPORT_FUNC_CALLBACK)(PVOID pContext,DWORD nOrdinal,LPCSTR pszFunc,PVOID *ppvFunc
);
使用示例
#include <windows.h>
#include <iostream>
#include "detours.h"#pragma comment(lib, "detours.lib")// 文件回调函数,用于处理每个导入模块(DLL)
BOOL CALLBACK ImportFileCallback(PVOID pContext, LPCSTR pszFile)
{std::cout << "Import Module: " << pszFile << std::endl;return TRUE; // 继续枚举
}// 函数回调函数,用于处理每个导入函数
BOOL CALLBACK ImportFuncCallback(PVOID pContext, DWORD nOrdinal, LPCSTR pszFunc, PVOID *ppvFunc)
{std::cout << "  Ordinal: " << nOrdinal << ", Name: " << (pszFunc ? pszFunc : "(unnamed)") << ", Address: " << *ppvFunc << std::endl;return TRUE; // 继续枚举
}int main(int argc, char *argv[])
{// 获取当前进程的主模块句柄HMODULE hModule = GetModuleHandle(NULL);if (hModule == NULL){return 1;}// 调用 DetourEnumerateImports 枚举导入函数if (!DetourEnumerateImports(hModule, NULL, (PF_DETOUR_IMPORT_FILE_CALLBACK)ImportFileCallback, (PF_DETOUR_IMPORT_FUNC_CALLBACK)ImportFuncCallback)){return 1;}system("pause");return 0;
}

这篇关于使用微软Detours库进行模块枚举的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1091770

相关文章

Java使用jar命令配置服务器端口的完整指南

《Java使用jar命令配置服务器端口的完整指南》本文将详细介绍如何使用java-jar命令启动应用,并重点讲解如何配置服务器端口,同时提供一个实用的Web工具来简化这一过程,希望对大家有所帮助... 目录1. Java Jar文件简介1.1 什么是Jar文件1.2 创建可执行Jar文件2. 使用java

C#使用Spire.Doc for .NET实现HTML转Word的高效方案

《C#使用Spire.Docfor.NET实现HTML转Word的高效方案》在Web开发中,HTML内容的生成与处理是高频需求,然而,当用户需要将HTML页面或动态生成的HTML字符串转换为Wor... 目录引言一、html转Word的典型场景与挑战二、用 Spire.Doc 实现 HTML 转 Word1

Python中logging模块用法示例总结

《Python中logging模块用法示例总结》在Python中logging模块是一个强大的日志记录工具,它允许用户将程序运行期间产生的日志信息输出到控制台或者写入到文件中,:本文主要介绍Pyt... 目录前言一. 基本使用1. 五种日志等级2.  设置报告等级3. 自定义格式4. C语言风格的格式化方法

Java中的抽象类与abstract 关键字使用详解

《Java中的抽象类与abstract关键字使用详解》:本文主要介绍Java中的抽象类与abstract关键字使用详解,本文通过实例代码给大家介绍的非常详细,感兴趣的朋友跟随小编一起看看吧... 目录一、抽象类的概念二、使用 abstract2.1 修饰类 => 抽象类2.2 修饰方法 => 抽象方法,没有

MyBatis ParameterHandler的具体使用

《MyBatisParameterHandler的具体使用》本文主要介绍了MyBatisParameterHandler的具体使用,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参... 目录一、概述二、源码1 关键属性2.setParameters3.TypeHandler1.TypeHa

Spring 中的切面与事务结合使用完整示例

《Spring中的切面与事务结合使用完整示例》本文给大家介绍Spring中的切面与事务结合使用完整示例,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考... 目录 一、前置知识:Spring AOP 与 事务的关系 事务本质上就是一个“切面”二、核心组件三、完

使用docker搭建嵌入式Linux开发环境

《使用docker搭建嵌入式Linux开发环境》本文主要介绍了使用docker搭建嵌入式Linux开发环境,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面... 目录1、前言2、安装docker3、编写容器管理脚本4、创建容器1、前言在日常开发全志、rk等不同

使用Python实现Word文档的自动化对比方案

《使用Python实现Word文档的自动化对比方案》我们经常需要比较两个Word文档的版本差异,无论是合同修订、论文修改还是代码文档更新,人工比对不仅效率低下,还容易遗漏关键改动,下面通过一个实际案例... 目录引言一、使用python-docx库解析文档结构二、使用difflib进行差异比对三、高级对比方

sky-take-out项目中Redis的使用示例详解

《sky-take-out项目中Redis的使用示例详解》SpringCache是Spring的缓存抽象层,通过注解简化缓存管理,支持Redis等提供者,适用于方法结果缓存、更新和删除操作,但无法实现... 目录Spring Cache主要特性核心注解1.@Cacheable2.@CachePut3.@Ca

C#下Newtonsoft.Json的具体使用

《C#下Newtonsoft.Json的具体使用》Newtonsoft.Json是一个非常流行的C#JSON序列化和反序列化库,它可以方便地将C#对象转换为JSON格式,或者将JSON数据解析为C#对... 目录安装 Newtonsoft.json基本用法1. 序列化 C# 对象为 JSON2. 反序列化