我想通过使用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
怎么可能?它与完全相同的系统调用具有完全相同的调用进程环境,但它做了不同的事情。关于这一点,我会很高兴。
答案 0 :(得分:0)
好的,解决方案实际上很简单:Python调用execv,而不是execve;打印的标准输出由调用该过程的代码占用,而不是打印到终端。这就是为什么它似乎不起作用(虽然它确实如此)。