如何拦截dlopen()中的文件系统访问?

时间:2011-10-08 20:29:14

标签: glibc dlopen

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

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

  • 不知怎的malloc绕过了上面的问题,因为ld.so中的malloc()没有功能free(),它只是调用memset()

  • 文件系统工作者的功能,例如__libc_read()中包含的ld.so是静态的,因此我无法使用-Wl,-wrap,__libc_read拦截它们。

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

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

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

1 个答案:

答案 0 :(得分:3)

  

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

--wrap解决方案可能不可行:它仅在(静态)链接时有效,而您的ld.solibc.so.6以及libdl.so.2都已链接,现在使用--wrap为时已晚。

LD_PRELOAD可能有效,除了...... ld.so认为dlopen()调用open()内部实现细节。因此,它只是调用内部__open函数,绕过PLT,并且可以使用open来插入libc

  

不知何故,malloc规避了问题

这是因为malloc支持实现自己calloc的用户(例如用于调试目的)。所以打电话给例如来自dlopen的{​​{1}}确实通过PLT,并通过LD_PRELOAD进行插入。

  

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

重建ld.so会做什么?我希望您能够拨打__llibc_openlibc.so.6),但由于显而易见的原因,这可能无法发挥作用:ld.so open 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的{​​{1}},并查找__open指令。如果open_verify未被删除,则您可以找到内部dl-load.c和要修补的功能(例如CALL中的mprotect)。一旦找到有趣的__libc_openmprotect包含它的页面是可写的,并修补您自己的插入器的地址(如果需要,可以调用dlopen()) ,然后{{1}}回来。任何未来{{1}}现在都将通过您的插入器。