ЕЛЬФ

Розуміння формату файлу ELF

Розуміння формату файлу ELF

Від вихідного коду до двійкового коду

Програмування починається з розумної ідеї та написання вихідного коду мовою програмування на ваш вибір, наприклад C, та збереження вихідного коду у файлі. За допомогою адекватного компілятора, наприклад GCC, ваш вихідний код спочатку перекладається в об'єктний код. Зрештою, компоновник перекладає об’єктний код у двійковий файл, який пов’язує об’єктний код із бібліотеками, на які посилаються. Цей файл містить окремі інструкції як машинний код, які розуміє центральний процесор і виконуються відразу після запуску скомпільованої програми.

Згаданий вище двійковий файл має певну структуру, і одним із найпоширеніших є ім'я ELF, що скорочує виконуваний та зв'язний формат. Він широко використовується для виконуваних файлів, переміщуваних об'єктних файлів, спільних бібліотек та дампів ядра.

Двадцять років тому - в 1999 році - проект 86open обрав ELF як стандартний бінарний формат файлів для Unix та Unix-подібних систем на процесорах x86. На щастя, формат ELF раніше був задокументований як у двійковому інтерфейсі програми System V, так і в стандарті інтерфейсу інструменту [4]. Цей факт значно спростив угоду про стандартизацію між різними постачальниками та розробниками операційних систем на базі Unix.

Причиною цього рішення був дизайн ELF - гнучкість, розширюваність та підтримка міжплатформенності для різних форматів ендіан та розмірів адрес. Дизайн ELF не обмежується конкретним процесором, набором команд або апаратною архітектурою. Детальне порівняння форматів виконуваних файлів див. Тут [3].

З тих пір формат ELF використовується у декількох різних операційних системах. Серед інших, це Linux, Solaris / Illumos, Free-, Net- та OpenBSD, QNX, BeOS / Haiku та Fuchsia OS [2]. Крім того, ви знайдете його на мобільних пристроях з ОС Android, Maemo або Meego OS / Sailfish OS, а також на ігрових консолях, таких як PlayStation Portable, Dreamcast та Wii.

Специфікація не пояснює розширення імені файлу ELF-файлів. У використанні різноманітні буквосполучення, такі як .axf, .смітник, .ельф, .o, .prx, .затяжка, .ко, .так, і .мод, або жоден.

Структура файлу ELF

У терміналі Linux команда man elf надає вам зручний підсумок про структуру файлу ELF:

Лістинг 1: Інструкція щодо структури ELF

$ людина ельф
ELF (5) Посібник програміста для Linux ELF (5)
НАЗВА
elf - формат файлів виконуваного файлу та формату зв’язування (ELF)
КОНТРОЛЬ
#включати
ОПИС
Файл заголовка визначає формат виконуваного двійкового файлу ELF
файлів. Серед цих файлів є звичайні виконувані файли, які можна перемістити
об'єктні файли, основні файли та спільні бібліотеки.
Виконуваний файл із використанням формату ELF складається з заголовка ELF,
за ними слід таблиця заголовків програми або таблиця заголовків розділу, або і те, і інше.
Заголовок ELF завжди має зміщений нуль файлу. Програма
таблиця заголовків та зміщення таблиці заголовків розділу у файлі
визначено в заголовку ELF. Дві таблиці описують решту
особливості файлу.
..

Як видно з наведеного вище опису, файл ELF складається з двох розділів - заголовка ELF та даних файлу. Розділ даних файлу може складатися з таблиці заголовків програми, що описує нуль або більше сегментів, таблиці заголовка розділу, що описує нуль або більше розділів, за якою слідують дані, на які посилаються записи з таблиці заголовків програми, і таблиці заголовків розділу. Кожен сегмент містить інформацію, необхідну для виконання файлу під час виконання, тоді як розділи містять важливі дані для зв'язування та переміщення. Рисунок 1 схематично це ілюструє.

Заголовок ELF

Заголовок ELF має довжину 32 байти і визначає формат файлу. Він починається з послідовності з чотирьох унікальних байтів, які є 0x7F, а потім 0x45, 0x4c і 0x46, що перекладається в три літери E, L і F. Серед інших значень заголовок також вказує, чи це файл ELF для 32- або 64-розрядного формату, використовує малу або велику обмеженість, показує версію ELF, а також для якої операційної системи файл скомпільований для взаємодії з правильний двійковий інтерфейс програми (ABI) та набір інструкцій процесора.

Шістнадцятковий дотик дотику двійкового файлу виглядає наступним чином:

.Лістинг 2: Hexdump двійкового файлу

$ hd / usr / bin / touch | голова -5
00000000 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 |.ЕЛЬФ… |
00000010 02 00 3e 00 01 00 00 00 e3 25 40 00 00 00 00 00 |…>…% @… |
00000020 40 00 00 00 00 00 00 00 28 e4 00 00 00 00 00 00 | @… (… |
00000030 00 00 00 00 40 00 38 00 09 00 40 00 1b 00 1a 00 | [захищено електронною поштою] @… |
00000040 06 00 00 00 05 00 00 00 40 00 00 00 00 00 00 00 | [захищено електронною поштою] |

Debian GNU / Linux пропонує команду readelf, яка надається в пакеті GNU 'binutils'. У супроводі перемикача -h (коротка версія “-file-header”) він чудово відображає заголовок файлу ELF. Лістинг 3 ілюструє це для команди touch.

.Лістинг 3: Відображення заголовка файлу ELF

$ readelf -h / usr / bin / touch
Заголовок ELF:
Магія: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
Клас: ELF64
Дані: доповнення 2, мало ендіан
Версія: 1 (поточна)
OS / ABI: UNIX - система V
Версія ABI: 0
Тип: EXEC (виконуваний файл)
Машина: Advanced Micro Devices X86-64
Версія: 0x1
Адреса точки входу: 0x4025e3
Початок заголовків програми: 64 (байт у файл)
Початок заголовків розділів: 58408 (байти у файл)
Прапори: 0x0
Розмір цього заголовка: 64 (байти)
Розмір заголовків програми: 56 (байт)
Кількість заголовків програми: 9
Розмір заголовків розділів: 64 (байти)
Кількість заголовків розділів: 27
Індекс таблиці рядків заголовка розділу: 26

Заголовок програми

Заголовок програми показує сегменти, що використовуються під час виконання, і повідомляє системі, як створити образ процесу. Заголовок з Лістингу 2 показує, що файл ELF складається з 9 заголовків програми, розмір яких становить 56 байт кожен, а перший заголовок починається з байта 64.

Знову ж таки, команда readelf допомагає витягти інформацію з файлу ELF. Перемикач -l (скорочення від -program-headers або -segments) показує більше деталей, як показано в лістингу 4.

.Лістинг 4: Відображення інформації про заголовки програм

$ readelf -l / usr / bin / touch
Тип файлу Elf - EXEC (виконуваний файл)
Точка входу 0x4025e3
Є 9 заголовків програм, починаючи зі зсуву 64
Заголовки програми:
Введіть Offset VirtAddr PhysAddr
FileSiz MemSiz Прапори Вирівняти
PHDR 0x0000000000000040 0x0000000000400040 0x0000000000400040
0x00000000000001f8 0x00000000000001f8 R E 8
INTERP 0x0000000000000238 0x0000000000400238 0x0000000000400238
0x000000000000001c 0x000000000000001c R 1
[Запит інтерпретатора програми: / lib64 / ld-linux-x86-64.так.2]
ЗАВАНТАЖИТИ 0x0000000000000000 0x0000000000400000 0x0000000000400000
0x000000000000d494 0x000000000000d494 R E 200000
ЗАВАНТАЖИТИ 0x000000000000de10 0x000000000060de10 0x000000000060de10
0x0000000000000524 0x0000000000000748 RW 200000
ДИНАМІЧНА 0x000000000000de28 0x000000000060de28 0x000000000060de28
0x00000000000001d0 0x00000000000001d0 RW 8
ПРИМІТКА 0x0000000000000254 0x0000000000400254 0x0000000000400254
0x0000000000000044 0x0000000000000044 R 4
GNU_EH_FRAME 0x000000000000bc40 0x000000000040bc40 0x000000000040bc40
0x00000000000003a4 0x00000000000003a4 R 4
GNU_STACK 0x0000000000000000 0x0000000000000000 0x0000000000000000
0x0000000000000000 0x0000000000000000 RW 10
GNU_RELRO 0x000000000000de10 0x000000000060de10 0x000000000060de10
0x00000000000001f0 0x00000000000001f0 R 1
Розділ для відображення сегментів:
Розділити сегменти…
00
01 .інтерп
02 .інтерп .Примітка.ABI-мітка .Примітка.гну.build-id .гну.хеш .динсим .динстр .гну.версія .гну.version_r .віднос.дин .віднос.plt .у цьому .plt .текст .фіні .родата .eh_frame_hdr .eh_frame
03 .init_array .fini_array .jcr .динамічний .здобули .здобули.plt .даних .bss
04 .динамічний
05 .Примітка.ABI-мітка .Примітка.гну.build-id
06 .eh_frame_hdr
07
08 .init_array .fini_array .jcr .динамічний .здобули

Заголовок розділу

Третя частина структури ELF - це заголовок розділу. Він призначений для переліку окремих розділів двійкового файлу. Перемикач -S (скорочення від -section-headers або -sections) перелічує різні заголовки. Що стосується команди дотику, тут є 27 заголовків розділів, і в лістингу 5 показані лише перші чотири з них, а також останній. Кожен рядок охоплює розмір розділу, тип розділу, а також його адресу та зміщення пам’яті.

.Лістинг 5: Деталі розділу, розкриті readelf

$ readelf -S / usr / bin / touch
Є 27 заголовків розділів, починаючи зі зміщення 0xe428:
Заголовки розділів:
[Nr] Ім'я Тип Адреса Зсув
Розмір EntSize Прапори Посилання Інформація Вирівняти
[0] НУЛЬ 0000000000000000 00000000
0000000000000000 0000000000000000 0 0 0
[1] .interp PROGBITS 0000000000400238 00000238
000000000000001c 0000000000000000 A 0 0 1
[2] .Примітка.ABI-тег ПРИМІТКА 0000000000400254 00000254
0000000000000020 0000000000000000 A 0 0 4
[3] .Примітка.гну.build-i ПРИМІТКА 0000000000400274 00000274
..
..
[26] .shstrtab STRTAB 0000000000000000 0000e334
00000000000000ef 0000000000000000 0 0 1
Ключ до прапорів:
W (запис), A (виділення), X (виконання), M (злиття), S (рядки), l (великий)
I (інформація), L (порядок посилань), G (група), T (TLS), E (виключає), x (невідомо)
O (потрібна додаткова обробка ОС) o (конкретно для ОС), p (для процесора)

Інструменти для аналізу файлу ELF

Як ви могли зауважити з наведених вище прикладів, GNU / Linux розроблений рядом корисних інструментів, які допоможуть вам проаналізувати файл ELF. Перший кандидат, на якого ми подивимось, - це файлова утиліта.

файл відображає основну інформацію про файли ELF, включаючи архітектуру набору команд, для якої призначений код у переміщуваному, виконуваному або спільному об'єктному файлі. У списку 6 він повідомляє, що / bin / touch - це 64-розрядний виконуваний файл, що слідує за стандартною базою Linux (LSB), динамічно пов’язаний та створений для ядра GNU / Linux версії 2.6.32.

.Лістинг 6: Основна інформація за допомогою файлу

$ file / bin / touch
/ bin / touch: виконуваний 64-розрядний LSB ELF, x86-64, версія 1 (SYSV), динамічно пов'язаний, інтерпретатор / lib64 / l,
для GNU / Linux 2.6.32, BuildID [sha1] = ec08d609e9e8e73d4be6134541a472ad0ea34502, позбавлений
$

Другий кандидат - readelf. Він відображає детальну інформацію про файл ELF. Список комутаторів порівняно довгий і охоплює всі аспекти формату ELF. Використання перемикача -n (скорочення від -notes) У лістингу 7 показані лише розділи приміток, які існують у стилі файлу - тег версії ABI та бітстринг ідентифікатора збірки.

.Лістинг 7: Відображення вибраних розділів файлу ELF

$ readelf -n / usr / bin / touch
Відображення приміток, знайдених із зміщенням файлу 0x00000254 довжиною 0x00000020:
Розмір даних власника Опис
GNU 0x00000010 NT_GNU_ABI_TAG (тег версії ABI)
ОС: Linux, ABI: 2.6.32
Відображення приміток, знайдених із зміщенням файлу 0x00000274 довжиною 0x00000024:
Розмір даних власника Опис
GNU 0x00000014 NT_GNU_BUILD_ID (унікальний бітстринг ідентифікатора збірки)
Ідентифікатор збірки: ec08d609e9e8e73d4be6134541a472ad0ea34502

Зверніть увагу, що в програмах Solaris та FreeBSD утиліта elfdump [7] відповідає readelf. Станом на 2019 рік не було нового випуску чи оновлення з 2003 року.

Номер три - пакет із назвою elfutils [6], який є суто доступним для Linux. Він надає альтернативні інструменти GNU Binutils, а також дозволяє перевіряти файли ELF. Зверніть увагу, що всі назви службових програм, що містяться в пакеті, починаються з eu для "elf utils".

І останнє, але не менш важливе, ми згадаємо objdump. Цей інструмент схожий на readelf, але фокусується на об'єктних файлах. Він надає подібний спектр інформації про файли ELF та інші формати об'єктів.

.Лістинг 8: Інформація про файл, вилучена objdump

$ objdump -f / bin / touch
/ bin / touch: формат файлу elf64-x86-64
архітектура: i386: x86-64, прапори 0x00000112:
EXEC_P, HAS_SYMS, D_PAGED
початкова адреса 0x00000000004025e3
$

Існує також програмний пакет під назвою "elfkickers" [9], який містить інструменти для зчитування вмісту файлу ELF, а також маніпулювання ним. На жаль, кількість випусків досить низька, і тому ми просто згадуємо про це, а не наводимо подальших прикладів.

Натомість, як розробник, ви можете поглянути на "pax-utils" [10,11]. Цей набір утиліт надає ряд інструментів, які допомагають перевірити файли ELF. Як приклад, dumpelf аналізує файл ELF і повертає файл заголовка C, що містить деталі - див. Малюнок 2.

Висновок

Завдяки поєднанню розумного дизайну та чудової документації формат ELF працює дуже добре, і все ще використовується після 20 років. Показані вище утиліти дають змогу переглянути уявлення про файл ELF і дозволити з’ясувати, що робить програма. Це перші кроки для аналізу програмного забезпечення - щасливий злом!

Посилання та посилання
  • [1] Виконуваний та зв’язаний формат (ELF), Вікіпедія
  • [2] Фуксія ОС
  • [3] Порівняння форматів виконуваних файлів, Вікіпедія
  • [4] Linux Foundation, посилання на технічні характеристики
  • [5] Сіро Сантіллі: Підручник ELF Hello World
  • [6] elfutils пакет Debian
  • [7] elfdump
  • [8] Майкл Болен: 101 файл ELF у Linux: Розуміння та аналіз
  • [9] ельфіки
  • [10] Загартовані / утиліти PaX
  • [11] pax-utils, пакет Debian
Подяка

Письменник висловлює подяку Акселю Беккерту за підтримку щодо підготовки цієї статті.

5 найкращих аркадних ігор для Linux
В наш час комп’ютери - це серйозні машини, що використовуються для ігор. Якщо ви не можете отримати новий високий бал, ви зрозумієте, що я маю на уваз...
Битва за Веснот 1.13.6 Розробка випущена
Битва за Веснот 1.13.6, випущений минулого місяця, є шостим випуском розробки в 1.13.x, і це забезпечує низку вдосконалень, особливо до інтерфейсу кор...
Як встановити League of Legends на Ubuntu 14.04
Якщо ви шанувальник League of Legends, то це можливість для вас тестувати League of Legends. Зверніть увагу, що LOL підтримується на PlayOnLinux, якщо...