Diassemblieren
Einleitung
Das Disassemblieren ist der Prozess, bei dem aus Maschinencode wieder menschenlesbarer Assembler-Code erzeugt wird. Es ist ein wichtiges Werkzeug für:
- Debugging: Nachvollziehen, was das Programm tatsächlich macht.
- Reverse Engineering: Verstehen fremder Binärdateien.
- Optimierung: Erkennen ineffizienter Codeabschnitte.
- Lernen: Verstehen, wie Hochsprachen wie C übersetzt werden.
Werkzeuge
Für ARM64 unter Linux – z. B. auf dem Raspberry Pi – bieten sich diese Tools an:
objdump
Teil von `binutils`. Zeigt dir den Assembler-Code aus Objektdateien oder Binärprogrammen an. Dies ist auch meine bevorzugte Art, um etwas zu Diassemblieren.
objdump -d ./program
Optionen:
- `-d` disassembliert ausführbare Abschnitte.
- `-M reg-names=std` (optional): zeigt Standard-Registerbezeichnungen (x0–x30).
- `-M no-aliases` (zeigt die "echten" Instruktionsnamen statt Pseudonyme).
Beispiel:
objdump -d -M reg-names=std ./program
gdb
Mit `gdb` (GNU Debugger) kannst du direkt im Programmfluss disassemblieren.
gdb ./program
(gdb) disassemble _start
Praktische Tipps
- Möchtest du den Code in einem Editor ansehen, kannst du die Ausgabe in eine Datei leiten:
objdump -d -M reg-names=std ./program > program.diassem
- Achte auf die Sectionen: `.text` ist der Code, andere wie `.data` oder `.bss` enthalten keine Instruktionen.
- Prüfe, ob deine Datei nicht mit Strip bearbeitet wurde (`strip` entfernt Debugsymbole).
- Wenn du aus einer reinen Binärdatei (ohne ELF-Header) disassemblieren willst, nutze `objdump` mit `--target binary` und `--architecture aarch64`.
Beispiel:
objdump -D -b binary -m aarch64 your.bin
Worauf achten?
- Alignment: ARM64 nutzt 4-Byte ausgerichtete Instruktionen.
- Branch-Adressen: Bei `b`, `bl`, `cbz`, `ret` und Co. kannst du nachvollziehen, wo dein Programm hin springt.
- System Calls: erkenne z. B. `mov x8, #93; svc 0` als `exit(0)`.
- Speicherzugriffe: beachte, welche Register für Adressierung verwendet werden.
`objdump` im Detail: Parameter und ihre Bedeutung
`objdump` ist ein sehr vielseitiges Werkzeug. Besonders beim Disassemblieren von ARM64-Binärdateien ist es hilfreich, die wichtigsten Optionen zu kennen.
Grundstruktur des Befehls
objdump [OPTIONEN] DATEI
Wichtige Optionen beim Disassemblieren
| Option | Beschreibung |
|---|---|
| `-d` | Disassembliert alle **ausführbaren Segmente** (z. B. `.text`). |
| `-D` | Disassembliert **die gesamte Datei**, auch nicht-ausführbare Abschnitte. Nützlich bei rohen Binärdateien oder unüblichen Formaten. |
| `-M <option>` | Legt das Disassemblierungsformat fest. Mehrere Optionen sind durch Kommas trennbar (z. B. `-M reg-names=std,no-aliases`). |
| `--section=<name>` | Disassembliert **nur eine bestimmte Sektion**, z. B. `.text`. |
| `--start-address=0xADDR` | Beginnt das Disassemblieren **ab dieser Adresse**. |
| `--stop-address=0xADDR` | Hört bei dieser Adresse auf. |
| `--architecture=aarch64` | Setzt die Architektur explizit, z. B. bei rohen Binärdateien. |
| `-b binary` | Interpretiert die Datei als **rohe Binärdaten** (keine ELF-Struktur). |
| `-s` | Rohdaten anzeigen |
Beispiele für ARM64
Einfaches Disassemblieren
objdump -d ./blink
Ohne Register-Aliase (z. B. `wzr` statt `w0`)
objdump -d -M no-aliases ./blink
Mit klassischen Register-Namen (x0–x30)
objdump -d -M reg-names=std ./blink
Nur `.text`-Sektion
objdump -d --section=.text ./blink
Disassemblieren roher Binärdaten
Wenn du z. B. ein 1:1-Memory-Dump oder reinen Maschinencode ohne ELF-Struktur hast:
objdump -D -b binary -m aarch64 yourfile.bin
Option `-M` im Detail
`-M` steht für **Disassembler-Modifikatoren** – mehrere können kombiniert werden:
- `no-aliases`
- Zeigt dir "echte" Instruktionen, keine Vereinfachungen.
- > Beispiel: Statt `mov x0, x1` sieht man `orr x0, x1, xzr`.
- `reg-names=std`
- Standardregister (x0–x30, sp, pc).
- `reg-names=raw`
- Zeigt numerische Register: `r0`, `r1`, ...
- `reg-names=apcs`
- Zeigt Register gemäß dem **ARM Procedure Call Standard** (z. B. `a1`, `v1`, `fp`, `lr`).
---
- Die `-s` Option: Rohdaten anzeigen
Die Option `-s` (kurz für `--full-contents`) zeigt den **Hexdump des gesamten Inhalts** der Datei, geordnet nach Sektionen.
- Beispiel:
```bash objdump -s ./blink ```
- Beispielausgabe:
```text Contents of section .text:
0000 52800000 d2800021 d2800442 d2800003 R...!...B.... 0010 d2800004 8b030084 d2800025 d2800026 .........%...&
```
- Bedeutung:
- Linke Spalte: Offset innerhalb der Sektion. - Rechte Spalten: Hex-Werte der Bytes. - Ganz rechts (manchmal): ASCII-Darstellung, wenn druckbar.
---
- Kombination mit `-d` und `-s`
Oft ist es sinnvoll, `-d` und `-s` **gemeinsam** zu nutzen – z. B., um zu sehen, wie ein Maschinenbefehl wirklich kodiert ist:
```bash objdump -ds ./blink ```
Oder: gezielt auf eine bestimmte Sektion fokussieren: ```bash objdump -s --section=.rodata ./blink ```
So kannst du **Strings, Konstanten oder Sprungtabellen** sichtbar machen, die nicht disassembliert, aber trotzdem mitverarbeitet werden.
---
- Zusammenfassung – wann `-s` nützlich ist:
| Situation | Warum `-s` sinnvoll ist | |----------|--------------------------| | Debugging von Konstanten/Strings | Gibt Einblick in `.rodata`, `.data`, `.bss` etc. | | Verstehen von Maschineninstruktionen | Hex-Werte → ARM64-Opcode | | Analyse von Binärdateien ohne Symbole | Du siehst trotzdem, **was im Speicher liegt** | | Reverse Engineering | Hex-Dumps helfen, Kontrollstrukturen und Datenlayout zu erkennen |
---
- Bonus: Nur Funktionssymbol disassemblieren
Wenn du Symbole hast (nicht `strip` benutzt): ```bash objdump -d ./blink --disassemble=_start ```
---
- Abschluss: Tipps
- Wenn deine Datei keine Symbole enthält, verwende zusätzlich `nm` oder `readelf`, um Adressen herauszufinden. - Kombiniere `objdump` mit `grep` zur gezielten Analyse:
```bash objdump -d ./blink | grep "<_start>" ```
Diassemblieren
-> objdump -s -d HelloWorld.o > HelloWorld.diassem
Hello.o: file format elf64-littleaarch64
Contents of section .text:
0000 200080d2 e1000058 a20180d2 080880d2 ......X........ 0010 010000d4 000080d2 a80b80d2 010000d4 ................ 0020 00000000 00000000 ........
Contents of section .data:
0000 48656c6c 6f20576f 726c6421 0a Hello World!.
Disassembly of section .text:
0000000000000000 <_start>:
0: d2800020 mov x0, #0x1 // #1 4: 580000e1 ldr x1, 20 <_start+0x20> 8: d28001a2 mov x2, #0xd // #13 c: d2800808 mov x8, #0x40 // #64 10: d4000001 svc #0x0 14: d2800000 mov x0, #0x0 // #0 18: d2800ba8 mov x8, #0x5d // #93 1c: d4000001 svc #0x0
...
negative Zahlen
-> Beispiel: 5 + -3
3 in 1 byte is 0x03 or 0000 0011. Inverting the bits is 1111 1100 Add 1 to get 1111 1101 = 0xFD Now add 5 + 0xFD = 0x102 = 2
movadd.o: file format elf64-littleaarch64
Contents of section .text:
0000 001980d2 812580d2 0200018b a00080d2 .....%.......... 0010 41008092 0200018b 000080d2 a80b80d2 A............... 0020 010000d4 ....
Disassembly of section .text:
0000000000000000 <_start>:
0: d2801900 mov x0, #0xc8 // #200 4: d2802581 mov x1, #0x12c // #300 8: 8b010002 add x2, x0, x1 c: d28000a0 mov x0, #0x5 // #5 10: 92800041 mov x1, #0xfffffffffffffffd // #-3 14: 8b010002 add x2, x0, x1 18: d2800000 mov x0, #0x0 // #0 1c: d2800ba8 mov x8, #0x5d // #93 20: d4000001 svc #0x0