Einführung in Linux ELFs: Verstehen und Analysieren

Es gibt Dinge auf der Welt, die wir für selbstverständlich halten, obwohl sie wahre Meisterwerke sind. Eine solche Sache sind Linux-Dienstprogramme wie ls und ps. Obwohl sie normalerweise als einfach empfunden werden, ist dies weit davon entfernt, wenn wir nach innen schauen. Und ELF, Executable und Linkable Format auch. Ein Dateiformat, das universell verwendet wird, aber nur wenige verstehen es. Diese Kurzanleitung hilft Ihnen beim Verständnis.



Nachdem Sie diesen Leitfaden gelesen haben, lernen Sie Folgendes:

  • Warum wird das ELF-Format benötigt und für welche Dateitypen wird es verwendet?
  • ELF-Dateistruktur und Formatdetails
  • Lesen und Analysieren des binären Inhalts einer ELF-Datei
  • Mit welchen Tools werden Binärdateien analysiert?

Was ist eine ELF-Datei?


ELF steht für Executable and Linkable Format und definiert die Struktur von Binärdateien, Bibliotheken und Kerndateien. Die Formatspezifikation ermöglicht es dem Betriebssystem, die in der Datei enthaltenen Maschinenanweisungen korrekt zu interpretieren. Eine ELF-Datei ist normalerweise die Ausgabedatei eines Compilers oder Linkers und hat ein Binärformat. Mit geeigneten Werkzeugen kann es analysiert und untersucht werden.

Warum ELF im Detail studieren?


Bevor wir uns mit den technischen Details befassen, werden wir Ihnen unbedingt erklären, warum das Verständnis des ELF-Formats nützlich ist. Erstens können Sie den internen Betrieb des Betriebssystems untersuchen. Wenn etwas schief gelaufen ist, können Sie mit diesem Wissen besser nachvollziehen, was genau und aus welchem ​​Grund passiert ist. Die Möglichkeit, ELF-Dateien zu untersuchen, kann auch hilfreich sein, um Sicherheitslücken zu finden und verdächtige Dateien zu erkennen. Und schließlich zum besseren Verständnis des Entwicklungsprozesses. Selbst wenn Sie in einer höheren Sprache wie Go programmieren, wissen Sie immer noch besser, was sich hinter den Kulissen abspielt.

Warum also ELF studieren?

  • Für ein allgemeines Verständnis des Betriebssystems
  • Für die Softwareentwicklung
  • Digitale Forensik und Incident Response (DFIR)
  • Malware-Recherche (Binäranalyse)

Von der Quelle zum Prozess


Welches Betriebssystem wir auch verwenden, es ist notwendig, die Quellcodefunktionen in die CPU-Sprache zu übersetzen - Maschinencode. Die einfachsten Funktionen können beispielsweise das Öffnen einer Datei auf der Festplatte oder das Anzeigen von Elementen auf dem Bildschirm sein. Anstatt die CPU-Sprache direkt zu verwenden, verwenden wir eine Programmiersprache mit Standardfunktionen. Der Compiler übersetzt diese Funktionen dann in Objektcode. Dieser Objektcode wird dann über den Linker in das gesamte Programm eingebunden. Das Ergebnis ist eine Binärdatei, die auf einer bestimmten Plattform und einem bestimmten CPU-Typ ausgeführt werden kann.

Bevor du anfängst


Dieser Beitrag enthält viele Teams. Es ist besser, sie auf einem Testcomputer auszuführen. Kopieren Sie vorhandene Binärdateien, bevor Sie diese Befehle ausführen. Wir werden auch ein kleines C-Programm schreiben, das Sie kompilieren können. Letztendlich ist Übung der beste Weg, etwas zu lernen.

Anatomie einer ELF-Datei


Ein häufiges Missverständnis ist, dass ELF-Dateien nur für binäre oder ausführbare Dateien sind. Wir haben bereits gesagt, dass sie für Teile von ausführbaren Dateien (Objektcode) verwendet werden können. Ein weiteres Beispiel sind Bibliotheksdateien und Core-Dumps (Core-Dateien und a.out-Dateien). Die ELF-Spezifikation wird auch unter Linux für Kernel und Kernelmodule verwendet.



Struktur


Aufgrund der Erweiterbarkeit von ELF-Dateien kann die Struktur für verschiedene Dateien variieren. Die ELF-Datei besteht aus:

  1. ELF-Header
  2. Daten

Mit dem Befehl readelf können wir uns die Dateistruktur ansehen und sie sieht ungefähr so ​​aus:



ELF-Header


Wie Sie auf dem Screenshot sehen können, beginnt der ELF-Header mit einer „magischen Zahl“. Diese "magische Zahl" gibt Auskunft über die Datei. Die ersten 4 Bytes legen fest, dass es sich um eine ELF-Datei handelt (45 = E, 4c = L, 46 = F, vor 7f).

Der ELF-Header ist erforderlich. Dies ist erforderlich, damit die Daten während der Verknüpfung und Ausführung korrekt interpretiert werden. Zum besseren Verständnis des internen Betriebs einer ELF-Datei ist es hilfreich zu wissen, wofür diese Informationen verwendet werden.

Klasse


Nach der Deklaration eines ELF-Typs folgt ein Klassenfeld. Dieser Wert gibt die Architektur an, für die die Datei bestimmt ist. Dies kann 01 (32-Bit-Architektur) oder 02 (64-Bit) sein. Hier sehen wir 02, das vom Befehl readelf als ELF64-Datei übersetzt wird, dh, diese Datei verwendet eine 64-Bit-Architektur. Das ist nicht verwunderlich, denn in meinem Auto ist ein moderner Prozessor verbaut.

Daten


Als nächstes folgt das Datenfeld mit zwei Optionen: 01 - LSB (Least Significant Bit), auch bekannt als Little-Endian, oder 02 - MSB (Most Significant Bit, Big-Endian). Diese Werte helfen bei der Interpretation der übrigen Objekte in der Datei. Dies ist wichtig, da unterschiedliche Prozessortypen unterschiedlich mit Datenstrukturen umgehen. In unserem Fall wird LSB verwendet, da der Prozessor eine AMD64-Architektur hat.

Der LSB-Effekt wird sichtbar, wenn das Hexdump-Dienstprogramm für eine Binärdatei verwendet wird. Sehen wir uns den ELF-Header für / bin / ps an.

$ hexdump -n 16 /bin/ps 0000000 457f 464c 0102 0001 0000 0000 0000 0000 0000010 

Wir sehen, dass die Wertepaare aufgrund der Interpretation der Datenreihenfolge unterschiedlich sind.

Version


Dann folgt ein weiterer magischer Wert "01", der die Versionsnummer ist. Derzeit ist nur die Version 01 verfügbar, daher bedeutet diese Nummer nichts Interessantes.

OS / ABI


Jedes Betriebssystem hat seine eigene Art, Funktionen aufzurufen, sie haben viele Gemeinsamkeiten, aber darüber hinaus weist jedes System kleine Unterschiede auf. Die Reihenfolge des Funktionsaufrufs wird durch das Application Binary Interface (ABI) festgelegt. Die OS / ABI-Felder beschreiben, welches ABI verwendet wird und in welcher Version. In unserem Fall ist der Wert 00, was bedeutet, dass bestimmte Erweiterungen nicht verwendet werden. In der Ausgabe wird dies als System V angezeigt.

ABI-Version


Bei Bedarf kann eine ABI-Version angegeben werden.

Auto


Der Titel gibt auch den erwarteten Maschinentyp (AMD64) an.

Typ


Das Feld Typ gibt an, wofür die Datei bestimmt ist. Hier sind einige gebräuchliche Dateitypen.

KERN (Wert 4)
DYN (Shared Object File), Bibliothek (Wert 3)
EXEC (ausführbare Datei), ausführbare Datei (Wert 2)
REL (Relocatable file), Datei vor dem Verknüpfen (Wert 1)

Siehe den vollständigen Titel


Obwohl einige Felder über readelf angezeigt werden können, gibt es tatsächlich mehr. Sie können beispielsweise herausfinden, für welchen Prozessor die Datei bestimmt ist. Verwenden Sie hexdump, um den vollständigen ELF-Header und alle Werte anzuzeigen.

 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 |.ELF............| 02 00 3e 00 01 00 00 00 a8 2b 40 00 00 00 00 00 |..>......+@.....| 40 00 00 00 00 00 00 00 30 65 01 00 00 00 00 00 |@.......0e......| 00 00 00 00 40 00 38 00 09 00 40 00 1c 00 1b 00 |....@.8...@.....| 

(Ausgabe hexdump -C -n 64 / bin / ps)

Das hervorgehobene Feld bestimmt den Maschinentyp. Der Wert 3e ist dezimal 62, was AMD64 entspricht. Informationen zu allen Dateitypen finden Sie in dieser Header-Datei.

Obwohl Sie all dies in einem hexadezimalen Speicherauszug ausführen können, ist es sinnvoll, ein Tool zu verwenden, das die Arbeit für Sie erledigt. Das Dienstprogramm dumpelf kann nützlich sein. Es werden formatierte Ausgaben angezeigt, die mit dem ELF-Header übereinstimmen. Es ist gut zu untersuchen, welche Felder verwendet werden und welche typischen Werte sie haben.

Jetzt, wo wir die Bedeutung dieser Felder erklärt haben, ist es an der Zeit, zu schauen, was wahre Magie hinter ihnen steckt, und mit den nächsten Überschriften fortzufahren!

Dateidaten


Neben dem Header bestehen ELF-Dateien aus drei Teilen.

  • Programmüberschriften oder -segmente
  • Abschnitt oder Abschnittsüberschriften
  • Daten

Bevor wir uns mit diesen Überschriften befassen, ist es hilfreich zu wissen, dass die ELF-Datei zwei verschiedene „Typen“ hat. Eine davon ist für den Linker konzipiert und ermöglicht die Ausführung von Code (Segmente). Der andere ist für Befehle und Daten (Abschnitte). Je nach Verwendungszweck wird der entsprechende Headertyp verwendet. Beginnen wir mit dem Programmheader, der sich in den ausführbaren ELF-Dateien befindet.

Programmtitel


Eine ELF-Datei besteht aus null oder mehr Segmenten und beschreibt, wie ein Prozess erstellt wird, ein Speicherabbild für die Laufzeitausführung. Wenn der Kernel diese Segmente sieht, platziert er sie mithilfe des Systemaufrufs mmap (2) im virtuellen Adressraum. Mit anderen Worten, es konvertiert vorbereitete Anweisungen in ein Bild im Speicher. Wenn es sich bei der ELF-Datei um eine reguläre Binärdatei handelt, werden diese Programmheader benötigt, da sie sonst einfach nicht funktionieren. Diese Header bilden zusammen mit den entsprechenden Datenstrukturen den Prozess. Für gemeinsam genutzte Bibliotheken ist der Prozess ähnlich.


Programmkopf in binärer ELF-Datei

In diesem Beispiel sehen wir 9 Programmtitel. Zunächst ist es schwer zu verstehen, was sie bedeuten. Lassen Sie uns in die Details eintauchen.

GNU_EH_FRAME


Dies ist die sortierte Warteschlange, die vom GCC-Compiler verwendet wird. Es speichert Ausnahmebehandlungsroutinen. Wenn etwas schief gelaufen ist, werden sie verwendet, um die Situation richtig zu handhaben.

GNU_STACK


Dieser Header wird zum Speichern von Stack-Informationen verwendet. Interessant ist, dass der Stack nicht ausführbar sein muss, da dies zu Sicherheitslücken führen kann.

Wenn das GNU_STACK-Segment fehlt, wird der ausführbare Stapel verwendet. Die Dienstprogramme scanelf und execstack zeigen die Details des Stack-Geräts an.

 # scanelf -e /bin/ps TYPE STK/REL/PTL FILE ET_EXEC RW- R-- RW- /bin/ps # execstack -q /bin/ps - /bin/ps 

Befehle zum Anzeigen des Programmheaders:

  • dumpelf (pax-utils)
  • Elfen -S / bin / ps
  • eu-readelf -program-headers / bin / ps

ELF-Abschnitte


Abschnittsüberschriften


Abschnittsüberschriften definieren alle Abschnitte einer Datei. Wie bereits erwähnt, werden diese Informationen zur Verlinkung und zum Umzug verwendet.

Abschnitte werden in einer ELF-Datei angezeigt, nachdem der GNU C-Compiler C-Code in Assembler konvertiert und der GNU Assembler Objekte erstellt.

Wie in der obigen Abbildung gezeigt, kann ein Segment aus 0 oder mehr Abschnitten bestehen. Es gibt vier Hauptabschnitte für ausführbare Dateien: .text, .data, .rodata und .bss. Jeder dieser Abschnitte startet mit unterschiedlichen Berechtigungen, die mit readelf -S angezeigt werden können.

.text


Enthält ausführbaren Code. Es wird in ein Segment mit Lese- und Ausführungsrechten gepackt. Es wird einmal heruntergeladen und sein Inhalt ändert sich nicht. Dies kann mit dem Dienstprogramm objdump festgestellt werden.

 12 .text 0000a3e9 0000000000402120 0000000000402120 00002120 2**4 CONTENTS, ALLOC, LOAD, READONLY, CODE 

.data


Initialisierte Daten mit Lese- und Schreibrechten.

.rodata


Initialisierte Daten mit schreibgeschützten Berechtigungen. (= A).

.bss


Nicht initialisierte Daten mit Lese- / Schreibberechtigungen. (= WA)

 [24] .data PROGBITS 00000000006172e0 000172e0 0000000000000100 0000000000000000 WA 0 0 8 [25] .bss NOBITS 00000000006173e0 000173e0 0000000000021110 0000000000000000 WA 0 0 32 


Befehle zum Anzeigen von Abschnitten und Titeln.

  • dumpelf
  • elfls -p / bin / ps
  • eu-readelf –section-headers / bin / ps
  • readelf -S / bin / ps
  • objdump -h / bin / ps

Abschnittsgruppen


Einige Abschnitte können so gruppiert werden, als ob sie ein einzelnes Ganzes bilden würden. Neue Linker unterstützen diese Funktionalität. Dies ist jedoch nicht üblich.

 # readelf -g /bin/ps There are no section groups in this file. 

Obwohl dies nicht sehr interessant erscheint, bietet das Wissen über die ELF-Dateianalyse-Tools große Vorteile. Aus diesem Grund finden Sie am Ende des Artikels eine Übersicht über diese Tools und ihren Zweck.

Statische und dynamische Binärdateien


Wenn Sie mit ELF-Binärdateien arbeiten, ist es hilfreich zu wissen, wie diese beiden Dateitypen verknüpft sind. Sie können statisch und dynamisch sein, und dies gilt für die von ihnen verwendeten Bibliotheken. Wenn die Binärdatei "dynamisch" ist, werden externe Bibliotheken verwendet, die einige allgemeine Funktionen enthalten, z. B. das Öffnen einer Datei oder das Erstellen eines Netzwerk-Sockets. Statische Binärdateien enthalten dagegen alle erforderlichen Bibliotheken.

Wenn Sie prüfen möchten, ob die Datei statisch oder dynamisch ist, verwenden Sie den Befehl file. Sie wird so etwas zeigen:

 $ file /bin/ps /bin/ps: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), <b>dynamically linked (uses shared libs)</b>, for GNU/Linux 2.6.24, BuildID[sha1]=2053194ca4ee8754c695f5a7a7cff2fb8fdd297e, stripped 

Um festzustellen, welche externen Bibliotheken verwendet werden, verwenden Sie einfach ldd für dieselbe Binärdatei:

 $ ldd /bin/ps linux-vdso.so.1 => (0x00007ffe5ef0d000) libprocps.so.3 => /lib/x86_64-linux-gnu/libprocps.so.3 (0x00007f8959711000) libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f895934c000) /lib64/ld-linux-x86-64.so.2 (0x00007f8959935000) 

Tipp: Um weitere Abhängigkeiten anzuzeigen, ist es besser, das Dienstprogramm lddtree zu verwenden.

Tools für die binäre Analyse


Wenn Sie ELF-Dateien analysieren möchten, ist es auf jeden Fall hilfreich, sich zunächst die vorhandenen Tools anzusehen. Es gibt Toolkits für die umgekehrte Entwicklung von Binärdateien und ausführbarem Code. Wenn Sie mit der Analyse von ELF-Dateien noch nicht vertraut sind, beginnen Sie mit der statischen Analyse. Statische Analyse impliziert, dass wir Dateien untersuchen, ohne sie zu starten. Wenn Sie beginnen, ihre Arbeit besser zu verstehen, fahren Sie mit der dynamischen Analyse fort. Führen Sie die Beispiele aus und sehen Sie sich ihr tatsächliches Verhalten an.

Beliebte Tools


Radare2


Das Radare2-Toolkit wurde von Sergi Alvarez erstellt. Die Zahl 2 impliziert, dass der Code im Vergleich zur ersten Version vollständig umgeschrieben wurde. Jetzt wird es von vielen Forschern verwendet, um die Funktionsweise des Codes zu untersuchen.

Software-Pakete


Auf den meisten Linux-Systemen sind Binutils installiert. Mit anderen Paketen können Sie weitere Informationen anzeigen. Das richtige Toolkit vereinfacht Ihre Arbeit, insbesondere wenn Sie ELF-Dateien analysieren. Ich habe hier eine Liste von Paketen und Dienstprogrammen zum Analysieren von ELF-Dateien zusammengestellt.

elfutils
/ usr / bin / eu-addr2line
/ usr / bin / eu-ar - eine Alternative zu ar zum Erstellen und Verarbeiten von Archivdateien
/ usr / bin / eu-elfcmp
/ usr / bin / eu-elflint - Überprüfen Sie, ob die gABI- und psABI-Spezifikationen eingehalten werden
/ usr / bin / eu-findtextrel - Suche nach Textverlagerungen
/ usr / bin / eu-ld - kombiniert Objekt- und Archivdateien
/ usr / bin / eu-make-debug-archive
/ usr / bin / eu-nm - Zeigt die Symbole des Objekts und der ausführbaren Dateien an
/ usr / bin / eu-objdump - Zeigt Informationen aus der Objektdatei an
/ usr / bin / eu-ranlib - Erstellt einen Index der Archivdateien
/ usr / bin / eu-readelf - Zeigt die ELF-Datei in lesbarer Form an
/ usr / bin / eu-size - Zeigt die Größe der einzelnen Abschnitte an (Text, Daten, BSS usw.).
/ usr / bin / eu-stack - Zeigt den Stapel des aktuellen Prozesses oder Kernel-Dumps an
/ usr / bin / eu-strings - zeigt Textstrings an (wie das Strings-Dienstprogramm)
/ usr / bin / eu-strip - Entfernt die Zeichentabelle aus der ELF-Datei
/ usr / bin / eu-unstrip - fügt der Binärdatei Symbole und Debugging-Informationen hinzu
Hinweis: Das elfutils-Paket ist ein guter Anfang, es enthält die meisten Analyse-Tools

Elfkicker
/ usr / bin / ebfc - Brainfuck-Sprachcompiler
/ usr / bin / elfls - Zeigt Programm- und Abschnittsüberschriften mit Flags an
/ usr / bin / elftoc - konvertiert ein Binärprogramm in ein C-Programm
/ usr / bin / infect - Ein Dienstprogramm, das eine Pipette injiziert, erstellt eine Setuid-Datei in / tmp
/ usr / bin / objres - Erstellt ein Objekt aus regulären oder binären Daten
/ usr / bin / rebind - Ändert die Bindung und Sichtbarkeit von Zeichen in ELF-Dateien
/ usr / bin / sstrip - Entfernt unnötige Komponenten aus einer ELF-Datei
Hinweis: Der Autor des ELFKickers-Pakets konzentriert sich auf die Bearbeitung von ELF-Dateien, sodass Sie mehr Informationen erhalten, wenn Sie mit den „falschen“ ELF-Binärdateien arbeiten

pax-utils
/ usr / bin / dumpelf - Dump der internen ELF-Struktur
/ usr / bin / lddtree - wie bei ldd, wobei der Grad der angezeigten Abhängigkeiten festgelegt wird
/ usr / bin / pspax - Zeigt ELF / PaX-Informationen zu laufenden Prozessen an
/ usr / bin / scanelf - eine breite Palette von Informationen, einschließlich PaX-Details
/ usr / bin / scanmacho - zeigt Details der Mach-O-Binärdateien (Mac OS X)
/ usr / bin / symtree - zeigt Baumzeichen an
Hinweis: Einige Dienstprogramme in diesem Paket können Verzeichnisse rekursiv durchsuchen und eignen sich ideal zum Analysieren des gesamten Inhalts eines Verzeichnisses. Der Schwerpunkt liegt auf PaX-Recherchetools. Zusätzlich zur Unterstützung von ELF können Sie Informationen aus Mach-O-Binärdateien extrahieren.

Ausgabebeispiel
 scanelf -a /bin/ps TYPE PAX PERM ENDIAN STK/REL/PTL TEXTREL RPATH BIND FILE ET_EXEC PeMRxS 0755 LE RW- R-- RW- - - LAZY /bin/ps 


Prelink
/ usr / bin / execstack - Sie können Informationen darüber anzeigen oder ändern, ob der Stack ausführbar ist
/ usr / bin / prelink - verschiebt Aufrufe in ELF-Dateien, um den Prozess zu beschleunigen

Häufig gestellte Fragen


Was ist ein ABI?


ABI ist die Application Binary Interface und definiert eine Low-Level-Schnittstelle zwischen dem Betriebssystem und dem ausführbaren Code.

Was ist ELF?


ELF ist ein ausführbares und verknüpfbares Format. Dies ist eine Formatspezifikation, die definiert, wie Anweisungen in ausführbaren Code geschrieben werden.

Wie kann ich den Dateityp sehen?


Verwenden Sie den Befehl file für die erste Stufe der Analyse. Dieser Befehl kann die Details anzeigen, die aus den "magischen" Zahlen und Überschriften extrahiert wurden.

Fazit


ELF-Dateien dienen zur Ausführung und Verknüpfung. Sie enthalten je nach Verwendungszweck die erforderlichen Segmente und Abschnitte. Der Kernel des Betriebssystems durchsucht die Segmente und ordnet sie dem Speicher zu (mit mmap). Abschnitte werden von einem Linker angezeigt, der eine ausführbare Datei oder ein freigegebenes Objekt erstellt.

ELF-Dateien sind sehr flexibel und unterstützen verschiedene Arten von CPUs, Maschinenarchitekturen und Betriebssystemen. Es ist auch erweiterbar, jede Datei ist unterschiedlich gestaltet, abhängig von den benötigten Teilen. Mit den richtigen Tools können Sie den Zweck der Datei herausfinden und den Inhalt der Binärdateien untersuchen. Sie können die in der Datei enthaltenen Funktionen und Zeilen anzeigen. Ein guter Anfang für diejenigen, die nach Malware suchen oder verstehen, warum sich der Prozess auf eine bestimmte Weise verhält (oder nicht).

Ressourcen für weitere Studien


Wenn Sie mehr über ELF und Reverse Engineering erfahren möchten, können Sie sich die Arbeit ansehen, die wir in Linux Security Expert leisten. Im Rahmen des Lehrplans verfügen wir über ein Reverse Engineering-Modul mit praktischer Laborarbeit.

Für diejenigen unter Ihnen, die es lieben zu lesen, ein gutes und tiefes Dokument: ELF Format und ein von Brian Raiter verfasster Artikel, auch bekannt als ELFkickers. Wer die Quelle verstehen möchte, sollte sich den dokumentierten ELF-Header von Apple ansehen.

Tipp:
Wenn Sie das Analysieren von Dateien verbessern möchten, können Sie die gängigen Analysetools verwenden , die derzeit verfügbar sind.

Source: https://habr.com/ru/post/de480642/


All Articles