От изходен код към двоичен код
Програмирането започва с умна идея и писане на изходен код на избран от вас програмен език, например 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 командният човек elf ви дава удобно резюме за структурата на ELF файл:
Листинг 1: Страницата на структурата на ELF
$ man elfELF (5) Ръководство на програмиста за Linux ELF (5)
ИМЕ
elf - формат на изпълними и свързващи формати (ELF) файлове
СИНОПСИС
#include
ОПИСАНИЕ
Заглавният файл
файлове. Сред тези файлове са нормални изпълними файлове, преместваеми
обектни файлове, основни файлове и споделени библиотеки.
Изпълним файл, използващ файловия формат 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 | глава -500000000 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 00 40 00 00 00 00 00 00 00 | [имейл защитен] |
Debian GNU / Linux предлага командата readelf, която се предоставя в пакета на GNU 'binutils'. Придружен от превключвателя -h (кратка версия за “-file-header”) той добре показва заглавката на ELF файл. Листинг 3 илюстрира това за командното докосване.
.Листинг 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
DYNAMIC 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-таг .Забележка.gnu.build-id .gnu.хеш .динсим .dynstr .gnu.версия .gnu.version_r .относително.дин .относително.plt .в него .plt .текст .фини .родата .eh_frame_hdr .eh_frame
03 .init_array .fini_array .jcr .динамичен .има .има.plt .данни .bss
04 .динамичен
05 .Забележка.ABI-таг .Забележка.gnu.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] NULL 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] .Забележка.gnu.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 Standard Base (LSB), динамично свързан и създаден за ядрото GNU / Linux версия 2.6.32.
.Листинг 6: Основна информация с помощта на файл
$ файл / кош / докосване/ 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 файлове и други обектни формати.
.Листинг 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] Fuchsia OS
- [3] Сравнение на изпълними файлови формати, Уикипедия
- [4] Linux Foundation, посочени спецификации
- [5] Ciro Santilli: Урок за ELF Hello World
- [6] elfutils пакет Debian
- [7] elfdump
- [8] Майкъл Болен: 101-те от ELF файловете в Linux: Разбиране и анализ
- [9] elfkickers
- [10] Закалени / PaX помощни програми
- [11] pax-utils, пакет Debian
Благодарности
Писателят би искал да благодари на Аксел Бекерт за подкрепата му по отношение на подготовката на тази статия.