#!/usr/bin/env python3 # -*- coding: utf-8 -*- # Скрипт генерирует КОРРЕКТНЫЙ 64-битный исполняемый ELF-файл для Linux (x86-64), # содержащий 12 инструкций NOP (0x90) в секции .text и один байт (0x0A) в секции .data. # Файл полностью соответствует ELF-спецификации. import struct def align_up(offset, alignment): """Выравнивание offset вверх до alignment""" return (offset + alignment - 1) & ~(alignment - 1) def pack_elf(): """ Создаёт байтовое представление валидного ELF-исполняемого файла. Возвращает bytes — содержимое файла. """ # Размер страницы памяти в Linux на x86-64 (4096 байт = 0x1000) PAGE_SIZE = 0x1000 # Адрес точки входа программы — начало секции .text ENTRY = 0x401000 # === СОДЕРЖИМОЕ СЕКЦИЙ === # Машинный код: 12 инструкций NOP (код операции 0x90) text_code = b'\x90' * 12 # Данные: один байт — символ новой строки (0x0A = '\n') data_content = b'\x0a' # Таблица строк имён секций (обязательна для Section Headers) # Формат: нуль-терминированные строки подряд. # Порядок: "", ".text", ".data", ".shstrtab" shstrtab_content = b'\x00.text\x00.data\x00.shstrtab\x00' # === СМЕЩЕНИЯ В ФАЙЛЕ (в байтах) === # Program Headers (заголовки сегментов) начинаются сразу после ELF-заголовка phdr_start = 64 # размер ELF-заголовка # Секция .text начинается с границы страницы 0x1000 (4096) text_offset = 0x1000 # Секция .data начинается со следующей страницы — 0x2000 (8192) data_offset = 0x2000 # Таблица имён секций (.shstrtab) размещается сразу после .data с ВЫРАВНИВАНИЕМ shstrtab_offset = align_up(data_offset + len(data_content), 8) # 0x2008 вместо 0x2001 # Заголовки секций (Section Headers) размещаются сразу после .shstrtab с выравниванием shdr_offset = align_up(shstrtab_offset + len(shstrtab_content), 16) # 0x2020 # === РАЗМЕРЫ КОМПОНЕНТОВ === text_size = len(text_code) # 12 байт data_size = len(data_content) # 1 байт shstrtab_size = len(shstrtab_content) # 17 байт # Размер Program Headers: 3 заголовка × 56 байт phdr_size = 3 * 56 # 168 байт # Размер одного заголовка секции — 64 байта для 64-битного ELF # Всего 4 секции: NULL, .text, .data, .shstrtab shdr_size = 4 * 64 # 256 байт # Общий размер файла: от начала до конца последнего заголовка секции file_size = shdr_offset + shdr_size # 0x2020 + 256 = 0x2120 (8480 байт) # Создаём байтовый массив нужного размера, заполненный нулями elf_data = bytearray(file_size) # === 1. ELF-ЗАГОЛОВОК (64 байта) === # e_ident — магическое число и базовые параметры формата (ИСПРАВЛЕНО) # Структура e_ident: 16 байт e_ident = ( b'\x7fELF' # ELF Magic (4 байта) b'\x02' # 64-bit (1 байт) b'\x01' # Little-endian (1 байт) b'\x01' # ELF Version (1 байт) b'\x00' # OS ABI: System V (1 байт) b'\x00' # ABI Version (1 байт) b'\x00\x00\x00\x00\x00\x00\x00' # Padding (7 байт) - ИТОГО 16 байт ) assert len(e_ident) == 16, f"e_ident должен быть 16 байт, а не {len(e_ident)}" # Упаковываем ELF-заголовок в бинарный формат elf_header = struct.pack( '<16sHHIQQQIHHHHHH', e_ident, # e_ident[16] - 16 байт 2, # e_type = ET_EXEC (исполняемый файл) 0x3e, # e_machine = EM_X86_64 (AMD x86-64) 1, # e_version = 1 ENTRY, # e_entry — адрес точки входа phdr_start, # e_phoff — смещение Program Headers в файле shdr_offset, # e_shoff — смещение Section Headers в файле 0, # e_flags — флаги архитектуры (0 для x86-64) 64, # e_ehsize — размер ELF-заголовка (64 байта) 56, # e_phentsize — размер одного Program Header (56 байт) 3, # e_phnum — количество Program Headers 64, # e_shentsize — размер одного Section Header (64 байта) 4, # e_shnum — количество Section Headers 3 # e_shstrndx — индекс секции с именами (.shstrtab) ) # Записываем ELF-заголовок в начало файла elf_data[0:64] = elf_header # === 2. PROGRAM HEADERS (заголовки сегментов) === def make_phdr(p_type, p_offset, p_vaddr, p_paddr, p_filesz, p_memsz, p_flags, p_align): """ Создаёт бинарное представление заголовка сегмента. """ # Проверки корректности assert p_offset % p_align == 0, f"Segment offset {p_offset:#x} not aligned to {p_align:#x}" assert p_vaddr % p_align == 0, f"Virtual address {p_vaddr:#x} not aligned to {p_align:#x}" assert p_filesz <= p_memsz, f"File size {p_filesz:#x} > memory size {p_memsz:#x}" return struct.pack('