用LD_PRELOAD覆盖execve()有时只能工作

时间:2016-06-19 20:50:05

标签: c linux

我想通过使用LD_PRELOAD来覆盖execve()系统调用,并且无法弄清楚为什么它有时会起作用,有时却不能。

考虑这个非常简单的代码覆盖execve()(我会保持完整,所以你可以尝试一下,如果你喜欢):

#define _GNU_SOURCE
#include <unistd.h>
#include <dlfcn.h>
typedef ssize_t (*execve_func_t)(const char* filename, char* const argv[], char* const envp[]);
static execve_func_t old_execve = NULL;
int execve(const char* filename, char* const argv[], char* const envp[]) {
    printf("Running hook\n");
    old_execve = dlsym(RTLD_NEXT, "execve");
    return old_execve(filename, argv, envp);
}

(编译:{{1​​}})

这个非常简单的测试程序:

gcc -std=c99 -o exec.so -shared exec.c -Wall -Wfatal-errors -fPIC -g -ldl

现在,当我在shell中执行#define _GNU_SOURCE #include <unistd.h> #include <dlfcn.h> int main() { char* args[] = {"ls", "/usr", NULL}; char* envp[] = {"LD_PRELOAD=/path/to/exec.so", NULL}; execve("/usr/bin/ls", args, envp); return 0; } 时,我希望我运行的任何二进制文件首先执行钩子。事实并非如此,这让我感到困惑:编辑:好的,这部分现在很清楚了。以下问题仍未解决。

export LD_PRELOAD=/path/to/exec.so

如您所见,钩子仅针对第二个exec运行,而不是针对第一个。

目前还不清楚: 然而,更让我感到困惑的是,在某些情况下,代码不会被预加载,甚至对于子进程也是如此;例如,当使用Python的子进程模块运行» strace -f -e trace=execve ./test execve("./test", ["./test"], [/* 58 vars */]) = 0 Running hook execve("/usr/bin/ls", ["ls", "/usr"], [/* 1 var */]) = 0 arm-none-eabi avr bin games include lib lib32 lib64 libexec local python sbin share src usr x86_64-pc-linux-gnu +++ exited with 0 +++ 时,会发生这种情况:

ls /usr

怎么可能?它与完全相同的系统调用具有完全相同的调用进程环境,但它做了不同的事情。关于这一点,我会很高兴。

1 个答案:

答案 0 :(得分:0)

好的,解决方案实际上很简单:Python调用execv,而不是execve;打印的标准输出由调用该过程的代码占用,而不是打印到终端。这就是为什么它似乎不起作用(虽然它确实如此)。