自制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)); }
问题根源及修正
核心错误点
- 链表节点解析错误:
InMemoryOrderModuleList的链表节点是LDR_DATA_TABLE_ENTRY结构体中的InMemoryOrderLinks成员,而非结构体本身。直接将Lentry.Flink强制转为LDR_DATA_TABLE_ENTRY*会获取到错误的结构体地址,导致读取的DllBase完全无效。 - 链表遍历逻辑错误:使用值拷贝
Lentry = *Lentry.Flink操作链表节点,而非指针遍历,会破坏链表的遍历逻辑,导致后续访问非法内存区域。 - 字符串比较严谨性不足:
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
相关产品推荐
相关产品推荐

