Linux 有没有办法拦截内部glibc呼叫?
我正在尝试使用一个旧程序(其中只有二进制文件可用),它只是在Debian Buster上的IO上卡住,而在使用较旧的glibc版本的系统上工作。有人发现问题与通过引入的glibc修复程序有关 我已经成功地编译了一个带有注释的修复程序的glibc,并且使用该glibc运行程序使其工作正常 系统的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
$ 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文件中:
$ 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,函数在那里已经是私有的)。@DanielJunglasobcopy
无法轻松修改完全链接的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