为什么我不能用LD_PRELOAD拦截bash中的write(2)?

时间:2013-10-26 10:55:46

标签: c linux shared-libraries


好的,我明白了。当libc函数被另一个libc函数调用时,你不能用LD_PRELOAD覆盖它。


我正在玩Dante socksifier,并注意到它不能与bash / dev / udp FD一起使用。然后我用write函数编写了一个简单的.so文件,它也不能与bash一起使用:
libtest.c

#include <unistd.h>
ssize_t write(int fildes, const void *buf, size_t nbyte)
{
  return nbyte;
}

test.c

#include <unistd.h>
int main(int argc, char *argv[]) {
  write(1,"abc\n",4);
  return 0;
}

_

$ gcc -g -O0 -fPIC -shared -o libtest.so libtest.c
$ gcc -g -O0 -o test test.c
$ ./test
abc
$ LD_PRELOAD=./libtest.so ./test
$ LD_PRELOAD=./libtest.so bash -c 'echo abc'
abc

upd:根据ensc,它与符号版本有关。

链接./test需要更改什么才能像bash那样失败?我的意思是,使用相同的.so文件命令:$ LD_PRELOAD=./libtest.so ./test将打印“abc”,因为test将绑定到glibc中的版本化write

我也在尝试相反的方法 - 使用版本化的write创建一个.so文件。 version.script

GLIBC_2.2.5 {
    write;
};

但我的图书馆仍无法拦截bash中的write

$ gcc -g -O0 -fPIC -shared -Wl,--version-script=./version.script -o libtest.so libtest.c
$ LD_PRELOAD=./libtest.so bash -c 'echo abc'
abc

1 个答案:

答案 0 :(得分:5)

当您查看使用过的符号时,您可能会看到版本化符号用于write

$ readelf -a test | grep write
48: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND write@@GLIBC_2.2.5

您必须编写带有VERSION部分的链接描述文件(info ld - &gt;“版本命令”)。

你的情况(操纵bash行为)更复杂,因为bash调用printf(3),而printf(3)又使用了libc的一些内部函数。当你运气好并且调用弱内部函数时(afais,只有'__write'),你可以在库中重载它。

否则,你必须覆盖bash调用的printf();你可以用'ltrace'找到它; e.g:

$ ltrace  bash -c 'echo abc'
__printf_chk(1, "%s", "abc")                                  = 3
_IO_putc('\n', 0x7fc5eeac3420abc

或通过设置LD_DEBUG( - &gt; man ld.so)