2011-07-01 48 views
9

我正在玩LD_PRELOAD來攔截libc調用,看起來寫入調用不會被wc攔截,儘管它似乎與cat一起工作。下面顯示了一個精簡版的問題。爲什麼LD_PRELOAD似乎不能用於寫入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 

任何解釋嗎?

回答

7

這是因爲,雖然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 
+0

另請參閱:http://stackoverflow.com/questions/6538501/linking-two-shared-libraries-with-some-of-the-same-symbols/6540059#6540059如何將符號綁定到內部拷貝庫。 – ninjalj

+0

感謝ltrace的指針。我將libc寫入調用與在wc命令上運行strace時出現的系統寫入調用混淆了。 –

1

LD_PRELOAD是真的攔截並重定向調用一個非常貧困的方法。它只適用於共享庫,並根據庫的鏈接方式以及使用的優化級別和內聯級別,您要攔截的呼叫可能無法可靠地攔截。

避免所有這些問題的一個很好的選擇是,使用ptrace跟蹤/調試接口,尤其是當您想攔截和重寫系統調用時。不幸的是,目前似乎沒有任何工具可以自動化這種方法。

相關問題