2011-07-01 11 views
9

libcコールを傍受するためにLD_PRELOADで遊んでいましたが、write呼び出しが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 

どれ説明? catwriteを使用しながらためだ

答えて

7

wcおそらくlibcに結合されているインラインwriteのバージョン、またはwriteへの参照のいずれかを使用しているprintfを使用するため、介在することはできません。

これは簡単に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へのポインタをありがとう。私はwcコマンドでstraceを実行したときに表示されていたシステム書き込み呼び出しとlibc書き込み呼び出しを混同していました。 –

1

LD_PRELOADは本当に呼び出しをインターセプトし、リダイレクトするための非常に悪い方法です。共有ライブラリのみで動作し、ライブラリのリンク方法や最適化とインライン化のレベルによって、インターセプトしたい呼び出しが確実にインターセプトできないことがあります。

これらの問題をすべて回避する優れた方法は、特に傍受して書き換えたいシステムコールの場合は、ptraceトレース/デバッグインターフェイスを使用することです。残念ながら、現時点でこのアプローチを自動化するツールはないようです。

関連する問題