【问题标题】:Why does LD_PRELOAD not seem to work for write with wc为什么 LD_PRELOAD 似乎不适用于 wc 写入
【发布时间】:2011-09-27 00:48:09
【问题描述】:

我正在使用 LD_PRELOAD 来拦截 libc 调用,看起来 write 调用没有被 wc 拦截,尽管它似乎可以与 cat 一起使用。问题的简化版本如下所示。

RedHat Linux 2.6.9-42.ELsmp

生成文件

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

写.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

有什么解释吗?

【问题讨论】:

    标签: c linux linker ld


    【解决方案1】:

    这是因为 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
    

    【讨论】:

    • 另请参阅:stackoverflow.com/questions/6538501/…,了解如何将符号绑定到库中的内部副本。
    • 感谢指向 ltrace 的指针。当我在 wc 命令上运行 strace 时,我将 libc 写入调用与系统写入调用混淆了。
    【解决方案2】:

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

    使用ptrace 跟踪/调试接口可以避免所有这些问题,尤其是在您想要拦截和重写系统调用时。不幸的是,目前似乎没有任何工具可以自动化这种方法。

    【讨论】:

      猜你喜欢
      • 2011-02-03
      • 2010-12-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-02-10
      • 2017-04-24
      • 1970-01-01
      • 2020-04-12
      相关资源
      最近更新 更多