実行前のファイル記述子のリダイレクト

実行前のファイル記述子のリダイレクト

私はgdbのプロセスを中断し、ファイル記述子で閉じてから、必要なファイル名で再度開くことで、プログラムが書き込むファイルを変更できることを知っています。実行時に同じことを行う方法はありますか?

たとえば、私が変更したいファイルがファイル記述子5を使用していることを知っているので、

./myexe 5>/dev/null

しかし、いくつか変更するだけで、興味のあるファイルはfd = 6になります。

答え1

プログラムがファイルを開くと、そのファイルはその時点で使用可能なファイル記述子に保存されます。プログラムが起動する前にファイルを開くと、他のファイル記述子を使用するだけになるため、関心のあるファイルが別の記述子にある可能性があります。プログラムが別のファイルを開くようにするには、オープン操作中に修正するか、後に介入する必要があります。

タスクを修正する1つの方法は、プログラムとシステムライブラリの間にいくつかのコードを挿入することです。事前ロード小さなコードの断片。これは、プログラムが動的にリンクされたバイナリまたは動的にリンクされたバイナリによって実行されるスクリプトであると仮定します(つまり、静的にリンクされていません)。ファイルに次のコードを書きますoverride_fopen.c

#include <dlfcn.h>
#include <fcntl.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#ifndef FROM
#error "Define FROM to the path to override in double quotes, e.g. -DFROM='\"/bad\"'"
#endif
#ifndef TO
#error "Define TO to the path to use instead in double quotes, e.g. -DFROM='\"/good\"'"
#endif
FILE *fopen(const char *path, const char *mode) {
    void *(*original_fopen)(const char *, const char *) = dlsym(RTLD_NEXT, "fopen");
    if (!strcmp(path, FROM)) {
        path = TO;
    }
    return original_fopen(path, mode);
}
int open(const char *path, int oflag, ...) {
    int (*original_open)(const char *, int, ...) = dlsym(RTLD_NEXT, "open");
    int ret;
    va_list args;
    if (!strcmp(path, FROM)) {
        path = TO;
    }
    va_start(args, oflag);
    if (oflag & O_CREAT) {
        ret = original_open(path, oflag, (mode_t)va_arg(args, mode_t));
    } else {
        ret = original_open(path, oflag);
    }
    va_end(args);
    return ret;
}

次のコマンドを使用してコンパイルします(Linuxの場合、他のUnixバリアントには他のオプションが必要な場合があります)。上書きするパスの周りに引用符を書き留めます。

gcc -DFROM='"/some/path"' -DTO='"/dev/null"' -D_GNU_SOURCE -O -Wall -fPIC -shared -o override_fopen.so override_fopen.c -ldl

次のようにプログラムを実行します(OSXではDYLD_PRELOAD代わりに使用LD_PRELOAD)。

LD_PRELOAD=./override_fopen.so ./myexe

この方法は、プログラムが呼び出すfopenopenライブラリ関数を呼び出す場合にのみ機能します。別の関数を呼び出す場合は、その関数をオーバーライドする必要があります。あなたはそれを使用することができますltraceプログラムがどのライブラリを呼び出すかを確認してください。

関連情報