Linux通过解析/proc/PID/maps中权限为r-xp且路径含.so的行获取动态库路径;Windows需调用EnumProcessModules与GetModuleFileNameExW枚举模块全路径。

Linux下用/proc/PID/maps解析映射的.so路径
Linux进程加载的动态库信息藏在 /proc/PID/maps 里,它不只记录.so,还包含所有内存映射区域,但可通过权限标记和文件名后缀快速筛选。关键点是:只有带可执行权限(rxp 或 r-xp)且路径以 .so 结尾(或含 .so.、.so-)的行才大概率是动态库。
实操建议:
- 读取
/proc/self/maps(当前进程)或/proc/[pid]/maps(其他进程,需权限) - 按行解析,用空格分割字段,第6列是路径(可能为空),若非空且含
.so且前一列含r-xp,就保留 - 注意路径可能为
[vdso]、[heap]等伪路径,直接跳过 - 某些系统级库(如
ld-linux-x86-64.so.2)路径不含.so但本质是动态链接器,可根据文件头或readelf -h进一步判断,一般可忽略
Windows下用EnumProcessModules + GetModuleFileNameEx获取.dll全路径
Windows没有类似 /proc 的统一视图,必须调用PSAPI接口。核心是 EnumProcessModules 枚举模块句柄,再用 GetModuleFileNameEx 获取每个模块的完整路径。注意:该函数在 Windows 7+ 上可用,但需链接 psapi.lib,且目标进程需有 PROCESS_QUERY_INFORMATION 权限。
常见错误现象:
立即学习“C++免费学习笔记(深入)”;
-
GetModuleFileNameEx返回0 → 检查是否漏了OpenProcess权限,或模块已卸载(竞态) - 返回路径为空或截断 → 缓冲区太小,务必传入
MAX_PATH大小并检查返回值是否等于MAX_PATH-1 - 只拿到模块名(如
kernel32.dll)→ 未使用完整路径版API,GetModuleFileNameEx才返回全路径,GetModuleBaseName只返回文件名
C++跨平台封装要注意的兼容性陷阱
想写一份同时支持 Linux 和 Windows 的代码,不能只靠宏开关拼凑逻辑。最易被忽略的是:Linux 下 /proc/PID/maps 是文本文件,而 Windows 是 API 调用,两者返回结果语义不同——Linux 可能列出已 mmap 但未符号解析的库(如 dlopen 加载的),Windows 则只返回 PE 格式模块,对通过 LoadLibraryA/W 加载的 DLL 才有效。
实操建议:
- Linux 路径需做 realpath 处理,因为 maps 中路径可能是相对符号链接(如
/lib/x86_64-linux-gnu/libc.so.6指向libc-2.31.so) - Windows 需处理 Unicode:用
GetModuleFileNameExW+wstring,避免 ANSI 版本在非英文路径下失败 - 不要依赖
dladdr—— 它只能查当前调用栈中符号所属模块,无法枚举全部已加载库 - 某些嵌入式或容器环境(如 musl libc、PID namespace)下
/proc不可用或不可读,应提供 fallback 日志提示
为什么 ldd 和 pstack 不适合用于运行时实时获取
ldd 是静态分析工具,它读取 ELF 的 DT_NEEDED 条目并模拟 loader 查找路径,但不会反映 dlopen 动态加载的库,也不体现运行时实际映射位置(比如被 preload 覆盖的库)。pstack 底层调用 gdb attach,会暂停目标进程,且输出是堆栈帧中的模块名,不是全路径列表,还可能因符号缺失显示为 ???。
真正需要运行时全量、准确、非侵入式获取,只能走:
- Linux:自己解析
/proc/PID/maps+readlink(/proc/PID/fd/...)补充部分符号链接(少数情况) - Windows:
EnumProcessModules+GetModuleFileNameExW组合,别试图用EnumProcessModulesEx(它多出的过滤参数在多数场景无实质帮助) - 跨平台库如
libprocps或boost::dll封装了部分逻辑,但底层仍是上述两套机制,仍需处理各自平台的边界条件
/proc/PID/maps 需目标进程未被 ptrace 或 seccomp 限制;Windows 下 OpenProcess 失败往往不是权限问题,而是目标进程开启了 PROTECT_PROCESS(如某些安全软件注入的进程)。这些细节不报错,但静默失败。



















