为什么LD_PRELOAD似乎不能用wc写入

我正在玩LD_PRELOAD拦截libc调用,似乎写入调用不被拦截与wc,虽然它似乎与猫一起工作。 下面显示了一个精简版的问题。

RedHat Linux 2.6.9-42.ELsmp

Makefile文件

writelib: gcc -Wall -rdynamic -fPIC -c write.c gcc -shared -Wl,-soname,libwrite.so -Wl,-export-dynamic -o libwrite.so write.o -ldl 

为write.c:

 #include <stdio.h> #include <string.h> #ifndef __USE_GNU #define __USE_GNU #define __USE_GNU_DEFINED #endif #include <dlfcn.h> #ifdef __USE_GNU_DEFINED #undef __USE_GNU #undef __USE_GNU_DEFINED #endif #include <unistd.h> #include <stdlib.h> static ssize_t (*libc_write)(int fd, const void *buf, size_t len); ssize_t write(int fd, const void *buf, size_t len) { static int already; ssize_t ret; if (!already) { if ((libc_write = dlsym(RTLD_NEXT, "write")) == NULL) { exit(1); } already = 1; } ret = (*libc_write)(fd,"LD_PRELOAD\n",11); return len; // not ret so cat doesn't take forever } 

输出:

 prompt: make gcc -Wall -rdynamic -fPIC -c write.c gcc -shared -Wl,-soname,libwrite.so -Wl,-export-dynamic -o libwrite.so write.o -ldl prompt: LD_PRELOAD=./libwrite.so /bin/cat write.c LD_PRELOAD prompt: LD_PRELOAD=./libwrite.so /usr/bin/wc write.c 32 70 572 write.c 

任何解释?

这是因为,当cat使用writewc使用printf ,这可能是使用内联版本的write ,或者其write引用绑定到libc ,因此不能插入。

这可以很容易地看到使用ltrace

 $ echo foo | ltrace wc 2>&1 | grep 'write\|print' printf("%*s", 7, "1") = 7 printf(" %*s", 7, "1") = 8 printf(" %*s", 7, "4") = 8 $ echo foo | ltrace cat 2>&1 | grep 'write\|print' write(1, "foo\n", 4foo 

LD_PRELOAD是一个非常糟糕的方法来拦截和重定向调用。 它只适用于共享库,根据库链接的方式以及使用的优化和内联的级别,您要拦截的调用可能无法可靠地被拦截。

避免所有这些问题的一个很好的选择是使用ptrace跟踪/调试接口,特别是当你想拦截和重写的系统调用时。 不幸的是,目前似乎还没有任何工具可以使这种方法自动化。