Diassemblieren: Unterschied zwischen den Versionen

Aus C und Assembler mit Raspberry
KKeine Bearbeitungszusammenfassung
KKeine Bearbeitungszusammenfassung
Zeile 1: Zeile 1:
== 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.
<syntaxhighlight lang="shell">
objdump -d ./blink
</syntaxhighlight>
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:
<syntaxhighlight lang="shell">
objdump -d -M reg-names=std ./blink
</syntaxhighlight>
=== gdb ===
Mit `gdb` (GNU Debugger) kannst du direkt im Programmfluss disassemblieren.
<syntaxhighlight lang="shell">
gdb ./blink
(gdb) disassemble _start
</syntaxhighlight>
== Praktische Tipps ==
* 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:
<syntaxhighlight lang="shell">
objdump -D -b binary -m aarch64 your.bin
</syntaxhighlight>
== 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 ===
<syntaxhighlight lang="shell">
objdump [OPTIONEN] DATEI
</syntaxhighlight>
=== 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
```bash
objdump -d ./blink
```
#### Ohne Register-Aliase (z. B. `wzr` statt `w0`)
```bash
objdump -d -M no-aliases ./blink
```
#### Mit klassischen Register-Namen (x0–x30)
```bash
objdump -d -M reg-names=std ./blink
```
#### Nur `.text`-Sektion
```bash
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:
```bash
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 ==
== Diassemblieren ==
-> objdump -s -d HelloWorld.o > HelloWorld.diassem
-> objdump -s -d HelloWorld.o > HelloWorld.diassem

Version vom 10. April 2025, 13:36 Uhr

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 ./blink

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 ./blink

gdb

Mit `gdb` (GNU Debugger) kannst du direkt im Programmfluss disassemblieren.

gdb ./blink
(gdb) disassemble _start

Praktische Tipps

  • 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


---

      1. Beispiele für ARM64
        1. Einfaches Disassemblieren

```bash objdump -d ./blink ```

        1. Ohne Register-Aliase (z. B. `wzr` statt `w0`)

```bash objdump -d -M no-aliases ./blink ```

        1. Mit klassischen Register-Namen (x0–x30)

```bash objdump -d -M reg-names=std ./blink ```

        1. Nur `.text`-Sektion

```bash objdump -d --section=.text ./blink ```

        1. Disassemblieren roher Binärdaten

Wenn du z. B. ein 1:1-Memory-Dump oder reinen Maschinencode ohne ELF-Struktur hast: ```bash objdump -D -b binary -m aarch64 yourfile.bin ```

---

      1. 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`).

---

    1. Die `-s` Option: Rohdaten anzeigen

Die Option `-s` (kurz für `--full-contents`) zeigt den **Hexdump des gesamten Inhalts** der Datei, geordnet nach Sektionen.

      1. Beispiel:

```bash objdump -s ./blink ```

      1. Beispielausgabe:

```text Contents of section .text:

0000 52800000 d2800021 d2800442 d2800003  R...!...B....
0010 d2800004 8b030084 d2800025 d2800026  .........%...&

```

      1. Bedeutung:

- Linke Spalte: Offset innerhalb der Sektion. - Rechte Spalten: Hex-Werte der Bytes. - Ganz rechts (manchmal): ASCII-Darstellung, wenn druckbar.

---

    1. 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.

---

    1. 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 |

---

      1. Bonus: Nur Funktionssymbol disassemblieren

Wenn du Symbole hast (nicht `strip` benutzt): ```bash objdump -d ./blink --disassemble=_start ```

---

      1. 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