如何查找DLL的最小与最大内存地址,解决注入扫内存时读取自身DLL的问题
解决方案
共有3种可落地的实现方案,可根据你的扫描场景选择:
- 方案1:直接排除自身DLL的固定模块地址范围
注入完成后第一时间调用GetModuleInformationAPI获取当前DLL在目标进程中的加载基址和镜像大小,得到固定的地址排除区间。后续扫描内存时只要当前内存块落入该区间直接跳过即可,该方案实现最简单、扫描效率最高,适合不需要排除DLL动态申请内存的场景。
核心实现代码示例:// 初始化阶段获取自身DLL信息 HMODULE hSelfModule = GetModuleHandle(L"你的注入DLL文件名.dll"); MODULEINFO selfModInfo = {0}; GetModuleInformation(GetCurrentProcess(), hSelfModule, &selfModInfo, sizeof(MODULEINFO)); ULONG_PTR excludeStart = (ULONG_PTR)selfModInfo.lpBaseOfDll; ULONG_PTR excludeEnd = excludeStart + selfModInfo.SizeOfImage; // 扫描时的过滤逻辑 MEMORY_BASIC_INFORMATION mbi; ULONG_PTR curAddr = 0; while(VirtualQuery((LPCVOID)curAddr, &mbi, sizeof(mbi)) == sizeof(mbi)) { // 命中自身DLL范围直接跳过 if(curAddr >= excludeStart && curAddr < excludeEnd) { curAddr += mbi.RegionSize; continue; } // 此处写你的正常扫描逻辑 curAddr += mbi.RegionSize; } - 方案2:通过内存块所属模块名过滤
遍历内存时调用K32GetMappedFileNameAPI查询当前内存块关联的模块文件名,和自身注入的DLL文件名做匹配,匹配成功则跳过该内存块。该方案适配性更强,就算DLL被重定位也不会影响过滤效果,但会增加扫描过程的性能开销,适合扫描频率不高的场景。 - 方案3:维护动态排除列表
如果需要同时排除DLL运行过程中通过VirtualAlloc、malloc等接口动态申请的内存,你可以额外维护一个动态排除列表,每次申请内存时将地址范围存入列表,扫描时同时和固定模块区间、动态排除列表做比对,命中则跳过。
注意事项
- 若目标进程为64位程序,需使用
ULONG_PTR类型存储地址,避免地址计算时出现整数溢出问题 - 如果你的扫描逻辑需要读取其他系统DLL的内存,不要直接排除所有模块范围,仅过滤自身DLL即可
内容的提问来源于stack exchange,提问作者GUY Yankovitch
相关产品推荐
相关产品推荐

