Skip to content
shellcodes

Linux-Shellcode erklärt: von C zu Bytes

Wie Linux-Shellcode funktioniert — Syscalls, Register und positionsunabhängiger Code — und wie man ihn sicher assembliert, kodiert und testet.

Veröffentlicht am 2 Min. Lesezeit

Linux-Shellcode ist klein, weil der Kernel die Hauptarbeit über Syscalls erledigt. Du linkst nicht gegen libc; du richtest Register ein und fragst den Kernel direkt. Wenn das Wort "Shellcode" neu ist, lies zuerst Was Shellcode ist.

Syscalls: x86 vs. x64

Die beiden Architekturen unterscheiden sich in drei Dingen, die für Shellcode wichtig sind:

x86x64
Syscall-Instruktionint 0x80syscall
Syscall-Nummereaxrax
Argumenteebx, ecx, edx, …rdi, rsi, rdx, …

execve ist Syscall 11 auf x86 und 59 auf x64. Nimmst du die Nummer für die falsche Architektur, rufst du etwas Unerwartetes auf — ein häufiger Anfängerfehler.

Positionsunabhängiger Code

Deine Bytes landen an einer Adresse, die du nicht kontrollierst, also kannst du keine Pointer fest kodieren. Der Standardtrick für Strings ist, sie auf den Stack zu schieben und ein Register auf den Stack zeigen zu lassen:

xor eax, eax
push eax            ; terminator
push 0x68732f2f     ; "//sh"
push 0x6e69622f     ; "/bin"
mov ebx, esp        ; ebx now points at the string, wherever it is

Keine .data-Sektion, keine absolute Adresse — es funktioniert, egal wo der Code läuft.

Null-Bytes vermeiden

xor eax, eax statt mov eax, 0 ist kein Stil; die zweite Form assembliert mit Null-Bytes, die die stringbasierte Auslieferung brechen. Die ganze Kunst von kompaktem Linux-Shellcode besteht darin, die Logik richtig hinzubekommen und dabei verbotene Bytewerte zu umgehen. Siehe Null-Bytes in Shellcode.

Zu Bytes assemblieren

Schreibe das Assembly, assembliere es und extrahiere dann die .text-Bytes. Die Logik zuerst in C zu prototypisieren ist ein guter Weg, die richtigen Syscalls und Argumente zu finden, bevor du das Assembly von Hand feinabstimmst. Funktionierende Beispiele mit vollständigen Byte-Strings stehen in den Shellcode-Beispielen.

Reihenfolge der Encoder-Pässe

Wenn dein Ziel bestimmte Bytes verbietet, kodierst du — aber die Encoder-Reihenfolge zählt: Ein zweiter Pass kann Bytes wieder einführen, die der erste entfernt hat. Daran scheitern viele; die Begründung steht in Reihenfolge der Encoder-Pipeline.

Testen

Assembliere, kodiere für dein Bad-Char-Set und verifiziere — alles client-seitig — im Shellcodes-Builder, und führe ihn dann nur in einer isolierten Lab-VM aus, die du kontrollierst. Nur autorisiertes Testen: verantwortungsvolle Nutzung.

Verwandte Artikel

Kommentierte Shellcode-Beispiele für Linux x86 und x64 — execve /bin/sh und Reverse TCP — mit den Bytes, der Disassemblierung und den Fallstricken.
Rohe Shellcode-Bytes zurück in Assembly verwandeln — Hex- und Escape-Formate dekodieren, mit Capstone disassemblieren und Bad Chars finden, bevor du ihn ausführst.
Wege zum Erzeugen von Shellcode im Vergleich — msfvenom, handgeschriebenes Assembly und ein browserbasierter Generator — mit den Abwägungen und wann man welchen nutzt.