代码之家  ›  专栏  ›  技术社区  ›  uli42

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

  •  0
  • uli42  · 技术社区  · 6 年前

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

    系统的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
    

    我还设法截获了

    所以我编写了一个小的共享库来拦截更改后的函数。不幸的是,这并没有成功,因为我的替换函数从未被调用过。作为测试,我添加了 fread fwrite 以同样的方式 那些 被叫来了。所以我的方法是有效的。

    更多细节: _IO_new_file_underflow 在glibc's iolib/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
    

    $ 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
    

    但这也不管用。

    在程序上运行ldd LD_DEBUG=all

    我现在想知道我是否遗漏了一些必要的东西,或者是否通常不可能实现对这两个函数的LD_PRELOAD替换。

    更新:增加了gdb体验,修复了输入错误

    0 回复  |  直到 6 年前
    推荐文章