Linux 有没有办法拦截内部glibc呼叫?

Linux 有没有办法拦截内部glibc呼叫?,linux,glibc,ld-preload,Linux,Glibc,Ld Preload,我正在尝试使用一个旧程序(其中只有二进制文件可用),它只是在Debian Buster上的IO上卡住,而在使用较旧的glibc版本的系统上工作。有人发现问题与通过引入的glibc修复程序有关 我已经成功地编译了一个带有注释的修复程序的glibc,并且使用该glibc运行程序使其工作正常 系统的glibc显示了上述修复程序更改的两个功能,因此我假设它们可以由自己的功能替换,从而有效地撤消修复程序: $ readelf -a /lib/x86_64-linux-gnu/libc.so.6 | gre

我正在尝试使用一个旧程序(其中只有二进制文件可用),它只是在Debian Buster上的IO上卡住,而在使用较旧的glibc版本的系统上工作。有人发现问题与通过引入的glibc修复程序有关

我已经成功地编译了一个带有注释的修复程序的glibc,并且使用该glibc运行程序使其工作正常

系统的glibc显示了上述修复程序更改的两个功能,因此我假设它们可以由自己的功能替换,从而有效地撤消修复程序:

$ readelf -a /lib/x86_64-linux-gnu/libc.so.6 | grep underflow
  1544: 000000000007ed60    86 FUNC    GLOBAL DEFAULT   13 _IO_str_underflow@@GLIBC_2.2.5
  1597: 0000000000074550   346 FUNC    GLOBAL DEFAULT   13 __wunderflow@@GLIBC_2.2.5
  1604: 00000000000753d0  1603 FUNC    GLOBAL DEFAULT   13 _IO_wfile_underflow@@GLIBC_2.2.5
  2152: 000000000007c520   705 FUNC    GLOBAL DEFAULT   13 _IO_file_underflow@@GLIBC_2.2.5
  2216: 000000000007d420   258 FUNC    GLOBAL DEFAULT   13 __underflow@@GLIBC_2.2.5
我还设法用 gdb

因此,我编写了一个小型共享库,用于拦截更改后的函数。不幸的是,这不起作用,因为我的替换函数从未被调用。作为一项测试,我添加了
fread
fwrite
的再植体,以相同的方式调用它们。所以我的一般方法是有效的

更多详情: -修复程序更改了glibc的
iolib/fileops.c
中的
\u IO\u new\u file\u underflow
iolib/oldfileops.c
中的
\u IO\u old\u file\u underflow
两个功能 -我编写了两个替换函数,可以撤消修复,然后调用原始函数:

int
_IO_new_file_underflow (FILE *fp)
{
  int (*next)(FILE *fp) = dlsym(RTLD_NEXT, "_IO_new_file_underflow");

  fprintf(stderr, "%s: called\n", __func__);

  if (fp->_flags & _IO_EOF_SEEN)
    fp->_flags &= ~_IO_EOF_SEEN;

  return next(fp);
}

int
_IO_old_file_underflow (FILE *fp)
{
  int (*next)(FILE *fp) = dlsym(RTLD_NEXT, "_IO_old_file_underflow");

  fprintf(stderr, "%s: called\n", __func__);

  if (fp->_flags & _IO_EOF_SEEN)
    fp->_flags &= ~_IO_EOF_SEEN;

  return next(fp);
}
  • 用gcc-ox.so-shared x.c-ldl-fPIC编译
  • 使用
    LD_PRELOAD=/path/to/x运行有故障的程序。因此faultyprogram
  • 结果:从未调用替换函数,程序失败
  • 这些符号位于.so文件中:
与系统glibc的上述输出不同,我的版本缺少符号,因此我还通过链接器版本脚本添加了符号:

$ cat version
VERSION {
GLIBC_2.2.5 {
         global: *;
};

$ gcc -o x.so -shared x.c -ldl -fPIC version
$ readelf -a x.so | grep underflow
     8: 0000000000001115   117 FUNC    GLOBAL DEFAULT   13 _IO_new_file_underflow@@GLIBC_2.2.5
     9: 000000000000118a   117 FUNC    GLOBAL DEFAULT   13 _IO_old_file_underflow@@GLIBC_2.2.5
    48: 0000000000001115   117 FUNC    GLOBAL DEFAULT   13 _IO_new_file_underflow
    51: 000000000000118a   117 FUNC    GLOBAL DEFAULT   13 _IO_old_file_underflow
但这也行不通

使用
LD_DEBUG=all
在程序上运行ldd时,我可以看到许多符号,但链接器没有解决这两个问题。我猜这是因为它们在glibc中被视为某种私有函数。但是如果这是真的,为什么这些符号在libc.so.6中是可见的呢

我现在想知道我是否遗漏了一些重要的东西,或者是否通常不可能为这两个功能实现LD_预加载替换


更新:添加了gdb体验,修复了打字错误:也许你应该在用旧gcc构建的Docker容器中运行这个程序。如果你只是使用
objcopy
删除或重命名glibc中的那些符号会发生什么。如果他们不在那里,就不能叫他们。因此,要么你得到一个链接器错误(这将告诉你为什么找不到替换符号),要么你的替换符号将被调用。输出文件与输入文件相同。“系统的glibc…”——它来自哪个“系统”?Debian Buster还是其他什么?在AICT上,Debian Buster使用GLIBC-2.28,函数被标记为私有,并在更早的时候停止导出(我有2.15,函数在那里已经是私有的)。@DanielJunglas
obcopy
无法轻松修改完全链接的ELF二进制文件:
$ cat version
VERSION {
GLIBC_2.2.5 {
         global: *;
};

$ gcc -o x.so -shared x.c -ldl -fPIC version
$ readelf -a x.so | grep underflow
     8: 0000000000001115   117 FUNC    GLOBAL DEFAULT   13 _IO_new_file_underflow@@GLIBC_2.2.5
     9: 000000000000118a   117 FUNC    GLOBAL DEFAULT   13 _IO_old_file_underflow@@GLIBC_2.2.5
    48: 0000000000001115   117 FUNC    GLOBAL DEFAULT   13 _IO_new_file_underflow
    51: 000000000000118a   117 FUNC    GLOBAL DEFAULT   13 _IO_old_file_underflow