Разбиране на файловия формат ELF

Understanding Elf File Format



От изходния код до двоичния код

Програмирането започва с наличието на умна идея и писането на изходния код на език за програмиране по ваш избор, например C, и запазването на изходния код във файл. С помощта на подходящ компилатор, например GCC, първоначално вашият изходен код се превежда в обектния код. В крайна сметка линкерът превежда обектния код в двоичен файл, който свързва обектния код с референтните библиотеки. Този файл съдържа единичните инструкции като машинен код, които се разбират от процесора и се изпълняват веднага след стартирането на компилираната програма.

Двоичният файл, споменат по -горе, следва специфична структура и един от най -често срещаните се нарича ELF, който съкращава изпълним и свързващ формат. Той се използва широко за изпълними файлове, преместваеми обектни файлове, споделени библиотеки и основни сметища.







Преди двадесет години-през 1999 г.-проектът 86open избра ELF като стандартен двоичен файлов формат за Unix и Unix-подобни системи на x86 процесори. За щастие, форматът ELF е бил предварително документиран както в двоичния интерфейс на приложение System System, така и в стандарта за интерфейс на инструмента [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, .bin, .elf, .o, .prx, .puff, .ko, .so и .mod, или няма.

Структурата на 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: Шестнадесетичното копие на двоичния файл

$ hd/usr/bin/touch | глава -5
00000000 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 | .ELF ........... |
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 40 00 00 00 00 00 00 00 | [защитен по имейл] |

Debian GNU/Linux предлага командата readelf, която се предоставя в пакета „binutils“ на GNU. Придружен от превключвателя -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 - System V
ABI версия: 0
Тип: EXEC (изпълним файл)
Машина: Разширени микро устройства 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.so.2]
Заредете 0x0000000000000000 0x0000000000400000 0x0000000000400000
0x000000000000d494 0x000000000000d494 R E 200000
Заредете 0x000000000000de10 0x000000000060de10 0x000000000060de10
0x0000000000000524 0x0000000000000748 RW 200000
DYNAMIC 0x000000000000de28 0x000000000060de28 0x000000000060de28
0x00000000000001d0 0x00000000000001d0 RW 8
ЗАБЕЛЕЖКА 0x0000000000000254 0x0000000000400254 0x0000000000400254
0x0000000000000044 0x0000000000000044 R 4
GNU_EH_FRAME 0x000000000000bc40 0x000000000040bc40 0x00000000004040bc40
0x00000000000003a4 0x00000000000003a4 R 4
GNU_STACK 0x0000000000000000 0x0000000000000000 0x0000000000000000
0x000000000000000000 0x000000000000000000 RW 10
GNU_RELRO 0x000000000000de10 0x000000000060de10 0x00000000006060de10
0x00000000000001f0 0x00000000000001f0 R 1

Съпоставяне на секции към сегменти:
Секции на сегменти ...
00
01. Прекъсване
02 .interp .note.ABI-tag .note.gnu.build-id .gnu.hash .dynsym .dynstr .gnu.version .gnu.version_r .rela.dyn .rela.plt .init .plt .text .fini. rodata .eh_frame_hdr .eh_frame
03 .init_array .fini_array .jcr .dynamic .got .got.plt .data .bss
04 .динамичен
05 .note.ABI-tag .note.gnu.build-id
06 .eh_frame_hdr
07
08 .init_array .fini_array .jcr .dynamic .got

Заглавието на раздела

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

.Списък 5: Подробности за раздела, разкрити от readelf

$ readelf -S/usr/bin/touch
Има 27 заглавки на секции, започващи от отместване 0xe428:

Заглавки на секции:
[Nr] Име Тип Тип Адрес Отместване
Размер EntSize Флагове Информация за връзката Подравнете
[0] NULL 0000000000000000 00000000
0000000000000000 0000000000000000 0 0 0
[1] .интерфейс ПРОБИТИ 0000000000400238 00000238
000000000000001c 0000000000000000 A 0 0 1
[2] .note.ABI-tag ЗАБЕЛЕЖКА 0000000000400254 00000254
0000000000000020 0000000000000000 A 0 0 4
[3] .note.gnu.build-i ЗАБЕЛЕЖКА 0000000000400274 00000274
...
...
[26] .shstrtab STRTAB 000000000000000000 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 файл. Първият кандидат, който ще разгледаме, е помощната програма за файлове.

file показва основна информация за ELF файловете, включително архитектурата на набора от инструкции, за която е предназначен кодът в преместваем, изпълним или споделен обект файл. В списък 6 той ви казва, че/bin/touch е 64-битов изпълним файл, следващ стандартната база на Linux (LSB), динамично свързан и създаден за версията на ядрото на GNU/Linux 2.6.32.

.Списък 6: Основна информация с помощта на файл

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

Вторият кандидат се препрочита. Той показва подробна информация за 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 файлове и други формати на обекти.

.Listing 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 файл и ви позволяват да разберете какво прави програмата. Това са първите стъпки за анализ на софтуера - щастливо хакване!

Връзки и препратки
Благодарности

Писателят би искал да благодари на Аксел Бекерт за подкрепата му при подготовката на тази статия.