2

open()在 Linux(在我的情况下为 Debian)上拦截时遇到了麻烦。这是一个内置到共享对象中的简约 C 源代码:

/* Defines are needed for dlfcn.h (RTLD_NEXT) */
#define __USE_GNU
#define _GNU_SOURCE

#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>
#include <unistd.h>

int open(char const *path, int oflag, ...) {
    int (*real_open)(char const *, int, ...);
    char *msg;
    va_list args;
    int mflag;

    fprintf(stderr, ">>>>> in open <<<<<<\n");
    real_open = dlsym(RTLD_NEXT, "open");
    if ( (msg = dlerror()) ) {
        fprintf(stderr, "dlsym error: %s\n", msg);
        exit(1);
    }
    va_start(args, oflag);
    mflag = va_arg(args, int);
    return real_open(path, oflag, mflag);
}

ssize_t read(int fd, void *buf, size_t count) {
    ssize_t (*real_read)(int, void*, size_t);
    char *msg;

    fprintf(stderr, ">>>>> in read <<<<<\n");
    real_read = dlsym(RTLD_NEXT, "read");
    if ( (msg = dlerror()) ) {
        fprintf(stderr, "dlsym error: %s\n", msg);
        exit(1);
    }
    return real_read(fd, buf, count);
}

共享对象是使用以下方法构建的:

cc -c -fPIC -Wall funcs.c
cc -shared -o libfuncs.so funcs.o -ldl -lc

现在当我尝试

export LD_PRELOAD=/path/to/libfuncs.so
cat somefile

然后我只在输出中看到它的踪迹read()>>>>> in read <<<<<. 我从来没有看到过一丝open()。我检查了cat Makefile使用的内容strace,果然 - 两者open()read()被称为:

open("Makefile", O_RDONLY|O_LARGEFILE)  = 3
fstat64(3, {st_mode=S_IFREG|0644, st_size=213, ...}) = 0
read(3, "testrun: libfuncs.so\n\tLD_PRELOAD"..., 32768) = 213

顺便说一句,我还检查了其他程序,例如odor bash,从来没有拦截过open()。这里发生了什么?提前致谢...

`

4

2 回答 2

3

为了添加到 shooper 的答案中,glibc 似乎在编译调用例如的应用程序时执行了程序集级重命名 from open()toopen64()open()

$ gcc -D_FILE_OFFSET_BITS=64 open.c -o open

添加-S到上述命令并检查确实被调用的open.s节目中的程序集源。表明它不仅仅是基于预处理器的重命名。open64()$ gcc -E ...

预处理的源代码有这个位,它执行重命名:

extern int open (const char *__file, int __oflag, ...) __asm__ ("" "open64")
     __attribute__ ((__nonnull__ (1)));

负责生成该声明的代码位于/usr/include/fcntl.h中:

#ifndef __USE_FILE_OFFSET64
extern int open (const char *__file, int __oflag, ...) __nonnull ((1));
#else
# ifdef __REDIRECT
extern int __REDIRECT (open, (const char *__file, int __oflag, ...), open64)
     __nonnull ((1));
# else
#  define open open64
# endif
#endif
#ifdef __USE_LARGEFILE64
extern int open64 (const char *__file, int __oflag, ...) __nonnull ((1));
#endif

带有 的声明__REDIRECT就是这里使用的。

如果这是真正的问题,我的猜测是 glibc 反过来将open64()调用转换为open("Makefile", O_RDONLY|O_LARGEFILE)您在strace. 由于您只能覆盖函数而不是系统调用本身,因此您应该尝试open64()像 shopper 建议的那样。

(我不确定为什么 glibc 会这样做,如果它是出于其他原因,而不仅仅是为了避免使用宏。)

于 2015-03-18T18:53:16.343 回答
2

也许尝试“open64”而不是“open”?

于 2015-03-18T18:15:49.207 回答