web-dev-qa-db-ja.com

プログラムを実行し、syscallを傍受してリダイレクトします

プログラムを実行したいのですが、そのプログラムが特定のファイルを読み取ろうとしたときに、代わりに選択した別のファイルを読み取ってもらいたいのです。

具体的には、プログラムは構成ファイルを読み取ろうとしますが、設計が不十分であり、ユーザーが構成ファイルの場所を指定することはできません。また、プログラムが読み取ろうとしている場所でファイルを編集する権限もありません。

straceを使用してプログラムによって作成されたシステムコールをdetectできることはわかっています。また、プログラムの下で実行すると、プログラムによって作成された唯一のopen()システムコールを確認できます。 straceinterceptそのsyscallを実行し、選択した別のファイルを開くように動作を変更する方法はありますか?

1
Drew

_LD_PRELOAD_はLinuxでこれを行うことができます。最初にアプリケーションを変更して、_app.c_

_#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>

int main(int argc, char *argv[])
{
    char c;
    int fd;
    fd = open(*++argv, O_RDONLY);
    read(fd, &c, 1);
    printf("%c\n", c);
    return 0;
}
_

これは、ファイルから文字を読み取るのに役立ちます。

_$ make app
cc     app.c   -o app
$ echo a > a
$ echo b > b
$ ./app a ; ./app b
a
b
_

これを変更するには、open、_fakeopen.c_を偽造するライブラリが必要です。

_#define _GNU_SOURCE
#include <dlfcn.h>
#include <fcntl.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>

typedef int (*orig_open) (const char *path, int oflag, ...);

int open(const char *path, int oflag, ...)
{
    orig_open fn;
    mode_t cmode = 0;
    va_list ap;
    if ((oflag & O_CREAT) == O_CREAT) {
        va_start(ap, oflag);
        cmode = (mode_t) va_arg(ap, int);
        va_end(ap);
    }
    if (strncmp(path, "a", 2) == 0)
        path = getenv("FAKE");
    fn = (orig_open) dlsym(RTLD_NEXT, "open");
    return fn(path, oflag, cmode);
}
_

これは、_LD_PRELOAD_を介してコンパイルおよび使用され、ファイル名が私たちが探しているものであり、FAKEがパスであると仮定した場合:

_$ cat Makefile
fakeopen.so: fakeopen.c
    $(CC) $(CFLAGS) -shared -fPIC -ldl fakeopen.c -o fakeopen.so
$ rm fakeopen.so
$ cat Makefile
fakeopen.so: fakeopen.c
    $(CC) $(CFLAGS) -shared -fPIC -ldl fakeopen.c -o fakeopen.so
$ make fakeopen.so
cc  -shared -fPIC -ldl fakeopen.c -o fakeopen.so
$ FAKE=b LD_PRELOAD=`pwd`/fakeopen.so ./app a
b
_

代わりにファイルbを読み取るように_./app a_を作成できます。もちろん、踏む可能性のあるエラーチェックやその他のレーキを増やす必要がありますが、これはopen(2)呼び出しを変更するための要点です。

4
thrig