如何检测当前进程卸载动态库?

How do you detect the unloading of a dynamic library in the current process?

在Windows上,我们可以通过LdrDllNotification注册一个回调函数,这样当任何一个DLL即将被卸载时,我们就可以有机会收集一些关于那个DLL的有用信息,包括地址、大小等

我对类 UNIX 平台(包括 Linux、macOS、iOS、Android 等)了解不够。我怎样才能在这些平台上做同样的事情?

在 Linux 上,库由 dynamic loader. The loading is usually done automatically when needed by the loader itself, but can also be done manually using the library function dlopen(). The unloading is done manually through dlclose() 加载和卸载,或者在程序退出时自动加载和卸载。这并不普遍适用于所有 Unix 系统,但仅适用于 POSIX 兼容的系统。

不幸的是,因为(不像Windows)加载和卸载库的工作是由动态加载器(它只是一个用户空间库)执行的,内核不知道发生了什么,不提供任何检测动态库加载或卸载的机制。更不幸的是,加载器本身也不提供任何这样的机制。事实上,除了使用指标或类似的东西之外,这些功能可能几乎没有用处。

您通常甚至不会在 Linux 的 运行 时间卸载库,除非我们谈论的是一个非常复杂的软件,需要在 运行 时限制其内存占用]宁。加载程序在启动时需要时加载库(或调用第一个需要的库函数时),然后它们像任何其他内存一样留给内核在程序结束时清理。

据我所知,您在 Linux 上检测动态库卸载的“最佳”方法是:

  1. 创建您自己的共享库实现 dlclose() 并在 运行 可执行文件时 预加载 它。这是解释 here and here.

  2. 继续观看/proc/self/maps解析加载库列表。

  3. 运行 像gdb这样的调试器下的程序,可以scripted/automated using Python.


根据其他操作系统...Android 是基于 Linux 的,但它具有额外的安全功能并且应用程序是沙盒的,除非您对设备进行 root 或使用调试 shell 你不能只是“运行”其他应用程序与自定义 dlclose() 甚至调试器挂钩。关于 iOS 我不能说太多,但我怀疑考虑到应用程序的能力非常有限(也被沙盒化),实现这样的功能甚至不是一个选择。 AFAIK macOS 还支持手动 loading/unloading 库的 dlopen()/dlclose(),但是链接器与 Linux(上面链接)上常用的链接器不同,所以我可以'关于自动 loading/unloading 行为就不多说了。