Изменение strace для захвата и замены имени файла в открытом системном вызове

Я пытаюсь изменить strace, чтобы захватить системный вызов открытия файла и изменить фактически открытый файл. Например, пользователь пытается: open(OUT,">input.txt"), но действительно будет открыт файл "input.txt.version1".

У меня был некоторый успех, когда длина нового имени точно такая же, как длина старого имени, с помощью ptrace(PTRACE_POKEDATA, pid, addr, laddr). Я перехватываю вызов open в open.c и модифицирую umoven в util.c, чтобы заменить символы вместо peek.

Но это не удается, когда новое имя файла длиннее, потому что оно может выйти за пределы исходной длины массива имен файлов. Что мне действительно нужно сделать, так это заменить указатель на массив символов новым указателем на мою собственную строку.

Имя файла находится в tcp->u_arg[0], что является регистром rdi в системах x86. Я пробовал варианты следующего без везения:

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 просто заботится о многих других проблемах.


person michael    schedule 11.12.2015    source источник
comment
Для downvoter: пожалуйста, объясните.   -  person Eugene Sh.    schedule 11.12.2015
comment
Зачем это делать? Похоже на вредоносное ПО.   -  person too honest for this site    schedule 11.12.2015
comment
@Olaf Это может быть полезно для отладки ...   -  person Eugene Sh.    schedule 11.12.2015
comment
Для этого есть много законных причин. (среди них тестирование и совместимость без модификации исходной программы)   -  person MByD    schedule 11.12.2015
comment
@Olaf это для автоматического управления версиями, не требуя изменения исходной программы, как это предлагается в вопросе.   -  person michael    schedule 11.12.2015


Ответы (1)


Ни ptrace, ни strace, но вы можете сделать это с LD_PRELOAD, подключив функцию open.

Редактировать: согласно комментарию @JonathanLeffler, я попытался исправить прототип функции ловушки, чтобы обработать аргумент режима (если задан). Я не на 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);
    }
}

скомпилируйте код как общий объект:

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

запустите программу с вашим хуком:

$ LD_PRELOAD=path/to/libhook.so myprogram
person MByD    schedule 11.12.2015
comment
Это интересный подход. Я вернусь и поработаю над этим. Я предполагаю, что это может работать для любого системного вызова? - person michael; 11.12.2015
comment
Сбор гнид: ваш pfn_open_t тип не соответствует официальному прототипу open(), у которого есть параметр ..., как вы прекрасно знаете. Если флаги включают O_CREAT, вам нужно передать этот третий параметр. - person Jonathan Leffler; 11.12.2015
comment
@JonathanLeffler - Спасибо, что указали на это. Я проигнорировал эту проблему, когда публиковал ответ, но это важная проблема для решения. Я постараюсь исправить это. Если у вас есть решение, пожалуйста, отредактируйте мой ответ или опубликуйте его отдельно. с удовольствием посмотрю :) - person MByD; 12.12.2015
comment
То, что у вас есть, близко к тому, что я бы использовал. Поскольку пользователь может не передать mode_t, если flags не включает O_CREAT, у меня, вероятно, было бы: mode_t mode = 0666; if (flags & O_CREAT) { va_list args; va_start(args, flags); mode = va_arg(args, int); va_end(args); } собирать его только в том случае, если он был (должен был) предоставлен. То, что у вас есть, обычно будет работать, хотя значение режима иногда может быть немного эксцентричным, но формально это не должно иметь значения. «Уточнение» (номинальная уловка, но на самом деле в основном занятая работа с ограниченным преимуществом или без него) будет заключаться в том, чтобы вызовы функций зависели от O_CREAT. - person Jonathan Leffler; 12.12.2015
comment
Это решение работает в некоторых случаях (например, касание исходного файла), но не работает в других случаях: perl -e open(IN,'›origfile');. Мне нужно, чтобы это работало во всех случаях или, по крайней мере, понимало различия, прежде чем я смогу принять этот ответ. - person michael; 13.12.2015
comment
Оказывается, мне нужно захватить open64 для perl. Есть ли список, чтобы я ничего не пропустил? - person michael; 13.12.2015