Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/linux/28.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
修改strace以捕获并替换打开的系统调用中的文件名_C_Linux_Strace_Ptrace - Fatal编程技术网

修改strace以捕获并替换打开的系统调用中的文件名

修改strace以捕获并替换打开的系统调用中的文件名,c,linux,strace,ptrace,C,Linux,Strace,Ptrace,我试图修改strace以捕获文件open syscall并更改实际打开的文件。例如,用户尝试: 打开(OUT,“>input.txt”),但真正要打开的文件是“input.txt.version1” 通过使用ptrace(ptrace_POKEDATA、pid、addr、laddr),当新名称的长度与旧名称的长度完全相同时,我取得了一些成功。我正在拦截open.c中的open调用,并将util.c中的umoven修改为poke而不是peek来替换字符 但是,当新文件名较长时,此操作将失败,因为它

我试图修改strace以捕获文件open syscall并更改实际打开的文件。例如,用户尝试: 打开(OUT,“>input.txt”),但真正要打开的文件是“input.txt.version1”

通过使用ptrace(ptrace_POKEDATA、pid、addr、laddr),当新名称的长度与旧名称的长度完全相同时,我取得了一些成功。我正在拦截open.c中的open调用,并将util.c中的umoven修改为poke而不是peek来替换字符

但是,当新文件名较长时,此操作将失败,因为它可能超出原始文件名数组的长度。我真正需要做的是用一个指向我自己字符串的新指针替换指向char数组的指针

文件名位于tcp->u_arg[0]中,这是x86系统上的rdi寄存器。我尝试过以下几种变体,但运气不佳:

struct user_regs_struct      x86_64_r;
uint64_t *const x86_64_rdi_ptr = (uint64_t *) &x86_64_r.rdi;
ptrace(PTRACE_POKEDATA, tcp->pid,  x86_64_rdi_ptr, &newPath);
如何用任意长度的新路径替换文件名?
只使用ptrace而不是strace的修改也可以。strace已经处理了很多其他问题。

不是
ptrace
,也不是
strace
,但是您可以通过
LD\u PRELOAD
钩住
open
功能来实现这一点

编辑:根据@JonathanLeffler的评论,我试图修复hook函数原型,以处理mode参数(如果给定的话),我不能100%确定这将始终有效,但它应该给出如何做到这一点的想法

胡克

#define _GNU_SOURCE
#include <dlfcn.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h> //mode_t
#include <stdarg.h>  //va_arg

typedef int (*pfn_open_t)(const char *pathname, int flags, mode_t mode);

int open(const char *pathname, int flags, ...)
{
    pfn_open_t o_open;
    va_list val;
    mode_t mode;
    o_open = (pfn_open_t)dlsym(RTLD_NEXT,"open");
    // Extract vararg (mode)
    va_start(val, flags);
    mode = va_arg(val, mode_t);
    va_end(val);
    if(strcmp(pathname, "origfile") == 0)
    {
         puts("opening otherfile\n");
         return o_open("otherfile", flags, mode);
    }
    else
    {
         printf("opening %s\n", pathname);
         return o_open(pathname,flags, mode);
    }
}
使用钩子运行程序:

$ LD_PRELOAD=path/to/libhook.so myprogram

选民:请解释一下,为什么要这样做?听起来像是恶意软件。@Olaf它可能对调试有用……这样做有很多正当的理由。(不修改原始程序的测试和兼容性就是其中之一)@Olaf这是用于自动版本控制,而不需要像问题中所建议的那样修改原始程序。这是一种有趣的方法。我会回去做的。我假设这可以用于任何系统调用?挑剔:您的
pfn\u open\u t
类型与
open()
的官方原型不匹配,后者有一个
参数,您很清楚。如果标志包括O_CREAT,您需要传递第三个参数。@JonathanLeffler-谢谢您指出这一点。我在发布答案时忽略了这个问题,但这是一个需要解决的重要问题。我会试着把它修好。如果你有一个解决方案在手-请随时编辑我的答案,或张贴它单独。我很高兴看到:)你所拥有的和我所用的很接近。由于用户可能不会通过
mode\u t
,除非
flags
包含O\u CREAT,我可能会:
mode\u t mode=0666;如果(flags&O_create){va_list args;va_start(args,flags);mode=va_arg(args,int);va_end(args);}
仅在(应该)提供时收集它。你所得到的通常会起作用,尽管模式值有时可能有点古怪——但这在形式上并不重要。“细化”(名义上的技巧——但实际上大部分都是繁忙的工作,其优势有限或没有优势)是根据O_CREAT进行函数调用。例如,此解决方案在某些情况下有效(“touch origfile”),但在其他情况下失败:perl-e“open(in,“>origfile”);”。在我接受这个答案之前,我需要这个方法在所有情况下都有效,或者至少理解其中的差异。
$ LD_PRELOAD=path/to/libhook.so myprogram