要获取一个二进制文件通过dlopen()动态加载的库你不能依赖ldd这类静态分析工具。因为dlopen()是在程序运行时才决定加载哪些库这些库的路径甚至可以是动态拼接的所以它们不会写在文件的依赖信息里。你可以根据具体场景从下面几种方法中选择一种。方法一运行时拦截与追踪 (最推荐)这是最可靠的方法。通过拦截程序对dlopen的调用你可以实时、准确地记录下所有动态加载的库。1. 使用LD_PRELOAD技术 (通用)LTTng 项目提供了一个名为liblttng-ust-dl.so的库它的工作原理就是利用LD_PRELOAD环境变量在目标程序启动时抢先注入自己从而钩取 (hook) 所有的dlopen调用并打印出加载的库路径。操作步骤# 安装 lttng-ust-tools (不同发行版包名可能略有不同) # 对于 Debian/Ubuntu: sudo apt install lttng-ust-tools # 对于 RHEL/CentOS: sudo yum install lttng-ust # 使用 LD_PRELOAD 运行你的程序 LD_PRELOADliblttng-ust-dl.so ./your_program当程序运行时所有dlopen加载的库路径都会被追踪并输出。这是专业性能分析工具如 OpenResty XRay使用的同款方法。仅仅设置LD_PRELOADliblttng-ust-dl.so是不够的你还需要通过lttng命令启动一个追踪会话才能看到记录下来的.so库信息。liblttng-ust-dl.so这个库的作用是记录事件比如dlopen的调用但它本身不会直接把结果打印在屏幕上。你需要像一个“录音师”一样用 LTTng 的工具去控制录制和读取最终的“磁带”。完整的操作需要以下三个步骤️ 操作步骤你可以直接复制下面的完整命令块一次性执行# 1. 创建一个追踪会话 lttng create my-dlopen-session --output/tmp/my-trace # 2. 启用必要的事件这是最关键的一步 # “这是一个来自用户空间( -u )的事件我们想追踪它(lttng_ust_dl:dlopen)” lttng enable-event --userspace lttng_ust_dl:dlopen # 3. 启动追踪 lttng start # 4. 运行你的程序此时预加载的库会开始记录 dlopen 的细节 LD_PRELOADliblttng-ust-dl.so ./你的程序 # 5. 程序运行完毕后停止追踪 lttng stop # 6. 销毁会话这会触发将内存中的数据刷新到磁盘 lttng destroy 如何查看结果追踪完成后原始数据是二进制格式需要使用babeltrace2这个工具来将它转换成人类可读的文本。babeltrace2 /tmp/my-trace如果一切顺利你会看到类似下面的输出其中path ...这一行就是你想要找的动态库路径[16:45:21.123456789] (0.000000123) 主机名 lttng_ust_dl:dlopen: { cpu_id 0 }, { baddr 0x7f1234560000, memsz 123456, flags 1, path /home/user/test/libexample.so, # -- 这就是你需要的库路径 has_build_id 0, has_debug_link 0 } 补充说明关于lttng_ust_dl:dlopen事件从搜索结果来看lttng_ust_dl:dlopen事件中path字段记录的就是dlopen()调用时传递的路径。官方手册也指出虽然liblttng-ust-dl.so也能产生其他类型的事件但对于追踪库加载路径这个需求直接使用lttng_ust_dl:dlopen是最直观和可靠的。为何需要lttng enable-event这是新手最容易遗漏的一步。liblttng-ust-dl.so就像一个“摄像机”而lttng enable-event命令则是告诉 LTTng 系统“请开始录制这台摄像机拍到的画面”。没有这个命令即使摄像机在运行也没有人在保存录像。2. 使用strace(系统调用追踪)strace可以追踪进程发起的系统调用。dlopen底层会调用open、openat等系统调用来读取动态库文件。操作步骤# -e 指定只追踪 open, openat 系统调用-f 跟踪子进程 strace -e open,openat -f ./your_program 21 | grep \.so这个方法的优点是几乎所有 Linux 系统都自带但输出会比较杂乱需要进行过滤。方法二静态分析与启发式方法 (作为备选)当无法动态运行程序时例如在离线分析或逆向工程中可以尝试以下方法但它们只能作为线索无法保证100%准确。1. 使用strings命令这是最简单但最不可靠的方法。strings命令可以从二进制文件中提取所有可打印字符序列。如果程序将动态库的路径以字符串常量形式写在代码中它就能被提取出来。操作步骤# -n 6 指定字符串最小长度为6然后过滤出包含 .so 的行 strings -n 8 ./your_program | grep \.so局限性如果库路径是运行时拼接的例如lib version .so或者被加密/混淆了这个方法就会失效。方法三检查/proc文件系统 (针对运行中进程)如果你已经运行了一个进程比如 PID 是 1234可以直接查看它的内存映射表。操作步骤cat /proc/1234/maps | grep \.so这个文件会列出进程当前加载的所有内存区域包括所有直接链接和通过dlopen打开的共享库。这种方法简单直接且权威因为它是系统内核给出的实际状态。总结与对比方法核心命令/操作优点缺点运行时拦截 (最推荐)LD_PRELOADliblttng-ust-dl.so ./程序100%准确专为此设计信息清晰需要额外安装lttng-ust工具系统调用追踪strace -e open ./程序 21 | grep .so无需安装额外工具通用性强输出冗余需要从大量日志中筛选静态字符串提取strings ./程序 | grep .so无需运行程序快速简单只能发现硬编码路径漏报率高进程内存检查cat /proc/PID/maps | grep .so针对已在运行的进程准确且直接需要进程已经在运行对于绝大多数的分析需求优先推荐LD_PRELOAD方法这是专门为解决此类问题而设计的。参考lttng-tools和lttng-ust包详解-CSDN博客
获取dlopen动态库方法
要获取一个二进制文件通过dlopen()动态加载的库你不能依赖ldd这类静态分析工具。因为dlopen()是在程序运行时才决定加载哪些库这些库的路径甚至可以是动态拼接的所以它们不会写在文件的依赖信息里。你可以根据具体场景从下面几种方法中选择一种。方法一运行时拦截与追踪 (最推荐)这是最可靠的方法。通过拦截程序对dlopen的调用你可以实时、准确地记录下所有动态加载的库。1. 使用LD_PRELOAD技术 (通用)LTTng 项目提供了一个名为liblttng-ust-dl.so的库它的工作原理就是利用LD_PRELOAD环境变量在目标程序启动时抢先注入自己从而钩取 (hook) 所有的dlopen调用并打印出加载的库路径。操作步骤# 安装 lttng-ust-tools (不同发行版包名可能略有不同) # 对于 Debian/Ubuntu: sudo apt install lttng-ust-tools # 对于 RHEL/CentOS: sudo yum install lttng-ust # 使用 LD_PRELOAD 运行你的程序 LD_PRELOADliblttng-ust-dl.so ./your_program当程序运行时所有dlopen加载的库路径都会被追踪并输出。这是专业性能分析工具如 OpenResty XRay使用的同款方法。仅仅设置LD_PRELOADliblttng-ust-dl.so是不够的你还需要通过lttng命令启动一个追踪会话才能看到记录下来的.so库信息。liblttng-ust-dl.so这个库的作用是记录事件比如dlopen的调用但它本身不会直接把结果打印在屏幕上。你需要像一个“录音师”一样用 LTTng 的工具去控制录制和读取最终的“磁带”。完整的操作需要以下三个步骤️ 操作步骤你可以直接复制下面的完整命令块一次性执行# 1. 创建一个追踪会话 lttng create my-dlopen-session --output/tmp/my-trace # 2. 启用必要的事件这是最关键的一步 # “这是一个来自用户空间( -u )的事件我们想追踪它(lttng_ust_dl:dlopen)” lttng enable-event --userspace lttng_ust_dl:dlopen # 3. 启动追踪 lttng start # 4. 运行你的程序此时预加载的库会开始记录 dlopen 的细节 LD_PRELOADliblttng-ust-dl.so ./你的程序 # 5. 程序运行完毕后停止追踪 lttng stop # 6. 销毁会话这会触发将内存中的数据刷新到磁盘 lttng destroy 如何查看结果追踪完成后原始数据是二进制格式需要使用babeltrace2这个工具来将它转换成人类可读的文本。babeltrace2 /tmp/my-trace如果一切顺利你会看到类似下面的输出其中path ...这一行就是你想要找的动态库路径[16:45:21.123456789] (0.000000123) 主机名 lttng_ust_dl:dlopen: { cpu_id 0 }, { baddr 0x7f1234560000, memsz 123456, flags 1, path /home/user/test/libexample.so, # -- 这就是你需要的库路径 has_build_id 0, has_debug_link 0 } 补充说明关于lttng_ust_dl:dlopen事件从搜索结果来看lttng_ust_dl:dlopen事件中path字段记录的就是dlopen()调用时传递的路径。官方手册也指出虽然liblttng-ust-dl.so也能产生其他类型的事件但对于追踪库加载路径这个需求直接使用lttng_ust_dl:dlopen是最直观和可靠的。为何需要lttng enable-event这是新手最容易遗漏的一步。liblttng-ust-dl.so就像一个“摄像机”而lttng enable-event命令则是告诉 LTTng 系统“请开始录制这台摄像机拍到的画面”。没有这个命令即使摄像机在运行也没有人在保存录像。2. 使用strace(系统调用追踪)strace可以追踪进程发起的系统调用。dlopen底层会调用open、openat等系统调用来读取动态库文件。操作步骤# -e 指定只追踪 open, openat 系统调用-f 跟踪子进程 strace -e open,openat -f ./your_program 21 | grep \.so这个方法的优点是几乎所有 Linux 系统都自带但输出会比较杂乱需要进行过滤。方法二静态分析与启发式方法 (作为备选)当无法动态运行程序时例如在离线分析或逆向工程中可以尝试以下方法但它们只能作为线索无法保证100%准确。1. 使用strings命令这是最简单但最不可靠的方法。strings命令可以从二进制文件中提取所有可打印字符序列。如果程序将动态库的路径以字符串常量形式写在代码中它就能被提取出来。操作步骤# -n 6 指定字符串最小长度为6然后过滤出包含 .so 的行 strings -n 8 ./your_program | grep \.so局限性如果库路径是运行时拼接的例如lib version .so或者被加密/混淆了这个方法就会失效。方法三检查/proc文件系统 (针对运行中进程)如果你已经运行了一个进程比如 PID 是 1234可以直接查看它的内存映射表。操作步骤cat /proc/1234/maps | grep \.so这个文件会列出进程当前加载的所有内存区域包括所有直接链接和通过dlopen打开的共享库。这种方法简单直接且权威因为它是系统内核给出的实际状态。总结与对比方法核心命令/操作优点缺点运行时拦截 (最推荐)LD_PRELOADliblttng-ust-dl.so ./程序100%准确专为此设计信息清晰需要额外安装lttng-ust工具系统调用追踪strace -e open ./程序 21 | grep .so无需安装额外工具通用性强输出冗余需要从大量日志中筛选静态字符串提取strings ./程序 | grep .so无需运行程序快速简单只能发现硬编码路径漏报率高进程内存检查cat /proc/PID/maps | grep .so针对已在运行的进程准确且直接需要进程已经在运行对于绝大多数的分析需求优先推荐LD_PRELOAD方法这是专门为解决此类问题而设计的。参考lttng-tools和lttng-ust包详解-CSDN博客