为了解决这个问题,我们假设/path/to/file
文件系统中有一个文件 ( ),其内容如下:
$> cat /path/to/file
this is the content of the
file /path/to/file
我对几乎所有正在运行的进程(并且具有对此文件的读取访问权限)以及阅读此内容感到满意。
然而应该有(这是问题的核心)是一个特定的进程,在读取时应/path/to/file
提供不同的文件内容。
$> cat /path/to/file
this is the DIFFERNT content of the
file /path/to/file
如何以某种方式欺骗特定进程的文件内容?
我的一些猜测,采取哪条路将是与以下相关的解决方案:
- 符号链接技巧
- (linux)命名空间(文件系统命名空间)技巧
chroot
诡计$LD_PRELOAD
挂钩技巧- 覆盖文件系统
我的平台是 GNU/linux,但如果有 POSIX 方式来实现那就更好了:)
更新
什么是好的解决方案/答案?
一个好的解决方案/答案的标准是,可以实现“特定进程的不同文件内容”,而不需要根用户的交互,即使理想情况下,欺骗文件一开始就不应该是用户可写的。
另一个好的标准是对进程显示的文件进程的修改是特定的,并且最好没有竞争条件。
背景
Mozilla firefox 使用 2 个 zip 档案/usr/lib/firefox/omni.ja
和/usr/lib/firefox/browser/omni.ja
,其中包含大量的 firefox 代码(主要是用 Javascript 编写的内容),通过欺骗该文件,我将能够修改我的 firefox 版本(包括一些我无法再实现为扩展,提供了放弃的 XPCOM 支持并且不喜欢 addon-siging 强制)
答案1
是的,挂载命名空间是一种方法:
$ cat file
foo
$ cat other-file
bar
$ sudo unshare -m zsh -c 'mount --bind other-file file; USERNAME=$SUDO_USER; cat file'
bar
$ cat file
foo
以上用于zsh
恢复被劫持的 cat 命令的原始用户的 uid/gids。
答案2
这是一种方法预加载通过一小段代码在程序和系统库之间插入一些代码。这假设该程序是动态链接的二进制文件,或者是由动态链接的二进制文件执行的脚本(即它不是静态链接的)。将以下代码写入文件override_fopen.c
:
#include <dlfcn.h>
#include <fcntl.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#ifndef FROM
#error "Define FROM to the path to override in double quotes, e.g. -DFROM='\"/bad\"'"
#endif
#ifndef TO
#error "Define TO to the path to use instead in double quotes, e.g. -DFROM='\"/good\"'"
#endif
FILE *fopen(const char *path, const char *mode) {
void *(*original_fopen)(const char *, const char *) = dlsym(RTLD_NEXT, "fopen");
if (!strcmp(path, FROM)) {
path = TO;
}
return original_fopen(path, mode);
}
int open(const char *path, int oflag, ...) {
int (*original_open)(const char *, int, ...) = dlsym(RTLD_NEXT, "open");
int ret;
va_list args;
if (!strcmp(path, FROM)) {
path = TO;
}
va_start(args, oflag);
if (oflag & O_CREAT) {
ret = original_open(path, oflag, (mode_t)va_arg(args, mode_t));
} else {
ret = original_open(path, oflag);
}
va_end(args);
return ret;
}
使用以下命令进行编译(适用于 Linux,其他 Unix 变体可能需要不同的选项)。请注意要覆盖的路径周围的引号。
gcc -DFROM='"/path/to/file"' -DTO='"/path/to/alternate/content"' -D_GNU_SOURCE -O -Wall -fPIC -shared -o override_fopen.so override_fopen.c -ldl
按如下方式运行程序(在 OSX 上,使用DYLD_PRELOAD
代替LD_PRELOAD
):
LD_PRELOAD=./override_fopen.so ./myexe
仅当程序调用fopen
或open
库函数时,此方法才有效。如果它调用其他函数,您需要覆盖该函数。您可以使用ltrace
查看程序调用了哪些库。