Verstehen des ELF -Dateiformates

Verstehen des ELF -Dateiformates

Vom Quellcode zum Binärcode

Die Programmierung beginnt mit einer cleveren Idee und dem Schreiben von Quellcode in einer Programmiersprache Ihrer Wahl, zum Beispiel C, und speichert den Quellcode in einer Datei. Mit Hilfe eines angemessenen Compilers, zum Beispiel GCC, wird Ihr Quellcode zuerst in Objektcode übersetzt. Schließlich übersetzt der Linker den Objektcode in eine Binärdatei, die den Objektcode mit den referenzierten Bibliotheken verknüpft. Diese Datei enthält die einzelnen Anweisungen als Maschinencode, die von der CPU verstanden und so ausgeführt werden, dass das kompilierte Programm ausgeführt wird.

Die oben erwähnte Binärdatei folgt einer bestimmten Struktur, und eine der häufigsten wird als Elf bezeichnet, das die ausführbare Datei und das Verknüpfungsformat abkennt. Es wird häufig für ausführbare Dateien, lockere Objektdateien, freigegebene Bibliotheken und Core -Dumps verwendet.

Vor zwanzig Jahren - 1999 - hat das 86OPEN -Projekt ELF als Standard -Binärdateiformat für UNIX- und UNIX -ähnliche Systeme auf X86 -Prozessoren ausgewählt. Glücklicherweise wurde das ELF -Format zuvor sowohl in der System -V -Anwendung Binary -Schnittstelle als auch im Standard -Grenzfläche dokumentiert [4]. Diese Tatsache hat die Übereinstimmung über die Standardisierung zwischen den verschiedenen Anbietern und Entwicklern von UNIX-basierten Betriebssystemen enorm vereinfacht.

Der Grund für diese Entscheidung war die Gestaltung von ELF - Flexibilität, Erweiterbarkeit und plattformübergreifende Unterstützung für verschiedene Endianformate und Adressgrößen. Das Design von ELF ist nicht auf einen bestimmten Prozessor, einen Anweisungssatz oder eine Hardwarearchitektur beschränkt. Für einen detaillierten Vergleich der ausführbaren Dateiformate schauen Sie hier an [3].

Seitdem wird das ELF -Format von mehreren verschiedenen Betriebssystemen verwendet. Dazu gehören unter anderem Linux, Solaris/Illumos, Free-, Net- und OpenBSD, QNX, Beos/Haiku und Fuchsia OS [2]. Darüber hinaus finden Sie es auf mobilen Geräten, die Android, Maemo oder Meego OS/Sailfish OS sowie auf Spielkonsolen wie PlayStation Portable, Dreamcast und Wii ausführen.

In der Spezifikation wird die Dateiname -Erweiterung für ELF -Dateien nicht klargestellt. Im Gebrauch sind eine Vielzahl von Buchstabenkombinationen, wie z .Axf, .Behälter, .Elf, .Ö, .prx, .Puff, .ko, .so und .Mod, oder keine.

Die Struktur einer ELF -Datei

Auf einem Linux -Terminal gibt Ihnen der Befehlsmann -Elf eine praktische Zusammenfassung zur Struktur einer ELF -Datei:

Listing 1: Die Manpage der Elf -Struktur

$ MAN ELF
ELF (5) Linux -Programmiererhandbuch Elf (5)
NAME
ELF -Format von ELF -Dateien (ausführbarer Format- und Verknüpfungsformat)
ZUSAMMENFASSUNG
#enthalten
BESCHREIBUNG
Die Header -Datei definiert das Format der ausführbaren Elfen -Binärdateien
Dateien. Unter diesen Dateien befinden sich normale ausführbare Dateien, die sich umschüssig machen
Objektdateien, Kerndateien und gemeinsame Bibliotheken.
Eine ausführbare Datei mit dem ELF -Dateiformat besteht aus einem ELF -Header,
gefolgt von einer Programmkopfzeile oder einer Abschnitts -Header -Tabelle oder beides.
Der ELF -Header befindet sich immer im Versatz Null der Datei. Das Programm
Headertabelle und der Offset des Abschnitts -Headertabelle in der Datei sind
im ELF -Header definiert. Die beiden Tabellen beschreiben den Rest der
Besonderheiten der Datei.

Wie Sie aus der obigen Beschreibung sehen können, besteht eine ELF -Datei aus zwei Abschnitten - einem ELF -Header und Dateidaten. Der Abschnitt "Dateidaten" kann aus einer Programmheader -Tabelle bestehen, in der Null oder mehr Segmente beschrieben werden. Jedes Segment enthält Informationen, die für die Ausführung der Laufzeit der Datei erforderlich sind, während Abschnitte wichtige Daten für die Verknüpfung und Verlagerung enthalten. Abbildung 1 zeigt dies schematisch.

Der Elf -Header

Der ELF -Header ist 32 Bytes lang und identifiziert das Format der Datei. Es beginnt mit einer Folge von vier eindeutigen Bytes, die 0x7f gefolgt von 0x45, 0x4c und 0x46 sind, was in die drei Buchstaben E, L und F übersetzt wird. Unter anderem gibt der Header auch an Rechtsanweisungssatz der rechten Anwendung Binary Interface (ABI) und CPU.

Der Hexdump der Binärdatei sieht sich wie folgt aus:

.Listing 2: Der Hexdump der Binärdatei

$ hd/usr/bin/touch | Kopf -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 00 00 00 00 00 00 00 00 00 |@… (… |
00000030 00 00 00 00 40 00 38 00 09 00 40 00 1B 00 1A 00 |… @ @.8… @… |
00000040 06 00 00 00 05 00 00 00 40 00 00 00 00 00 00 00 |… @… |

Debian GNU/Linux bietet den Befehl Readelf an, der im GNU -Paket "Binutils" bereitgestellt wird. Begleitet von der Switch -H (Kurzversion für „-File-Header“) zeigt die Header einer ELF-Datei gut an. Die Auflistung 3 zeigt dies für den Befehls Touch.

.Listing 3: Anzeigen des Header einer ELF -Datei

$ readelf -h/usr/bin/touch
Elf Header:
Magie: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
Klasse: ELF64
Daten: 2's Komplement, Little Endian
Version: 1 (aktuell)
OS/ABI: UNIX - System V
ABI -Version: 0
Typ: exec (ausführbare Datei)
Maschine: Erweiterte Mikrogeräte x86-64
Version: 0x1
Einstiegspunktadresse: 0x4025e3
Beginn der Programmheader: 64 (Bytes in die Datei)
Start der Abschnittsüberschriften: 58408 (Bytes in die Datei)
Flaggen: 0x0
Größe dieses Headers: 64 (Bytes)
Größe der Programmüberschriften: 56 (Bytes)
Anzahl der Programmüberschriften: 9
Größe der Abschnittsüberschriften: 64 (Bytes)
Anzahl der Abschnittsüberschriften: 27
Abschnitts -Header -Zeichenfolge -Tabellenindex: 26

Der Programmkopf

Der Programmheader zeigt die zur Laufzeit verwendeten Segmente und teilt dem System mit, wie ein Prozessbild erstellt wird. Der Header von Listing 2 zeigt, dass die ELF -Datei aus 9 Programmheadern mit jeweils 56 Bytes besteht, und der erste Header beginnt bei Byte 64.

Auch hier hilft der Befehl readelf, die Informationen aus der ELF -Datei zu extrahieren. Der Switch -L (kurz für -Programm -Header oder -segmente) enthält weitere Details, wie in Listing 4 gezeigt.

.Listing 4: Informationen zu den Programmheadern anzeigen

$ readelf -l/usr/bin/touch
Elf -Dateityp ist exec (ausführbare Datei)
Einstiegspunkt 0x4025e3
Es gibt 9 Programmheader, beginnend bei Offset 64
Programmheader:
Geben Sie Offset Virtaddr PhysAddr ein
Dateisize Memsiz Flags richten sich an
PHDR 0x0000000000000040 0x00000000400040 0x0000000000400040
0x000000000001f8 0x000000000001f8 R E 8
Interp 0x00000000000238 0x0000000000400238 0x0000000000400238
0x0000000000001c 0x000000000000001c R 1
[Anforderungsprogramm Dolmetscher: /lib64 /ld-linux-x86-64.So.2]
Laden 0x0000000000000000 0x0000000000400000 0x0000000000400000
0x000000000000D494 0x000000000000D494 R E 200000
Laden 0x000000000000DE10 0x0000000060DE10 0x000000000060DE10
0x00000000000524 0x00000000000748 RW 200000
Dynamisch 0x000000000000DE28 0x000000000060DE28 0x000000000060DE28
0x00000000000001d0 0x000000000001d0 RW 8
Hinweis 0x0000000000000254 0x0000000000400254 0x0000000000400254
0x00000000000044 0x0000000000000044 R 4
GNU_EH_FRAME 0X000000000000BC40 0x000000000040BC40 0x000000000040BC40
0x000000000003A4 0x000000000003A4 R 4
GNU_Stack 0x0000000000000000000000000000000000000000000000000000
0x00000000000000 0x0000000000000000 RW 10
GNU_RELRO 0x00000000000000DE10 0x0000000060DE10 0x000000000060DE10
0x000000000001f0 0x000000000001f0 R 1
Abschnitt zur Segmentzuordnung:
Segmentabschnitte…
00
01 .Interp
02 .Interp .Notiz.Abi-Tag .Notiz.Gnu.Build-id .Gnu.Hash .DynSym .Dynstr .Gnu.Ausführung .Gnu.Version_R .Rela.Dyn .Rela.PLT .drin .PLT .Text .Fini .Rodata .EH_FRAME_HDR .EH_FRAME
03 .init_array .Fini_Array .JCR .dynamisch .bekommen .bekommen.PLT .Daten .BSS
04 .dynamisch
05 .Notiz.Abi-Tag .Notiz.Gnu.Build-id
06 .EH_FRAME_HDR
07
08 .init_array .Fini_Array .JCR .dynamisch .bekommen

Der Abschnittskopf

Der dritte Teil der ELF -Struktur ist der Abschnittsübergang. Es soll die einzelnen Abschnitte der Binary auflisten. Der Switch -S (kurz für die Abschnitte oder -sektionen) listet die verschiedenen Header auf. Was den Touch -Befehl betrifft, so gibt es 27 Abschnitts -Header, und das Auflistung 5 zeigt die ersten vier von ihnen sowie die letzte, nur die letzten, nur. Jede Zeile deckt die Abschnittsgröße, den Abschnittstyp sowie die Adresse und den Speicherversatz ab.

.Listing 5: Abschnitt Details von Readelelf enthüllt

$ readelf -S/usr/bin/touch
Es gibt 27 Abschnittsüberschriften, beginnend bei Offset 0xE428:
Abschnittsüberschriften:
[Nr] Name Typ -Adresse Offset
Größe Inssize Flags Link Info ausrichten
[0] NULL 0000000000000000 000000000000
0000000000000000 0000000000000000 0 0 0 0
[1] .Interp Progbits 0000000000400238 00000238
000000000000001c 0000000000000000 A 0 0 1
[2] .Notiz.ABI-TAG Note 0000000000400254 00000254
0000000000000020 0000000000000000 A 0 0 4
[ 3] .Notiz.Gnu.Build-I Note 0000000000400274 00000274


[26] .Shstrtab Strtab 00000000000000000000e334
00000000000000EF 0000000000000000 0 0 1
Schlüssel zu Flaggen:
W (schreiben), a (alloc), x (ausführen), m (merge), s (saiten), l (groß)
I (info), l (Linkauftrag), g (Gruppe), t (tls), e (ausschließen), x (unbekannt)
O (zusätzliche Betriebssystemverarbeitung erforderlich) O (OS -spezifisch), P (Prozessorspezifisch)

Tools zur Analyse einer ELF -Datei

Wie Sie möglicherweise aus den obigen Beispielen festgestellt haben, ist GNU/Linux mit einer Reihe nützlicher Tools ausgewählt, mit denen Sie eine ELF -Datei analysieren können. Der erste Kandidat, den wir uns ansehen werden, ist das Dateidienstprogramm.

Die Datei zeigt grundlegende Informationen zu ELF -Dateien an, einschließlich der Anweisungssatzarchitektur, für die der Code in einer laufbaren, ausführbaren oder freigegebenen Objektdatei beabsichtigt ist. In Listing 6 wird angegeben, dass/bin/touch eine 64-Bit-ausführbare Datei nach der Linux Standard Base (LSB) ist, dynamisch verknüpft und für das GNU/Linux-Kernelversion 2 erstellt wurde.6.32.

.Listing 6: Grundlegende Informationen mit der Datei mit Datei

$ Datei /bin /touch
/bin/touch: ELF 64-Bit LSB Executable, x86-64, Version 1 (SYSV), dynamisch verknüpft, Interpreter/lib64/l,
Für GNU/Linux 2.6.32, Buildid [SHA1] = EC08D609E9E8E73D4BE6134541A472AD0EA34502, Stripped
$

Der zweite Kandidat ist Readelf. Es zeigt detaillierte Informationen zu einer ELF -Datei an. Die Liste der Schalter ist vergleichsweise lang und deckt alle Aspekte des ELF -Formats ab. Verwenden der Auflistung von Switch -n (kurz für -notes).

.Auflistung 7: Zeigen Sie ausgewählte Abschnitte einer ELF -Datei an

$ readelf -n/usr/bin/touch
Anzeigen von Notizen, die bei Dateiversatz 0x00000254 mit Länge 0x00000020 gefunden wurden:
Beschreibung der Besitzerdatengröße
GNU 0x00000010 NT_GNU_ABI_TAG (ABI -Versions -Tag)
OS: Linux, ABI: 2.6.32
Anzeigen von Notizen, die bei Dateiversatz 0x00000274 mit Länge 0x00000024 gefunden wurden:
Beschreibung der Besitzerdatengröße
Gnu 0x00000014 nt_gnu_build_id (eindeutige Build -ID -Bitstring)
Build ID: EC08D609E9E8E73D4BE6134541A472AD0EA34502

Beachten. Ab 2019 gibt es seit 2003 keine neue Veröffentlichung oder Aktualisierung nicht mehr.

Nummer drei ist das Paket namens Elfutils [6], das nur für Linux verfügbar ist. Es bietet alternative Tools für GNU Binutils und ermöglicht auch die Validierung von ELF -Dateien. Beachten Sie, dass alle Namen der im Paket angegebenen Dienstprogramme mit der EU für "ELF -Utils" beginnen.

Last but not least werden wir Objdump erwähnen. Dieses Tool ähnelt Readelf, konzentriert sich jedoch auf Objektdateien. Es bietet eine ähnliche Auswahl an Informationen zu ELF -Dateien und anderen Objektformaten.

.Listing 8: Dateiinformationen, die von Objdump extrahiert wurden

$ objdump -f /bin /touch
/bin/touch: Dateiformat ELF64-X86-64
Architektur: i386: x86-64, Flags 0x00000112:
EXEC_P, HAS_SYMS, D_PAGT
Startadresse 0x00000000004025e3
$

Es gibt auch ein Softwarepaket namens 'Elfkickers' [9], das Tools enthält, um den Inhalt einer ELF -Datei zu lesen und sie zu manipulieren. Leider ist die Anzahl der Veröffentlichungen ziemlich niedrig, und deshalb erwähnen wir sie nur und zeigen keine weiteren Beispiele an.

Als Entwickler können Sie sich stattdessen auf "Pax-Utils" [10,11] ansehen, stattdessen. Dieser Satz von Dienstprogrammen bietet eine Reihe von Tools, mit denen ELF -Dateien validiert werden können. Dumpelf analysiert beispielsweise die ELF -Datei und gibt eine C -Header -Datei mit den Details zurück - siehe Abbildung 2.

Abschluss

Dank einer Kombination aus cleverem Design und ausgezeichneter Dokumentation funktioniert das ELF -Format sehr gut und wird nach 20 Jahren immer noch verwendet. Die oben gezeigten Dienstprogramme ermöglichen Ihnen eine Einsichtsansicht in eine ELF -Datei und ermöglichen Sie heraus, was ein Programm tut. Dies sind die ersten Schritte zur Analyse von Software - Happy Hacking!

Links und Referenzen
  • [1] ausführbares und verknüpfbares Format (ELF), Wikipedia
  • [2] Fuchsia OS
  • [3] Vergleich der ausführbaren Dateiformate, Wikipedia
  • [4] Linux Foundation, Referenzierte Spezifikationen
  • [5] Ciro Santilli: Elf Hello World Tutorial
  • [6] Elfutils Debian -Paket
  • [7] Elfdump
  • [8] Michael Boelen: Die 101 der Elf -Dateien unter Linux: Verständnis und Analyse
  • [9] Elfkickers
  • [10] Härtung/PAX -Dienstprogramme
  • [11] Pax-Utils, Debian-Paket
Anerkennung

Der Schriftsteller möchte Axel Beckert für seine Unterstützung in Bezug auf die Vorbereitung dieses Artikels danken.