【发布时间】:2013-10-26 10:55:46
【问题描述】:
好的,我明白了。当另一个 libc 函数调用它时,您不能用 LD_PRELOAD 覆盖一个 libc 函数。
我在玩 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
【问题讨论】:
-
write(2)在第 2 节中为syscalls(2) - 没有write(3);顺便说一句,一些聪明的程序可能会做一个直接的系统调用 -e.g.使用syscall(2) 或SYSENTER机器指令,甚至不使用瘦write(2)包装器。那你需要ptrace(2) -
@BasileStarynkevitch 顺便说一句,C 函数
write()的签名不是模仿 1:1 的write系统调用吗? -
或多或少是的,但是原始系统调用(通过
SYSENTER)获取其参数的方式不同(通过寄存器)并且给出的错误代码完全不同。我的观点是LD_PRELOAD解决方案不是防弹的。
标签: c linux shared-libraries