我的目标是在位于特定路径的特定进程组中挂接多个 glibc 函数。有多种方法可以这样做(gdb、strace 等)。但我需要它在最早阶段自动可靠地完成,这样我就不会错过任何一个电话。所以我决定使用 LD_PRELOAD
方法。而且我需要它在没有任何用户干预的情况下自动完成,因此将 LD_PRELOAD
注入(inject)环境有点脆弱,可能会被用户覆盖。所以我决定在 /etc/ld.so.preload
中指定我的库 - 这很好用。
在我的库 ctor 代码中,我检查我所在的进程是否是我需要的进程并进行必要的 Hook ,否则它是空操作,库只是一个自重。
__attribute__((constructor)) void my_lib_ctor()
{
if (is_relevant_process())
{
do_the_wiring();
}
}
该库不导出任何符号,默认情况下隐藏其中的所有内容(-fvisibility=hidden
编译器标志),因此任何进程对我的库没有任何真正的依赖性。因此,如果注入(inject)到不相关的进程中,它可以安全地卸载。
更新过程需要卸载 - 如果要更新库,则不应将其加载到长时间运行的进程中 - 否则它们会在库替换时崩溃(这是预期的)。感兴趣的进程是短暂的并且由用户启动,因此对它们的影响可以忽略不计。
问题是 - 我不知道如何安全地卸载它。我在考虑 dlclose
,但是从库本身调用它会导致它从调用返回到已经卸载的库代码。
如果有其他方法自动且可靠地在早期阶段(在应用程序的 main()
执行之前) Hook glibc 调用,而不触及感兴趣的应用程序本身,如果你让我知道它们,我会很高兴(操作系统配置的轻微修改,例如预加载,是可以的)。谢谢!
最佳答案
我觉得你有一些误解,你问的就是没有意义:
Inside my library ctor code, I check if the process I'm in is the one I need and do necessary hooking, otherwise it's a no-op and library is just a dead weight.
卸载它的工作,而不是让它无所事事,它更多重量。
Unload is required for update procedure - if library is to be updated, it shouldn't be loaded into long-running processes - otherwise they will crash on library replacement (which is expected).
只有当您错误地覆盖库文件而不是替换文件时才会发生这种情况。后者可以通过将临时文件安装到同一目录并以旧文件为目标执行 rename
功能(相当于 mv
命令)来执行。
And if there are other methods for automatically and reliably hooking glibc calls on the early stage
您对“可靠”的关注听起来可疑地接近想要使用此机制以潜在恶意应用程序无法绕过的方式实现策略/访问控制。这在图书馆层面根本不可能。您需要在某种真正的沙箱中运行它们才能实现这一点(例如,通过将文件替换为在适当的沙箱中调用它们的包装脚本)。
关于c++ - 自行卸载的 Linux 共享库,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56149540/