Ein NOP hat meine YARA-Regel nicht gebrochen. Eine einzige Encoding-Änderung schon.
Sicherheit Engineering 9. August 2026

Ein NOP hat meine YARA-Regel nicht gebrochen. Eine einzige Encoding-Änderung schon.

Eine Untersuchung auf Byte-Ebene für Detection Engineers: Warum ein eingefügter NOP eine YARA-Hex-Regel intakt lässt, während eine einzige äquivalente x86-64-Encoding-Änderung sie aushebelt – reproduziert mit Aether 1.0.0 als Referenzimplementierung.

C
Christian Schnapka
Macstab Engineering
6 Min. Lesezeit
Auch auf Medium Auf Medium lesen

Eine Signatur fixiert einen einzigen Punkt im Encoding-Raum

Eine YARA-Hex-Regel ist ein syntaktisches Prädikat über einem Byte-Puffer. Was sie erkennen soll, ist ein semantisches Objekt, etwa eine Funktion, die 7 zurückgibt. Zwischen diesen beiden Ebenen liegt die bestimmende Eigenschaft von x86-64: ein Encoding variabler Länge, in dem die Abbildung von Byte-Folgen auf architektonische Effekte massiv viele-auf-eins ist. RAX auf 7 setzen und zurückkehren hat, vorsichtig geschätzt, mehr als ein Dutzend gültiger Encodings.

Eine Signatur fixiert einen Punkt in diesem Raum. Die gesamte Aufgabe eines Mutators besteht darin, zu einem anderen Punkt zu wandern. Die naheliegende Annahme – einen NOP einfügen, Hash und Größe ändern, und die Identitätsregel ist ausgehebelt – misst deshalb auf der falschen Ebene. Die Frage ist nie, ob sich irgendwelche Bytes verschoben haben. Sie lautet, ob der exakte Punkt, den die Regel fixiert, noch irgendwo im Puffer vorkommt – und ob die Regel einen Punkt oder eine Familie fixiert.

Dies ist eine x86-64-Laboranalyse für die autorisierte Bewertung von Detections, mit Aether 1.0.0 und Zydis v4.1.1 als reproduzierbarer Referenzimplementierung. Sie beansprucht weder beliebige .text-Semantik noch allgemeines Binary-Rewriting noch die Umgehung irgendeines Sicherheitsprodukts.

Diagramm, das die Identitätsebene (SHA-256, Größe, Hex-Dump, YARA-String-Match) der semantischen Ebene (Multi-Input-Orakel, Simulator, native Ausführung) gegenüberstellt
Identitätsebene gegenüber semantischer Ebene: Eine Byte-Signatur und ein Verhaltensorakel beobachten unterschiedliche Dinge.

Sechs Bytes, ein NOP, trotzdem ein Treffer

Die Testfunktion besteht aus sechs Bytes: B8 07 00 00 00 C3, also mov eax, 7; ret. Die Lehrregel matcht genau diese Bytes, zusammenhängend. Sie ist eine reine Laborregel, keine Produktionssignatur; ihr Wert liegt darin, die Identitätsebene sichtbar zu machen.

Der erste SAFE-Lauf mit Seed 42 erzeugte 90 B8 07 00 00 00 C3: ein Ein-Byte-NOP vor dem unveränderten Original. Der Hash hat sich geändert, die Größe hat sich geändert, der Rückgabewert stimmt weiterhin, und die Regel matcht trotzdem, weil die sechs Byte lange Nadel ein Byte weiter hinten intakt ist.

Der Grund ist mechanisch. YARA zerlegt das Muster in kurze Atome, typischerweise Teilfolgen von bis zu vier Bytes wie 07 00 00 00, legt sie in einem Aho-Corasick-Automaten ab und führt die vollständige Prüfung nur an Atom-Treffern aus. Der Automat ist positionsunabhängig, eine Verschiebung um ein Byte ändert also nichts. Die Konsequenz: Die tatsächliche Stärke einer Identitätsregel ist die Qualität ihres seltensten Atoms, nicht ihre Länge. Wird der Immediate-Wert als B8 ?? ?? ?? ?? C3 mit Wildcards versehen, muss YARA auf den Ein-Byte-Atomen B8 und C3 ankern, die in realem .text allgegenwärtig sind – die Regel wird zu einer langsamen, unpräzisen Prüfung.

Die Schlussfolgerung, Junk-Einfügung habe die Signatur ausgehebelt, ist daher ohne Test der Regel selbst nicht haltbar. Dieses Experiment hat Padding gemessen, nicht die Zerstörung einer Regel.

yara
{ B8 07 00 00 00 C3 }   // contiguous identity

Eine Encoding-Änderung, und die Regel verfehlt

Seed 5 nimmt einen anderen Weg durch dieselbe SAFE-Policy und erzeugt 48 C7 C0 07 00 00 00 C3. Die ursprüngliche Bytefolge kommt nicht mehr vor, weil die Instruktion ihre Encoding-Klasse gewechselt hat: ein REX-Präfix, dessen W-Bit 64-Bit-Operandengröße wählt, die MOV-Opcode-Gruppe C7 /0, ein registerdirektes ModR/M, das RAX auswählt, derselbe Immediate-Wert 7 und ret. Das Ergebnis ist effektiv mov rax, 7; ret.

Die Aussage hat eine präzise Grenze. B8 erweitert seinen 32-Bit-Immediate-Wert mit Nullen nach RAX, REX.W + C7 /0 dagegen mit Vorzeichen. Für den positiven Wert 7 liefern beide denselben 64-Bit-Wert. Aethers Feld pure_rax ist jedoch ein 32-Bit-Orakel für den Rückgabewert. Bei einem Immediate-Wert wie 0x80000000 würden sich die beiden Formen in den oberen 32 Bit unterscheiden, und das Orakel könnte es nicht sehen. Die semantische Aussage ist bewusst auf diese Hülle mit positivem Immediate-Wert und die deklarierte 32-Bit-Ausgabedomäne beschränkt.

Auch der Seed allein bestimmt die Ausgabe nicht; ein veröffentlichter Lauf muss einen frischen Prozess, den ersten geseedeten Morph und den exakten Build angeben. Mit dieser Disziplin ist der Vergleich eindeutig:

Diagramm: Das ursprüngliche B8-Encoding verzweigt in die NOP-Variante mit Seed 42 (Regeltreffer) und die REX-Variante mit Seed 5 (kein Treffer), beide mit reinem RAX gleich 7
Gleiches reines Ergebnis, andere Encoding-Klasse: Die NOP-Variante lässt die Nadel intakt, die REX-Form entfernt sie.
  • Original B8 … C3: Identitätsregel HIT, pure_rax 7
  • Seed 42 (90 + Original): Identitätsregel HIT, pure_rax 7 → 7 OK
  • Seed 5 (48 C7 C0 … C3): Identitätsregel MISS, pure_rax 7 → 7 OK

Was das Ergebnis glaubwürdig macht

Das ist kein Argument dafür, dass Detection unmöglich wäre. Eine Regel, die beide Encoding-Familien erkennt, kann weiterhin beide matchen. Es ist ein Argument dafür, dass ein einzelnes Identitätsfragment unvollständig ist.

Aether hebt jede Instruktion mit Zydis an und klassifiziert sie als Control, Memory, Identity, PureRax oder eine andere Klasse; nur klassifizierte Instruktionen gelangen in einen semantisch begrenzten Substitutionskatalog, und ret wird nie als rein diversifiziert. Bytes, die Zydis nicht dekodieren kann, bleiben opak – ein fehlerhaftes Decoding verkleinert also die Transformationsfläche, statt ein Rewriting zu erfinden. Jede Ausgabe wird erneut angehoben und geprüft: durch einen reinen 32-Bit-Vergleich des Rückgabewerts, einen hostunabhängigen Simulator mit festen Multi-Input-Paaren und, auf x86-64 oder im amd64-Docker-Labor, durch native Ausführung. Im Lab- oder Industry-Modus führt eine Abweichung zum Fail-Closed.

Der Benchmark im Labor des Autors auf Apple Silicon nutzte 5.096 Korpuseinträge (1.000 synthetisch, 4.096 aus ELF). Er meldet 10.192 erfolgreiche Morphs, 5.020 reine Prüfungen und 4.862 native Prüfungen ohne Brüche sowie 94,89 % eindeutige Ausgaben nach SHA-256. In der fokussierten Matrix mit 128 Seeds traf die Labor-Identitätsregel 30-mal (23,44 %) und verfehlte 98-mal (76,56 %), ohne reine Brüche. Das sind Messwerte dieses Builds und Hosts, keine dauerhaften Produktkennzahlen.

Flussdiagramm der Aether-MorphEngine-Pipeline: Lift, Analyze, Verzweigung nach Produktmodus, Diversify, Expand, Shuffle, Split, Permute, Assemble und Verify
Die MorphEngine-Pipeline: Jede ausgegebene Variante durchläuft erneutes Lifting und Verifikation, bevor sie zählt.

Die Ebenen, die übereinstimmen müssen

Die Lehre lautet nicht, mehr Signaturen zu verwenden, und auch nicht, dass Morphing gewinnt. Sie lautet, Regeln auf der Ebene zu testen, die sie tatsächlich beobachten. Das Sechs-Byte-Beispiel durchquert fünf Ebenen, und wer eine davon für das ganze System hält, macht aus einem überzeugenden Byte-Dump eine falsche Behauptung. Ein strukturelles Re-Lifting kann keine vollständige Maschinensemantik beweisen, ein bestandenes reines Orakel nicht, dass ein EDR keinen Alarm ausgelöst hat, und ein YARA-MISS nicht, dass ein Encoding in keiner Detection-Familie vorkommt.

  • Decode: Welche Bytes und welchen Kontrollflussgraphen haben wir tatsächlich angehoben?
  • Analyse: Ist diese Transformation nach dem aktuellen Modell zulässig?
  • Lowering: Zeigen Sprünge weiterhin auf die beabsichtigten logischen Blöcke?
  • Orakel: Hat der deklarierte Ausgabevertrag in dieser Domäne gehalten?
  • Detection: Welche Beobachtungsgröße hat sich geändert, und welcher Sensor sieht sie noch?

Vom Experiment zur Detection-CI

Das nützliche Muster: legale semantische Zwillinge innerhalb einer eng deklarierten Domäne erzeugen, Regel und Orakel ausführen, die Evidenz aufbewahren und dann den Sensor reparieren, der versagt hat. Der Job sollte auf mindestens drei Ebenen laufen: Das semantische Orakel verwirft Mutationen, die den deklarierten Vertrag verletzen, die Identität wird als exakte Bytes, Größe und Hash festgehalten, und der benannte Detektor läuft mit seiner exakten Regel. Eine ClamAV- oder EDR-Beobachtung ist eine separate vierte Messung, kein Ersatz für das YARA-Ergebnis.

Bewahren Sie den exakten Labor-YARA-Quelltext, den JSON-Benchmark-Bericht, dekodierte Vorher-nachher-Listings sowie Version und Datum des Detektors auf. Benennen Sie das Orakel, statt nur validiert zu schreiben: Apple Silicon kann die Simulation ausführen, x86-64 aber nicht nativ, daher gehört native Ausführung ins amd64-Docker-Labor.

Wenn eine Regel versagt, sollte die Reparatur der Ebene folgen. Eine zusammenhängende Byte-Regel braucht eventuell Alternativen für die Encoding-Familie, Kontext oder ein zweites Signal; eine Regel, die sowohl B8 ?? … C3 als auch 48 C7 C0 ?? … C3 abdeckt, kann beide Formen erkennen. Ein Größen- oder Entropie-Detektor sieht die mittlere Expansion von etwa 2,19× womöglich bereits und braucht nur Kalibrierung. Ein Verhaltenssensor sollte gegen Ausführung, Allokation, Timing und Speicher getestet werden, statt aus einem statischen Hash abgeleitet zu werden.

Labortopologie: Autoren-Host baut Aether mit Zydis v4.1.1, ein Linux-amd64-Container für den nativen Nachweis und ein optionaler Scan-Container mit ClamAV und YARA
Labortopologie: nativer Nachweis in einem amd64-Container, Detektormessungen in einem separaten Scan-Container.

Key Takeaways

Ein NOP hat die Regel nicht gebrochen; ein einziges äquivalentes Encoding schon. Das Experiment zeigt eine Schwäche einer zusammenhängenden Identitätsregel, kein universelles Versagen von Detection, und es gilt nur innerhalb seiner deklarierten Domäne: eine Hülle mit positivem Immediate-Wert, ein 32-Bit-Rückgabe-Orakel, ein benannter Build und eine benannte Regel.

Die richtige Antwort ist nicht, Unverwundbarkeit zu versprechen, sondern die Annahmen einer Regel ausführbar und regressionsgetestet zu machen. Aether ist für die autorisierte Laborverwendung unter der Aether Research License gedacht. Der vollständige Medium-Artikel enthält jede Messung und jeden Vorbehalt, und die Dokumente SCOPE, SCORECARD, LIBRARY und SECURITY im Repository sollten gelesen werden, bevor ein Ergebnis als Aussage über einen Einsatz gewertet wird.

#detection-engineering #yara #x86-64 #reverse-engineering #malware-analysis
C

Christian Schnapka

Macstab Engineering

Christian Schnapka entwickelt die offenen Engineering-Werkzeuge hinter Macstab. Die ausführlichen Fassungen dieser Untersuchungen veröffentlicht er auf Medium – mit jeder Messung, jedem Vorbehalt und jedem Fehlschlag.