我想拦截 dlopen() 内部发生的所有文件系统访问。起初,它看起来像 LD_PRELOAD
或 -Wl,-wrap,
将是可行的解决方案,但由于某些技术原因,我无法使其正常工作:
_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
时定义,但是如何保证只有一个静态数据结构的副本,同时仍然导出一个公共(public)接口(interface)函数呢? (这是一个 glibc 构建系统问题,但我还没有找到这些细节的文档。)有没有更好的方法进入
dlopen()
?注意:我不能使用像
FUSE
这样的 Linux 特定解决方案。因为这是针对不支持此类事物的最小“计算节点”内核。
最佳答案
it would seem like LD_PRELOAD or -Wl,-wrap, would be viable solutions
--wrap
解决方案不可能可行:它仅在(静态)链接时有效,并且您的 ld.so
和 libc.so.6
和 libdl.so.2
都已经链接,所以现在使用 --wrap
为时已晚。LD_PRELOAD
本来可以工作,除了 ... ld.so 认为 dlopen()
调用 open()
是一个内部实现细节。因此,它只是调用内部 __open
函数,绕过 PLT
,以及您插入 open
的能力。Somehow malloc circumvents the issue
这是因为
libc
支持实现自己的 malloc
的用户(例如用于调试目的)。所以调用例如来自 calloc
的 dlopen
确实经过 PLT
,并且可以通过 LD_PRELOAD
插入。This might all mean that I need to build my own ld.so directly from source instead of linking it into a wrapper.
重建后的
ld.so
会做什么?我认为您希望它调用 __libc_open
(在 libc.so.6
中),但是由于显而易见的原因,这不可能起作用:首先是 ld.so
open
s libc.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
链接。另一种选择:运行时修补。这有点小技巧,但是您可以(一旦获得主控制权)只需扫描
.text
的 ld.so
,然后查找 CALL __open
指令。如果 ld.so
没有被剥离,那么您可以找到内部 __open
和您要修补的功能(例如 open_verify
中的 dl-load.c
)。一旦你找到有趣的 CALL
, mprotect
包含它的页面是可写的,并修补你自己的插入器的地址(如果需要,它可以反过来调用 __libc_open
),然后 mprotect
它回来。任何 future 的 dlopen()
现在都将通过您的插入器。
关于glibc - 如何在 dlopen() 中拦截文件系统访问?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7699583/