使用微软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;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/51926.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【无标题】Image-to-Image Translation 图像风格迁移中的成对图像拼接代码

引 言 在图像风格迁移任务中&#xff0c;近几年比较火热的Generative Adversarial Nets (GAN)模型以及各种变体深受视觉研究团体的青睐&#xff0c;在具体任务中取得比较不错的实验表现。在有监督图像风格迁移任务迁移中&#xff0c;需要输入给模型成对的图片&#xff08;一个来…

Gaussian Splatting 在 Ubuntu22.04 下部署

代码:graphdeco-inria/gaussian-splatting (github) 论文:[2308.04079] 3D Gaussian Splatting for Real-Time Radiance Field Rendering (arxiv.org) 1. 禁用自带驱动 Nouveau Ubuntu 自带的显卡驱动,是非 Nvida 官方版。在后面装 CUDA 的时候,会报驱动不兼容问题。 1.…

2024关于接口测试自动化的总结与思考!

序 近期看到阿里云性能测试 PTS 接口测试开启免费公测&#xff0c;本着以和大家交流如何实现高效的接口测试为出发点&#xff0c;本文包含了我在接口测试领域的一些方法和心得&#xff0c;希望大家一起讨论和分享&#xff0c;内容包括但不仅限于&#xff1a; 服务端接口测试介…

SQL进阶技巧:如何不使用union all进行行转列?【三种方法实现】

目录 0 前言 1 需求描述 2 数据准备 3 数据分析 3.1 lateral view explode(array()) 方法 3.2 使用stack()方法 3.3 lateral view inline(array(struct<>)) 4 小结 0 前言 行转列一直是SQL开发常见的数据结构转换方式,一般最普遍的方法就是采用union all的形…

如何将网站地图Sitemap提交至百度、谷歌及Bing搜索引擎

原文&#xff1a;如何将网站地图Sitemap提交至百度、谷歌及Bing搜索引擎 - 孔乙己大叔 (rebootvip.com) 在当今高度竞争的互联网环境中&#xff0c;搜索引擎优化&#xff08;SEO&#xff09;对于网站的可见性和成功至关重要。网站地图&#xff08;Sitemap&#xff09;&#xff…

死锁问题分析和解决——资源回收时

1.描述问题 在完成线程池核心功能功能时&#xff0c;没有遇到太大的问题&#xff08;Any,Result,Semfore的设计&#xff09;&#xff0c;在做线程池资源回收时&#xff0c;遇到了死锁的问题 1、在ThreadPool的资源回收&#xff0c;等待线程池所有线程退出时&#xff…

Window下node安装以及配置

在 Windows 下安装 Node.js 非常简单&#xff0c;你可以通过官方提供的安装程序或者使用多版本管理工具&#xff08;如 NVM-Win&#xff09;来进行安装。下面是两种方法的具体步骤&#xff1a; 1. 安装 Node.js程序 步骤如下&#xff1a; 访问官方网站&#xff1a; 访问 Node…

【Redis】数据类型详解及其应用场景

目录 Redis 常⻅数据类型预备知识基本全局命令小结 数据结构和内部编码单线程架构引出单线程模型为什么单线程还能这么快 Redis 常⻅数据类型 Redis 提供了 5 种数据结构&#xff0c;理解每种数据结构的特点对于 Redis 开发运维⾮常重要&#xff0c;同时掌握每种数据结构的常⻅…

【Oracle篇】统计信息和动态采样的深度剖析(第一篇,总共六篇)

&#x1f4ab;《博主介绍》&#xff1a;✨又是一天没白过&#xff0c;我是奈斯&#xff0c;DBA一名✨ &#x1f4ab;《擅长领域》&#xff1a;✌️擅长Oracle、MySQL、SQLserver、阿里云AnalyticDB for MySQL(分布式数据仓库)、Linux&#xff0c;也在扩展大数据方向的知识面✌️…

Go 语言运算符

Go 语言运算符 Go 语言是一种静态类型、编译型语言&#xff0c;由 Google 开发&#xff0c;旨在提高多核处理器下的编程效率。Go 语言在设计上注重简洁和高效&#xff0c;其运算符就是这一设计理念的体现。本文将详细介绍 Go 语言中的运算符&#xff0c;包括算术运算符、比较运…

PostgreSQL-02-入门篇-查询数据

文章目录 1 简单查询SELECT 语句简介SELECT 语句语法SELECT 示例1) 使用 SELECT 语句查询一列数据的示例2) 使用 SELECT 语句查询多列数据的示例3) 使用 SELECT 语句查询表所有列数据的示例4) 使用带有表达式的 SELECT 语句的示例5) 使用带有表达式的 SELECT 语句的示例 2 列别…

地平线—征程2(Journey 2-J2)芯片详解(10)—中断映射

写在前面 本系列文章主要讲解地平线征程2&#xff08;Journey 2-J2&#xff09;芯片的相关知识&#xff0c;希望能帮助更多的同学认识和了解征程2&#xff08;Journey 2-J2&#xff09;芯片。 若有相关问题&#xff0c;欢迎评论沟通&#xff0c;共同进步。(*^▽^*) 错过其他章…

MySQL基础:函数

&#x1f48e;所属专栏&#xff1a;MySQL 函数是指一段可以直接被另一段程序调用的程序或代码&#xff0c;在MySQL中也内置了许多函数供开发者去调用&#xff0c;例如之前提到的聚合函数&#xff0c;本节再去介绍一些其他常用的函数 字符串函数 函数功能CONCAT(S1,S2...Sn)字…

可视化编程-七巧低代码入门02

1.1.什么是可视化编程 非可视化编程是一种直接在集成开发环境中&#xff08;IDE&#xff09;编写代码的编程方式&#xff0c;这种编程方式要求开发人员具备深入的编程知识&#xff0c;开发效率相对较低&#xff0c;代码维护难度较大&#xff0c;容易出现错误&#xff0c;也需要…

《图解设计模式》笔记(三)生成实例

五、Singleton模式&#xff1a;只有一个实例 Singleton 是指只含有一个元素的集合。因为本模式只能生成一个实例&#xff0c;因此以 Singleton命名。 示例程序类图 Singleton.java public class Singleton {private static Singleton singleton new Singleton();private Si…

[Meachines] [Easy] bounty web.config 文件上传代码注入+内核MS10-092权限提升

信息收集 IP AddressOpening Ports10.10.10.93TCP:80 $ nmap -p- 10.10.10.93 --min-rate 1000 -sC -sV PORT STATE SERVICE VERSION │ 80/tcp open http Microsoft IIS httpd 7.5 …

x264是怎样实现多种位深(bitdepth)支持的?

随着生活水平的提高&#xff0c;小伙伴们的眼神也越发好了。8bit 位深不够用了&#xff0c;现在都 10bit&#xff0c;12bit 了。鼠哥编 x264 的时候&#xff0c;也都必须是支持 8bit 和 10bit 位深的。x264 在不同位深的支持上&#xff0c;颇具奇技淫巧。其实 x265 也不遑多让&…

使用Element UI组件时,icon图标不显示

问题描述&#xff1a; 我在使用Element UI组件的日期选择器时&#xff0c;发现图标不显示(左边是原图&#xff0c;右边的问题图)。 经过检查我发现&#xff0c;我的JS&#xff0c;CSS文件都没有问题&#xff0c;只是缺少了element-icons.tff和element-icons.woff这两个文件。 …

【运维项目经历|041】上云项目-物理机迁移到阿里云

🍁博主简介: 🏅云计算领域优质创作者 🏅2022年CSDN新星计划python赛道第一名 🏅2022年CSDN原力计划优质作者 ​ 🏅阿里云ACE认证高级工程师 ​ 🏅阿里云开发者社区专家博主 💊交流社区:CSDN云计算交流社区欢迎您的加入! 目录 项目名称 项目背景 项目目标 项…

微信小程序的四种弹窗使用

​ 在做小程序的过程中&#xff0c;弹窗也算是非常实用的功能了&#xff0c;这几天写的几个功能就用到了弹窗&#xff0c;也可能是初学者的问题&#xff0c;比较菜&#xff0c;想找一个可以带图片的自定义的弹窗&#xff0c;&#xff0c;这里简单介绍一下官方封装好的四个弹窗…