Как вы вводите код в процесс без ptrace - PullRequest
1 голос
/ 02 мая 2020

Есть ли способ внедрить код в двоичный файл ELF без ptrace, я не могу его использовать, поскольку программа, для которой я пишу, использует GDB, и я не хочу останавливать процесс на некоторое время это инъекция. Я прочитал, что это возможно с помощью /proc/pid/mem, но я не мог найти ничего о том, как это сделать. Я также не хочу использовать LD_PRELOAD, поскольку для этого потребуется перезапустить программу, и я бы хотел сделать это во время выполнения.

РЕДАКТИРОВАТЬ: я не могу использовать ptrace, поскольку процесс может быть уже присоединен к gdb

Ответы [ 2 ]

1 голос
/ 02 мая 2020

/proc/pid/mem ведет себя как образ памяти процесса. Чтобы прочитать / записать память процесса, просто откройте /proc/pid/mem, затем lseek по желаемому адресу и read() или write() сколько угодно байтов.

Например, чтобы перезаписать байт в адрес 0x12345 в процессе с 0x90, вы можете просто сделать

fd = open("/proc/XXX/mem", O_RDWR);
lseek(fd, 0x12345, SEEK_SET);
unsigned char new = 0x90;
write(fd, &new, 1);

В 32-битной системе вместо этого используйте lseek64 (и добавьте #define _LARGEFILE64_SOURCE до включения в стандарт).

Обратите внимание, что для доступа к /proc/XXX/mem требуются те же разрешения, что и для отслеживания процесса. В частности, в некоторых системах вам может потребоваться быть root.

0 голосов
/ 04 мая 2020

Я решил, что буду использовать process_vm_writev, что, кажется, работает. Я не знаю, почему он не хочет писать в /proc/pid/mem, что странно.

/**
 * @brief write_process_memory Writes to the memory of a given process
 * @param pid                  Program pid
 * @param address              The base memory address
 * @param buffer               Buffer to write
 * @param n                    How many bytes to write
 * @return                     Returns bytes written
 */
ssize_t write_process_memory(pid_t pid, void *address, void *buffer, ssize_t n) {
    struct iovec local, remote;
    /* this might have to be made so that if n > _SC_PAGESIZE
     * local would be split into multiple locals, similar to how
     * read_process_memory works, no fucking clue though if it's necessary */
    remote.iov_base = address;
    remote.iov_len = n;
    local.iov_base = buffer;
    local.iov_len = n;
    ssize_t amount_read = process_vm_writev(pid, &local, 1, &remote, 1, 0);
    return amount_read;
}
...