использование memfd_create и fexecve для запуска ELF из памяти - PullRequest
0 голосов
/ 01 августа 2020

Я знаю, что другие люди делали это на разных языках, но я не могу найти пример кода C, самый распространенный был в Perl, и это действительно сбивало с толку, потому что я не знаю Perl и я просто хочу загрузить двоичный файл (с диска) в память, а затем выполнить его https://magisterquis.github.io/2018/03/31/in-memory-only-elf-execution.html

1 Ответ

0 голосов
/ 06 сентября 2020

Здесь вы go, пример, написанный на C (скомпилированный на linux 5.4 и работающий должным образом):

#define _GNU_SOURCE
#define _POSIX_C_SOURCE 200809L

#include <sys/types.h>
#include <sys/mman.h>

#include <unistd.h>

#include <err.h>
#include <errno.h>

size_t min(size_t x, size_t y)
{
    return x > y ? y : x;
}

/**
 * @param len != 0
 */
void fdput(int fd, const char *str, size_t len)
{
    size_t cnt = 0;
    do {
        ssize_t result = write(fd, str + cnt, min(len - cnt, 0x7ffff000));
        if (result == -1) {
            if (errno == EINTR)
                continue;
            err(1, "%s failed", "write");
        }
        cnt += result;
    } while (cnt != len);
}
#define fdputc(fd, constant_str) fdput((fd), (constant_str), sizeof(constant_str) - 1)

int main(int argc, char* argv[])
{
    int fd = memfd_create("script", 0);
    if (fd == -1)
        err(1, "%s failed", "memfd_create");

    fdputc(fd, "#!/bin/bash\necho Hello, world!");

    {
        const char * const argv[] = {"script", NULL};
        const char * const envp[] = {NULL};
        fexecve(fd, (char * const *) argv, (char * const *) envp);
    }

    err(1, "%s failed", "fexecve");
}

Я также тестировал с вызовом fork() непосредственно перед fexecve, и он также работает должным образом.

Вот код (в основном идентичный приведенному выше):

#define _GNU_SOURCE
#define _POSIX_C_SOURCE 200809L

#include <sys/types.h>
#include <sys/mman.h>
#include <sys/wait.h>

#include <unistd.h>

#include <err.h>
#include <errno.h>

size_t min(size_t x, size_t y)
{
    return x > y ? y : x;
}

/**
 * @param len != 0
 */
void fdput(int fd, const char *str, size_t len)
{
    size_t cnt = 0;
    do {
        ssize_t result = write(fd, str + cnt, min(len - cnt, 0x7ffff000));
        if (result == -1) {
            if (errno == EINTR)
                continue;
            err(1, "%s failed", "write");
        }
        cnt += result;
    } while (cnt != len);
}
#define fdputc(fd, constant_str) fdput((fd), (constant_str), sizeof(constant_str) - 1)

int main(int argc, char* argv[])
{
    int fd = memfd_create("script", 0);
    if (fd == -1)
        err(1, "%s failed", "memfd_create");

    fdputc(fd, "#!/bin/bash\necho Hello, world!");

    pid_t pid = fork();
    if (pid == 0) {
        const char * const argv[] = {"script", NULL};
        const char * const envp[] = {NULL};
        fexecve(fd, (char * const *) argv, (char * const *) envp);

        err(1, "%s failed", "fexecve");
    } else if (pid == -1)
        err(1, "%s failed", "fork");

    wait(NULL);

    return 0;
}
...