【问题标题】:Is it possible to override C syscall open without LD_PRELOAD?是否可以在没有 LD_PRELOAD 的情况下覆盖打开的 C 系统调用?
【发布时间】:2021-11-28 17:53:27
【问题描述】:

源被打印,但没有open:open64: 被打印。如何解决这个问题?谢谢!

/*
gcc -o emload emload.c -ldl
./emload
*/

// emload.c

#define _GNU_SOURCE

#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <dlfcn.h>
#include <fcntl.h>
#include <stdarg.h>

typedef int   (*orig_open_func_type)(const char *__file, int flags, ...);
typedef int   (*orig_openat_func_type)(int dirfd, const char *__file, int flags, ...);


int open(const char *__file, int __oflag, ...)
{
    orig_open_func_type orig_func;
    orig_func = (orig_open_func_type)dlsym(RTLD_NEXT, "open");
    int res = 0;

    if (__oflag & O_CREAT) {
        va_list ap;
        va_start(ap, __oflag);
        int mode = va_arg(ap, unsigned);
        res = orig_func(__file, __oflag, mode);
        va_end(ap);
    }
    else
        res = orig_func(__file, __oflag);

    printf("open: %d (%s)\n", res, __file);
    return res;
}

int open64(const char *__file, int __oflag, ...)
{
    orig_open_func_type orig_func;
    orig_func = (orig_open_func_type)dlsym(RTLD_NEXT, "open64");
    int res = 0;

    if (__oflag & O_CREAT) {
        va_list ap;
        va_start(ap, __oflag);
        int mode = va_arg(ap, unsigned);
        res = orig_func(__file, __oflag, mode);
        va_end(ap);
    }
    else
        res = orig_func(__file, __oflag);

    printf("open64: %d (%s)\n", res, __file);
    return res;
}

int openat(int dirfd, const char *__file, int __oflag, ...)
{
    orig_openat_func_type orig_func = (orig_openat_func_type)dlsym(RTLD_NEXT, "openat");
    int res = 0;

    if (__oflag & O_CREAT) {
        va_list ap;
        va_start(ap, __oflag);
        int mode = va_arg(ap, unsigned);
        res = orig_func(dirfd, __file, __oflag, mode);
        va_end(ap);
    }
    else
        res = orig_func(dirfd, __file, __oflag);

    printf("openat: %d (%s)\n", res, __file);
    return res;
}

char source[2 << 20];

int main(int argc, char **argv, char **env)
{
    FILE* f = fopen("emload.c", "r");
    fread(source, sizeof(source), 1, f);
    puts(source);
    fclose(f);
    return 0;
}

【问题讨论】:

  • 它是否真的适用于LD_PRELOAD? glibc 似乎在内部文件打开函数中显式使用其内部__open,这被解析为__GI___libc_open。我认为即使使用 LD_PRELOAD 也无法覆盖它,因为它不是对 open 的调用。
  • 刚试了,还是不行 :( 用这个简单的技巧似乎不可能在系统调用级别覆盖 open :( 是不是只在最新版本的 glibc 中改变了?因为有很多展示这些覆盖的在线问题/回购 - 如果它甚至不适用于简单的fopen 用法,那么这些将毫无用处。

标签: c overriding system-calls libc ld-preload


【解决方案1】:

GLIBC 的fopen 直接调用系统调用包装器,没有任何地址解析,所以你在这里不走运。您的其他选择是:

  • 使用来自单独进程的ptrace(2),通过PTRACE_SYSCALL 请求跟踪系统调用。这将在 任何 系统调用上停止,而不仅仅是您需要的系统调用,因此可能会降低性能。
  • 修补内存中的包装以跳转到您的覆盖。但是,这可能会使执行原始代码变得更加困难,因为您需要分析它的前几条指令(您覆盖)以重现它们的效果。或者,您可以完全重新实现包装器,避免返回到原始版本。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-04-17
    • 1970-01-01
    • 1970-01-01
    • 2017-03-17
    • 2018-03-22
    • 1970-01-01
    • 2014-07-07
    相关资源
    最近更新 更多