linux 为什么LD_PRELOAD技巧在被fopen()调用时不捕获open()?

pcrecxhr  于 12个月前  发布在  Linux
关注(0)|答案(3)|浏览(186)

我使用LD_PRELOAD技巧来捕获open64()调用,我想我知道如何正确地做到这一点:使用从

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

int main() {
  open64("foobar.txt", 0);
  return 0;
}

字符串
我得到了open64,正如我所期望的:

>LD_PRELOAD=$PWD/catch.so ./foobar
open64 called


但是,当open64替换为fopen64时:

#include <stdio.h>

int main() {
  fopen64("foobar.txt", "r");
  return 0;
}


现在open64没有被捕获。为什么?
如果fopen64调用open,我确实拦截了openopen64,但没有捕获到。
两个版本的foobar程序,当与strace一起执行时,显示open被调用,这意味着fopen64确实在内部调用openopen64
我想也许有些东西是静态链接的,但似乎不是这样:

>ldd foobar


示出

libc.so.6 => /lib64/libc.so.6


这是一个共享库,

>nm /lib64/libc.so.6


显示了open64fopen64的定义(但不是fopen,这就是为什么在问题中,我使用“64”版本作为参数;也许fopenfopen64的宏或类似的东西,没有关系,因为问题发生在64或没有64的情况下)。

pftdvrlh

pftdvrlh1#

我认为它是这样工作的:用户空间程序调用libc中的库函数,libc调用内核中的系统调用。使用LD_PRELOAD可以拦截程序和libc之间的libc调用。你不能拦截系统调用。如果glibc内部调用另一个函数(例如fopen调用open),你不能拦截它。
在这种情况下,最好使用ltrace而不是strace,因为它显示了哪些库调用已经完成。这些是您可以拦截的调用。


的数据

qzlgjiam

qzlgjiam2#

你需要ptracePTRACE_SYSCALL,这是一个blog on it

rjzwgtxy

rjzwgtxy3#

我最近遇到了一个类似的问题,我认为答案可以归结为glibc的实现。
以下是所有AFAICT从看glibc-2.37源代码,并不被视为福音。
fopen()和fopen 64()最终调用内部函数__open()(或者,不太可能,__open_nocancel())(可能使用O_LARGEFILE),而不是open()或open 64()。这些低级函数执行内联系统调用,而不是调用open()系统调用 Package 器(您使用LD_PRELOAD覆盖)。
你可能会说,“好吧,让我们用LD_PRELOAD覆盖__open(),然后到此为止”。这是可行的,除了glibc还用__attribute__标记__open()和__open_nocancel()。((visibility(“hidden”)。这会导致这些符号对LD_PRELOAD不可见,因此尽管您可以定义自己版本的__open(),对原始__open()的调用将不会被正确拦截。
我看了Bionic(Android libc)的源代码进行比较,虽然我认为你可以像你想的那样拦截open(),但我认为你会在fclose()端遇到问题(因为它最终调用_close(),这是隐藏的,而不是close())。

相关问题