Skip to content

Stack-Strings und dekodierte Strings in Malware finden

Warum Malware ihre Strings versteckt, wie Stack-Strings, Tight Strings und dekodierte Strings funktionieren und wie Emulation sie ohne Ausführung zurückgewinnt.

Veröffentlicht am 4 Min. Lesezeit

Kurz gesagt. Einfache String-Extraktion findet nur Text, der unverändert in der Datei steht. Malware versteckt ihre interessanten Strings — C2-Adressen, Mutex-Namen, Befehle — oft, indem sie sie auf dem Stack baut oder zur Laufzeit dekodiert. Wer den Code emuliert, der sie baut, gewinnt die meisten zurück, ohne das Sample auszuführen. Der PE Parser macht das im Tab Code-Analyse, im Sinne von Mandiants FLOSS.

Was strings sieht und was nicht

Eine String-Extraktion durchsucht die Datei nach Folgen druckbarer Zeichen (ASCII, UTF-16). Das ist schnell und findet viel: Importnamen, Fehlermeldungen, Pfade, URLs im Klartext. Genau deshalb verstecken Autoren die Strings, auf die es ankommt. Drei Techniken decken das meiste ab:

  • Stack-Strings. Der Code schreibt die Zeichen einzeln in einen lokalen Puffer: mov byte [ebp-0x20], 'h', mov byte [ebp-0x1f], 't'… Der Text existiert nur im Speicher, solange die Funktion läuft. In der Datei sieht man eine Folge von Instruktionen, keinen String.
  • Tight Strings. Ein Stack-String, der selbst kodiert ist und kurz vor der Verwendung von einer kurzen Schleife in derselben Funktion dekodiert wird — typischerweise ein XOR mit konstantem Schlüssel.
  • Dekodierte Strings. Die Strings liegen verschlüsselt im Datenabschnitt, und eine Dekodierfunktion macht sie bei Bedarf lesbar. Sie wird von vielen Stellen aufgerufen, jedes Mal mit einem anderen verschlüsselten Block, und liefert oder schreibt den Klartext.

Alle drei hebeln die statische Extraktion aus, und alle drei sind für jeden sichtbar, der nachvollzieht, was der Code tut.

Wie Emulation sie zurückgewinnt

Ein Emulator ist eine CPU in Software: Er liest jede Instruktion, aktualisiert simulierte Register und Speicher und geht weiter. Nichts erreicht den echten Prozessor oder das Betriebssystem — Aufrufe von Windows-Funktionen beantworten Stubs mit plausiblen Werten (ein neuer Puffer für eine Speicherreservierung, ein Erfolgscode für den Rest). Die Analyse des PE Parser arbeitet in drei Durchgängen:

  1. Funktionen finden. Ab Einsprungpunkt, Exporten, TLS-Callbacks und jedem direkten Aufruf folgt sie dem Code und findet Funktionen und deren Aufrufe.
  2. Stack- und Tight Strings. Jede Funktion wird ab ihrem Anfang für eine begrenzte Zahl von Instruktionen emuliert; druckbarer Text, der in ihrem Stack-Frame entsteht, wird gesammelt, vor und nach einer Dekodierschleife.
  3. Dekodierte Strings. Funktionen, die wie Decoder aussehen — ein XOR in einer Schleife, klein, von mehreren Stellen aufgerufen —, werden von jeder Aufrufstelle aus emuliert, mit den Argumenten, die der Aufrufer vorbereitet hat. Text, den der Decoder in den Speicher schreibt, wird gesammelt, zusammen mit der Adresse des Decoders.

Gemeldet wird nur Text, den eine einfache Extraktion nicht sehen konnte — die Liste bleibt kurz und relevant.

Im PE Parser

  • Öffnen Sie eine native 32- oder 64-Bit-Datei und wechseln Sie zum Tab Code-Analyse. Die Analyse läuft im Browser, für die meisten Dateien in wenigen hundert Millisekunden.
  • Wiederhergestellte Strings erscheinen mit ihrer Art (dekodiert, Stack, enge Schleife) und der Funktion, die sie gebaut hat. Ein Klick auf die Adresse öffnet dort das Disassembly.
  • Strings, die noch kodiert wirken (vor allem Sonderzeichen), sind standardmäßig ausgeblendet; ein Kästchen zeigt sie an.
  • Netzwerkindikatoren unter den wiederhergestellten Strings — URLs, Domains, IP-Adressen — landen im Tab IOCs und in dessen Exporten (IOCs exportieren).
  • Für eine ganze Sammlung nutzen Sie Code-Analyse in der Werkzeugleiste: Jede native Datei wird verarbeitet, und eine Spalte Code zeigt, wie viele Fähigkeiten und Strings jede enthält.

Derselbe Tab listet die im Code gefundenen Fähigkeiten: Anti-Debugging-Prüfungen, Prozessinjektion, API-Hashing, Krypto-Konstanten (MD5, SHA, CRC32, TEA, RC4, AES), Keylogging-Hooks und mehr, jeweils zugeordnet zu MITRE ATT&CK und dem Malware Behavior Catalog, mit den Funktionen, in denen sie gefunden wurden.

Grenzen

  • Gepackte Dateien. Ist der Code gepackt, emuliert man den Entpacker-Stub, nicht das Programm. Erst entpacken — UPX erledigt der PE Parser selbst (gepackte Executables erkennen).
  • Instruktionsabdeckung. Der Emulator deckt gewöhnlichen Ganzzahl-x86-/x64-Code ab. Decoder, die Gleitkomma- oder SIMD-Instruktionen nutzen, werden übersprungen.
  • Schlüssel von außen. Ein Decoder, dessen Schlüssel zur Laufzeit aus dem Netz, der Registry oder einer Datei kommt, lässt sich statisch nicht auflösen.
  • Budgets. Jede Emulation ist begrenzt, damit eine feindliche Datei die Seite nicht blockiert; sehr große Programme werden eventuell nur teilweise analysiert, und der Tab sagt es.

Wenn diese Grenzen greifen, ist die Sandbox der nächste Schritt: das Sample isoliert ausführen und seinen Speicher sichern. Für die große Mehrheit gängiger Malware gewinnt die Emulation die nötigen Strings jedoch in Sekunden zurück — ohne dass das Sample je läuft.

Verwandte Artikel

Statische Triage von Windows-Executables mit dem kostenlosen PE Parser: Dateien oder ZIP laden, Indikatoren lesen, Builds vergleichen, exportieren.
Verdächtige EXE-, DLL- und SYS-Dateien von einem Windows-Host oder Image finden und kopieren, ohne sie auszuführen: PowerShell, Velociraptor, Images.
Statische Hinweise auf gepackte Windows-Executables – Section-Namen, Entropie, W+X, Entry Point, Importe, Overlay – und ihre Fallstricke.