Секреты покорения эльфов



         

Анатомия эльфов и их репродуктивные возможности


Изначально UNIX (и производные от нее операционные системы) поддерживали множество исполняемых форматов, ожесточенно конкурирующих между собой, но теперь поле боя опустело и среди дымящихся обломков минувших сражений остался один ELF, ставший стандартом де-факто для LINUX и BSD. Кое-где еще встречается древний a.out, но на него можно не обращать внимания.

Аббревиатура ELF расшифровывается как от Execution & Linkable Format (формат исполнения и компоновки). Он состоит в определенном родстве с win32 PE, поэтому у них много общего. В начале ELF-файла расположен служебный заголовок (ELF-header), описывающий основные характеристики файла — тип (исполнения или линковки), архитектура ЦП, виртуальный адрес точки входа, размеры и смещения остальных заголовков…

За ELF-header'ом следует таблица сегментов (program header table), перечисляющая имеющиеся сегменты и их атрибуты. В формате линковки она необязательно. Линкеру сегменты глубоко фиолетов и он работает исключительно на уровне секций. Напротив, системный загрузчик, загружающий исполняемый ELF-файл в память, игнорирует секции, и оперирует целыми сегментами.

Сегменты и секции — что это такое? Сегмент — это непрерывная область адресного пространства со своими атрибутами доступа. В частности, сегмент кода имеет атрибут исполнения, а сегмент данных — атрибуты чтения и записи. Не стоит путать ELF-сегменты с сегментами x86 процессора! В защищенном режиме 386+ никаких "сегментов" в изначальном смысле этого слова уже нет, а есть только селекторы и все сегменты ELF-файла загружается в единый 4 Гбайтовый x86-сегмент! В зависимости от типа сегмента, величина выравнивания в памяти может варьировать от 4h до 1000h байт (размер страницы на x86). В самом ELF-файле хранятся в невыровненном виде, плотно прижатые друг к другу. Так что со свободным пространством для внедрения сплошные напряги.

Ближайший аналог ELF-сегментов — PE-секции, но в PE-файлах, секция — это наименьшая структурная единица, а вот в ELF-файлах сегмент может быть разбит на один или несколько фрагментов — секций. В частности, типичный кодовый сегмент состоит из секций .init (процедуры инициализации), .plt (секция связок), .text (основой код программы) и .finit (процедуры финализации). Секции нужны линкеру для комбинирования, чтобы он мог отобрать секции с похожими атрибутами и оптимальным образом растасовать их по сегментам при сборке файла, то есть "скомбинировать".




Содержание  Назад  Вперед