有没有办法拦截内部glibc调用?

时间:2020-01-26 23:44:59

标签: linux glibc ld-preload

我正在尝试使用一个旧程序(其中只有二进制文件可用),而在使用旧版本glibc的系统上工作时,该程序只会卡在Debian Buster的IO上。有人发现问题与通过https://sourceware.org/bugzilla/show_bug.cgi?id=1190

引入的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。

因此,我写了一个小的共享库来拦截已更改的功能。不幸的是,由于我的替换函数从未调用过,因此无法解决。作为测试,我以相同的方式为freadfwrite添加了替换,并调用了那些。所以我的一般方法是有效的。

更多详细信息: -该修复程序更改了glibc的_IO_new_file_underflowiolib/fileops.c中的_IO_old_file_underflow中的两个功能iolib/oldfileops.c -我编写了两个替换函数,它们撤消了修复程序,然后调用原始函数:

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 -o x.so -shared x.c -ldl -fPIC
  • 进行编译
  • 使用LD_PRELOAD=/path/to/x.so faultyprogram
  • 运行错误的程序
  • 结果:从不调用替换函数,程序失败。
  • 这些符号位于.so文件中:
$ readelf -a x.so | grep underflow
     8: 000000000000118a   117 FUNC    GLOBAL DEFAULT   12 _IO_old_file_underflow
     9: 0000000000001115   117 FUNC    GLOBAL DEFAULT   12 _IO_new_file_underflow
    47: 0000000000001115   117 FUNC    GLOBAL DEFAULT   12 _IO_new_file_underflow
    50: 000000000000118a   117 FUNC    GLOBAL DEFAULT   12 _IO_old_file_underflow

与以上来自系统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_PRELOAD替换。

更新:增加了gdb体验,修正了错字

0 个答案:

没有答案