如何不打开进程句柄遍历进程中所有已加载的DLL
无目标进程句柄场景下枚举已加载DLL的实现方法
首先明确核心限制:只要要求不对目标进程创建任何类型句柄,所有依赖进程句柄的用户态枚举接口(包括EnumProcessModules、带PROCESS_QUERY_INFORMATION权限的CreateToolhelp32Snapshot模块遍历逻辑)全部不可用。
你之前尝试解析PE头失败是必然的,核心原因有两个:
- 磁盘上存储的PE文件头里的导入表,仅记录程序静态链接阶段就确定要加载的DLL,运行时通过
LoadLibrary动态加载的模块、注入类模块都不会出现在静态导入表中,拿不到全量结果。 - 就算你尝试读取目标进程内存中映射的PE头,没有合法进程句柄的前提下,你没有权限直接读取目标进程的用户态地址空间,硬读要么触发访问违例崩溃,要么读到被换出到页面文件的无效数据。
可行的无句柄实现路径只有两类:
- 内核驱动遍历方案
编写轻量内核层驱动,直接访问系统维护的进程EPROCESS结构体,遍历其内存中保存的PEB_LDR_DATA加载模块链表,或者遍历进程VadRoot下所有属性为MEM_IMAGE的内存段,校验PE头后提取模块名即可。全程不需要对目标进程创建任何句柄,拿到的是运行时全量加载的DLL列表。注意:内核态读取用户态内存地址前必须先做内存探测校验,避免访问换出页或非法地址触发蓝屏。
- 系统信息查询旁路方案
不直接操作目标进程,调用NtQuerySystemInformation接口传入对应VAD查询的信息类(不同系统版本号有差异,可通过系统版本动态适配),拉取全系统所有进程的虚拟地址描述符(VAD)快照,筛选出对应目标PID下、内存类型为MEM_IMAGE的地址段,再匹配段起始地址的PE头特征,校验为合法DLL映像后提取模块名即可。
这个方案全程只需要当前进程拥有查询系统信息的普通权限,不需要打开目标进程获取任何句柄,纯用户态就能实现,缺点是不同Windows版本的VAD信息结构体定义可能有调整,需要做多版本适配。
内容的提问来源于stack exchange,提问作者Man Ling
相关产品推荐
相关产品推荐

