7

我想拦截 dlopen() 内部发生的所有文件系统访问。起初,这似乎是LD_PRELOAD-Wl,-wrap,将是可行的解决方案,但由于一些技术原因,我无法让它们工作:

  • ld.so 在处理 LD_PRELOAD 时已经映射了它自己的符号。拦截初始加载对我来说并不重要,但此时_dl_*工作函数已解决,因此未来的调用会通过它们。我认为LD_PRELOAD为时已晚。

  • 不知何故malloc绕过了上面的问题,因为malloc()ld.so 内部没有函数free(),它只是调用memset().

  • 文件系统工作函数,例如__libc_read(),包含在ld.so其中是静态的,所以我不能用-Wl,-wrap,__libc_read.

这可能都意味着我需要ld.so直接从源代码构建自己的,而不是将其链接到包装器中。那里的挑战是两者libc都是rtld-libc从同一来源构建的。我知道宏IS_IN_rtld是在构建时定义的rtld-libc,但是如何保证只有一个静态数据结构的副本,同时仍然导出公共接口函数?(这是一个 glibc 构建系统问题,但我还没有找到这些细节的文档。)

有没有更好的进入方法dlopen()

注意:我不能使用特定于 Linux 的解决方案,FUSE因为这是针对不支持此类东西的最小“计算节点”内核。

4

1 回答 1

5

看起来 LD_PRELOAD 或 -Wl,-wrap 将是可行的解决方案

--wrap解决方案不可能可行:它仅在(静态)链接时有效,并且您的ld.soandlibc.so.6libdl.so.2都已经链接,所以现在使用--wrap.

除了 ... ld.so 考虑调用内部实现细节LD_PRELOAD的事实之外,本可以工作。因此,它只是调用内部函数, bypassing和你干预它的能力。dlopen()open()__openPLTopen

malloc 以某种方式规避了这个问题

那是因为libc支持实现自己的用户malloc(例如出于调试目的)。所以对 eg callocfrom的调用dlopen确实通过了PLT,并且可以通过 via 插入LD_PRELOAD

这可能都意味着我需要直接从源代码构建自己的 ld.so,而不是将其链接到包装器中。

重建ld.so会做什么?我认为您希望它调用__libc_open(in libc.so.6),但由于显而易见的原因,这不可能起作用:首先是ld.sos openlibc.so.6在进程启动时)。

ld.so您可以将调用__open替换为调用来重建open。这将导致ld.so通过PLT,并将其暴露于LD_PRELOAD干预。

如果你走那条路,我建议你不要ld.so用你的新副本覆盖系统(出错并导致系统无法启动的机会太大了)。相反,将其安装到例如/usr/local/my-ld.so,然后将您的二进制文件与-Wl,--dynamic-linker=/usr/local/my-ld.so.

另一种选择:运行时修补。这有点小技巧,但是您可以(一旦您在 main 中获得控制权)只需扫描.textofld.so并查找CALL __open说明。如果ld.so没有被剥离,那么您可以同时找到 internal__open和要修补的函数(例如open_verifyin dl-load.c)。一旦你找到了有趣的CALL,包含它的页面是可写的,并在你自己的 interposer 的地址中打补丁(如果需要,mprotect它可以反过来调用),然后返回。现在,任何未来都将通过您的插入器。__libc_openmprotectdlopen()

于 2011-10-17T05:11:49.293 回答