michael
michael

Reputation: 265

Modifying strace to capture and replace the filename in an open syscall

I'm trying to modify strace to capture the file open syscall and change the file that is actually opened. For example, the user tries: open(OUT,">input.txt"), but the file that really will be opened is "input.txt.version1".

I have had some success when the length of the new name is exactly the same as the length of the old name, by using ptrace(PTRACE_POKEDATA, pid, addr, laddr). I'm intercepting the open call in open.c and modifying umoven in util.c to poke instead of peek to replace characters.

But, this fails when the new filename is longer, because it can overrun the original filename array length. What I really need to do is replace the pointer to the char array with a new pointer to my own string.

The filename is in tcp->u_arg[0], which is the rdi register on x86 systems. I have tried variations of the following with no luck:

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);

How can I replace the filename with a new path of arbitrary length? An answer using only ptrace instead of a modification of strace would be fine too. strace just takes care of so many other issues already.

Upvotes: 3

Views: 1118

Answers (1)

MByD
MByD

Reputation: 137392

Not ptrace, nor strace, but you can do that with LD_PRELOAD by hooking the open function.

Edit: as per @JonathanLeffler comment, I tried to fix the hook function prototype, to handle the mode argument (if given) I am not 100% sure that this will always work, but it should give the idea of how to do that.

hook.c

#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);
    }
}

compile the code as shared object:

gcc -shared -fPIC  hook.c -o libhook.so -ldl

run the program with your hook:

$ LD_PRELOAD=path/to/libhook.so myprogram

Upvotes: 5

Related Questions