You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

自制GetModuleHandle实现函数运行异常,寻求问题排查帮助

自定义GetModuleHandle函数段错误排查

我为学习目的自行实现了WINAPI的GetModuleHandle函数,但测试时出现段错误,以下是相关代码及问题分析:

自定义函数代码

PVOID SelfGetModuleHandle(PCWSTR name) {

    PEB* pPeb = RtlGetCurrentPeb();//获取进程环境块
    PPEB_LDR_DATA pLdr = pPeb->Ldr;
    LIST_ENTRY Lentry = pLdr->InMemoryOrderModuleList;
    LIST_ENTRY FirstLentry = Lentry;
    do
    {
        LDR_DATA_TABLE_ENTRY LDataTableEntry = *(LDR_DATA_TABLE_ENTRY*)Lentry.Flink;
        if (StrCmpW(LDataTableEntry.FullDllName.Buffer, name) == 0) {
            printf("Base foud: %p\n", LDataTableEntry.DllBase);
            return (LDataTableEntry.DllBase);
        }
        Lentry = *Lentry.Flink;
    } while (memcmp(&Lentry, &FirstLentry, sizeof(LIST_ENTRY)));
    return NULL;
}

测试代码

typedef
double
(__stdcall* POW)( //假设pow来自NTDLL(偏移0x151498)
    double a,
    double b
    );

int main(){
    HMODULE dllBase = (HMODULE)SelfGetModuleHandle(L"ntdll.dll");//得到00000000001F8000,正确应为00007FFD36FD0000
    POW pow = (POW)GetProcAddress(dllBase, "pow");
    printf("%f", pow(2.0,3.0));
}

问题根源及修正

核心错误点

  1. 链表节点解析错误:InMemoryOrderModuleList的链表节点是LDR_DATA_TABLE_ENTRY结构体中的InMemoryOrderLinks成员,而非结构体本身。直接将Lentry.Flink强制转为LDR_DATA_TABLE_ENTRY*会获取到错误的结构体地址,导致读取的DllBase完全无效。
  2. 链表遍历逻辑错误:使用值拷贝Lentry = *Lentry.Flink操作链表节点,而非指针遍历,会破坏链表的遍历逻辑,导致后续访问非法内存区域。
  3. 字符串比较严谨性不足:StrCmpW区分大小写,但系统加载的模块名可能存在大小写差异,容易出现匹配失败的情况。

修正后的函数代码

#include <winternl.h>
#include <shlwapi.h>
#pragma comment(lib, "shlwapi.lib")

PVOID SelfGetModuleHandle(PCWSTR name) {
    PPEB pPeb = RtlGetCurrentPeb();
    if (!pPeb) return NULL;

    PPEB_LDR_DATA pLdr = pPeb->Ldr;
    if (!pLdr) return NULL;

    PLIST_ENTRY pCurrentEntry = pLdr->InMemoryOrderModuleList.Flink;
    PLIST_ENTRY pHeadEntry = &pLdr->InMemoryOrderModuleList;

    while (pCurrentEntry != pHeadEntry) {
        // 通过CONTAINING_RECORD宏从链表节点获取完整的LDR_DATA_TABLE_ENTRY结构体地址
        PLDR_DATA_TABLE_ENTRY pEntry = CONTAINING_RECORD(pCurrentEntry, LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks);
        
        // 忽略大小写比较模块名,提升匹配兼容性
        if (StrCmpIW(pEntry->FullDllName.Buffer, name) == 0) {
            printf("Base found: %p\n", pEntry->DllBase);
            return pEntry->DllBase;
        }

        pCurrentEntry = pCurrentEntry->Flink;
    }
    return NULL;
}

额外说明

测试代码中pow函数实际属于msvcrt.dll而非ntdll.dll,修正自定义函数后,若要正常测试需将模块名改为L"msvcrt.dll",或更换ntdll.dll中真实存在的函数进行验证。

内容的提问来源于stack exchange,提问作者Prince 2 lu

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.24 19:40:18