首页 > 其他分享 >使用微软Detours库进行模块枚举

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

时间:2024-08-20 16:49:56浏览次数:10  
标签:PVOID 函数 lib 微软 枚举 参数 Detours 模块 include

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;
}

标签:PVOID,函数,lib,微软,枚举,参数,Detours,模块,include
From: https://www.cnblogs.com/LyShark/p/18369761

相关文章

  • 使用微软Detours库进行DLL注入
    Detours是微软开发的一个强大的WindowsAPI钩子库,用于监视和拦截函数调用。它广泛应用于微软产品团队和众多独立软件开发中,旨在无需修改原始代码的情况下实现函数拦截和修改。本篇文章旨在帮助开发者更好地理解和应用Detours库进行DLL注入操作,从而实现对目标进程的高效控制和管......
  • python环境安装之后,cmd输入python回车会打开微软商店
    坑爹!python环境安装之后,cmd输入python回车会打开微软商店最近发现,安装python环境成功之后,可能会出现cmd输入python验证是否安装成功老会打开微软商店!解决,打开系统环境配置,找到刚安装python环境的时候加入的python安装路径你会发现这个windowsapp在python安装目录前面,把w......
  • OOP篇(Java - 抽象类、类、对象、构造器、接口、内部类、 代码块、枚举)(doing)
    目录一、抽象类1.简介2.什么时候定义抽象类?3.什么是抽象方法?4.抽象类的作用是什么?5.继承抽象类需要做什么?6.抽象类为什么不能创建对象?自己干什么,创建对象毫无意义7.final和abstract是什么关系?二、类1.简介2.表示类关系的UML符号3.类的组成4.如何定义......
  • Java:枚举转换
    在Java中,你可以使用Enum.valueOf()方法将字符串转换为枚举常量。但是,如果你想要将枚举转换为其他类型,你需要自定义转换方法。以下是一个简单的例子,演示如何将枚举转换为整数:publicenumColor{RED(1),GREEN(2),BLUE(3);privatefinalintvalue;Color(......
  • EfficientMod:微软出品,高效调制主干网络 | ICLR 2024
    EfficientModulation(EfficientMod)融合了卷积和注意力机制的有利特性,同时提取空间上下文并对输入特征进行投影,然后使用简单的逐元素乘法将其融合在一起。EfficientMod的设计保证了高效性,而固有的调制设计理念则保证了其强大的表示能力来源:晓飞的算法工程笔记公众号论文:E......
  • C++:新枚举与新结构
    一、枚举(一)C枚举?真整数!    考虑下面的程序#include<stdio.h>#include<stdlib.h>typedefenum{spring,summer,autumn,winter}Season;voidprintSeason(Seasonseason){ switch(season){ casespring: printf("spring"); break; case......
  • C#接口、结构体、抽象类、枚举、可空类型相关概念
    C#中的接口:定义一套规则,其他类实现规则。规则===》锲约,合同。接口必须实现,才能使用。接口也是多态性的表现。1、C#接口的概念?接口:使用java和asp.net等编写的API接口。让其他人通过相应的请求协议(如:http/https)来访问。理解成“在接口服务器上定义多个方法,在客户端上调用这......
  • Windows11 微软Microsoft官方制作系统U盘方法,系统安装最详细教程
    准备一个8G容量以上的U盘制作系统盘注意,在制作系统盘时会格式化U盘,所以最好准备个空U盘,请做好备份!防止资料丢失。因为做系统盘要清空原有U盘的所有数据。制作系统盘windows系统一般建议安装最新版本,如果习惯使用win10可以安装win10版本,如果是12代之后的英特尔CPU最好安装win11,对......
  • Windows11 微软Microsoft官方系统安装、重装操作教程
    01系统镜像下载推荐到微软中国官网下载Windows正版系统,或者可以到第三方的系统镜像下载站获取下载链接,使用迅雷工具进行下载,我这里推荐两个下载站,如果不想弄迅雷下载那么麻烦,也可以用我的123盘分享下载还是那句话,非常不建议下载各种奇葩定制系统,大部分系统中有夹带私货,安全性和......
  • 枚举
    枚举排列全排列voidAllPermutation(intl,intr){ vector<int>p; for(inti=l;i<=r;++i) { p.push_back(i); } do { //dosomething }while(next_permutation(p.begin(),p.end()));}子集枚举全部子集voidAllSubset(ints){ for(inti=s;i;......