Een NOP brak mijn YARA-regel niet. Eén encodingwijziging wel.
Beveiliging Engineering 9 augustus 2026

Een NOP brak mijn YARA-regel niet. Eén encodingwijziging wel.

Een onderzoek op byteniveau voor detection engineers: waarom een ingevoegde NOP een YARA-hexregel intact laat, terwijl één equivalente x86-64-encodingwijziging hem omzeilt — gereproduceerd met Aether 1.0.0 als referentie-implementatie.

C
Christian Schnapka
Macstab Engineering
6 min lezen
Ook op Medium Lezen op Medium

Een signatuur legt één punt in de coderingsruimte vast

Een YARA-hexregel is een syntactisch predicaat over een bytebuffer. Wat ze probeert te vangen is een semantisch object, bijvoorbeeld een functie die 7 teruggeeft. Tussen die twee vlakken zit de bepalende eigenschap van x86-64: een codering met variabele lengte waarin de afbeelding van bytereeksen op architecturale effecten massaal veel-op-één is. RAX op 7 zetten en terugkeren heeft, voorzichtig geschat, meer dan een dozijn geldige coderingen.

Een signatuur legt één punt in die ruimte vast. De hele taak van een mutator is naar een ander punt te gaan. De intuïtieve aanname — voeg een NOP in, verander hash en grootte, en de identiteitsregel is omzeild — meet daarom op het verkeerde vlak. De vraag is nooit of er bytes zijn verschoven. De vraag is of het exacte punt dat de regel vastlegt nog ergens in de buffer voorkomt, en of de regel een punt of een familie vastlegt.

Dit is een x86-64-labanalyse voor geautoriseerde evaluatie van detecties, met Aether 1.0.0 en Zydis v4.1.1 als reproduceerbare referentie-implementatie. Ze claimt geen willekeurige .text-semantiek, geen algemene binaire herschrijving en geen omzeiling van enig beveiligingsproduct.

Diagram dat het identiteitsvlak (SHA-256, grootte, hexdump, YARA-stringmatch) tegenover het semantische vlak zet (multi-input-orakel, simulator, native uitvoering)
Identiteitsvlak tegenover semantisch vlak: een bytesignatuur en een gedragsorakel observeren verschillende dingen.

Zes bytes, één NOP, nog steeds een hit

De testfunctie is zes bytes: B8 07 00 00 00 C3, oftewel mov eax, 7; ret. De lesregel matcht precies die bytes, aaneengesloten. Het is een regel uitsluitend voor het lab, geen productiesignatuur; de waarde ervan is dat hij het identiteitsvlak zichtbaar maakt.

De eerste SAFE-capture met seed 42 leverde 90 B8 07 00 00 00 C3 op: een NOP van één byte vóór het ongewijzigde origineel. De hash veranderde, de grootte veranderde, de returnwaarde blijft gelijk en de regel matcht nog steeds, omdat de naald van zes bytes één byte verderop intact is.

De reden is mechanisch. YARA reduceert het patroon tot korte atomen, doorgaans substrings van maximaal vier bytes zoals 07 00 00 00, plaatst ze in een Aho-Corasick-automaat en draait de volledige verifier alleen bij atoomtreffers. De automaat is positie-onafhankelijk, dus een verschuiving van één byte verandert niets. Het gevolg: de echte kracht van een identiteitsregel is de kwaliteit van haar zeldzaamste atoom, niet haar lengte. Wildcards op de immediate, zoals B8 ?? ?? ?? ?? C3, dwingen YARA om te ankeren op de atomen van één byte B8 en C3, die elke echte .text verzadigen en de regel veranderen in een trage verificatiestap met lage precisie.

De conclusie dat het invoegen van opvulling de signatuur heeft omzeild, is dus niet aanvaardbaar zonder de regel zelf te testen. Dit experiment mat padding, niet de vernietiging van de regel.

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

Eén coderingswijziging, en de regel mist

Seed 5 volgt een ander pad door dezelfde SAFE-policy en levert 48 C7 C0 07 00 00 00 C3 op. De oorspronkelijke string komt niet meer voor omdat de instructie van coderingsklasse is veranderd: een REX-prefix waarvan de W-bit een operandgrootte van 64 bits kiest, de MOV-opcodegroep C7 /0, een register-directe ModR/M die RAX selecteert, dezelfde immediate 7 en ret. Het resultaat is feitelijk mov rax, 7; ret.

De bewering heeft een precieze grens. B8 breidt zijn 32-bits immediate met nullen uit in RAX, terwijl REX.W + C7 /0 hem met teken uitbreidt. Voor de positieve immediate 7 leveren beide vormen dezelfde 64-bits waarde op. Het pure_rax-veld van Aether is echter een 32-bits orakel voor de returnwaarde. Met een immediate als 0x80000000 zouden de twee vormen in de bovenste 32 bits verschillen, en het orakel zou dat niet zien. De semantische bewering is bewust beperkt tot deze vorm met positieve immediate en het opgegeven 32-bits uitvoerdomein.

Ook de seed alleen bepaalt de uitvoer niet; een gepubliceerde capture moet een nieuw proces, de eerste morph met seed en de exacte build vermelden. Met die discipline is de vergelijking zuiver:

Diagram van de originele B8-codering die vertakt in de NOP-variant van seed 42 (regel matcht) en de REX-variant van seed 5 (regel mist), beide met pure RAX gelijk aan 7
Hetzelfde pure resultaat, een andere coderingsklasse: de NOP-variant laat de naald intact, de REX-vorm verwijdert haar.
  • Origineel B8 … C3: identiteitsregel HIT, pure_rax 7
  • Seed 42 (90 + origineel): identiteitsregel HIT, pure_rax 7 → 7 OK
  • Seed 5 (48 C7 C0 … C3): identiteitsregel MISS, pure_rax 7 → 7 OK

Wat het resultaat geloofwaardig maakt

Dit is geen argument dat detectie onmogelijk is. Een regel die beide coderingsfamilies herkent, kan nog steeds beide matchen. Het is een argument dat één enkel identiteitsfragment onvolledig is.

Aether decodeert elke instructie met Zydis en classificeert haar als Control, Memory, Identity, PureRax of een andere klasse; alleen geclassificeerde instructies komen in een semantisch begrensde substitutiecatalogus, en ret wordt nooit als puur gediversifieerd. Bytes die Zydis niet kan decoderen, blijven behouden als opaak, zodat een foute decodering het transformatieoppervlak verkleint in plaats van een herschrijving te verzinnen. Elke uitvoer wordt opnieuw gedecodeerd en gecontroleerd met een pure 32-bits returnvergelijking, een host-onafhankelijke simulator met vaste paren van meerdere invoerwaarden en, op x86-64 of in het amd64-Dockerlab, native uitvoering. In Lab- of Industry-modus leidt een pure afwijking tot een fail-closed-resultaat.

De labbenchmark van de auteur op Apple Silicon gebruikte 5.096 corpusitems (1.000 synthetisch, 4.096 uit ELF). Die rapporteert 10.192 geslaagde morphs, 5.020 pure controles en 4.862 native controles zonder enige breuk, en 94,89% unieke uitvoer volgens SHA-256. Op de gerichte matrix van 128 seeds matchte de lab-identiteitsregel 30 keer (23,44%) en miste ze 98 keer (76,56%), zonder pure breuken. Dit zijn capturegegevens voor die build en die host, geen permanente productcijfers.

Stroomdiagram van de MorphEngine-pipeline van Aether: lift, analyze, vertakking per productmodus, diversify, expand, shuffle, split, permute, assemble en verify
De MorphEngine-pipeline: elke uitgegeven variant doorloopt opnieuw decoderen en verificatie voordat ze meetelt.

De lagen die het met elkaar eens moeten zijn

De les is niet om meer signaturen te gebruiken, en ook niet dat morphing wint. De les is regels te testen op het vlak dat ze werkelijk observeren. Het voorbeeld van zes bytes doorkruist vijf lagen, en één daarvan als het hele systeem behandelen is precies hoe een overtuigende bytedump een onjuiste bewering wordt. Een structurele herdecodering kan geen volledige machinesemantiek bewijzen, een geslaagd puur orakel kan niet bewijzen dat een EDR geen alert gaf, en een YARA-MISS kan niet bewijzen dat een codering in geen enkele detectiefamilie voorkomt.

  • Decodering: welke bytes en welke control-flow-graaf hebben we werkelijk gedecodeerd?
  • Analyse: staat het huidige model deze transformatie toe?
  • Lowering: wijzen sprongen nog naar de bedoelde logische blokken?
  • Orakel: werd het opgegeven uitvoercontract in dit domein nageleefd?
  • Detectie: welke observabele is veranderd, en welke sensor ziet het nog?

Het experiment omzetten in detectie-CI

Het bruikbare patroon: genereer geldige semantische tweelingen binnen een smal gedefinieerd domein, draai de regel en het orakel, bewaar het bewijs en repareer daarna de sensor die faalde. Draai de job op minstens drie vlakken: het semantische orakel verwerpt mutaties die het opgegeven contract schenden, identiteit wordt vastgelegd als exacte bytes, grootte en hash, en de genoemde detector draait met zijn exacte regel. Een waarneming van ClamAV of een EDR is een afzonderlijke vierde meting, geen vervanging van het YARA-resultaat.

Bewaar de exacte bron van de lab-YARA-regel, het JSON-benchmarkrapport, de gedecodeerde listings van vóór en na, en de versie en datum van de detector. Benoem het orakel in plaats van gevalideerd te schrijven: Apple Silicon kan de simulatie draaien maar x86-64 niet native uitvoeren, dus gebruik het amd64-Dockerlab wanneer uitvoering op hardware vereist is.

Wanneer een regel faalt, moet de reparatie het vlak volgen. Een regel met aaneengesloten bytes heeft mogelijk alternatieven per coderingsfamilie, context of een tweede signaal nodig; een regel die zowel B8 ?? … C3 als 48 C7 C0 ?? … C3 dekt, kan beide vormen herkennen. Een detector op grootte of entropie ziet mogelijk al de gemiddelde expansie van ongeveer 2,19× en heeft alleen kalibratie nodig. Een gedragssensor moet worden getest tegen uitvoerings-, allocatie-, timing- en geheugenoppervlakken, in plaats van te worden afgeleid uit een statische hash.

Labtopologie: host van de auteur die Aether bouwt met Zydis v4.1.1, een Linux-amd64-container voor native bewijs en een optionele scancontainer met ClamAV en YARA
Labtopologie: native bewijs in een amd64-container, detectormetingen in een aparte scancontainer.

Key Takeaways

Een NOP brak de regel niet; één equivalente codering wel. Het experiment toont een zwakte in één aaneengesloten identiteitsregel aan, geen universeel falen van detectie, en het geldt alleen binnen het opgegeven domein: een vorm met positieve immediate, een 32-bits returnorakel, een benoemde build en een benoemde regel.

Het juiste antwoord is geen onkwetsbaarheid beloven, maar de aannames van een regel uitvoerbaar maken en met regressietests afdekken. Aether is bedoeld voor geautoriseerd gebruik in het lab onder de Aether Research License. Het volledige Medium-artikel bevat elke meting en elk voorbehoud, en de documenten SCOPE, SCORECARD, LIBRARY en SECURITY in de repository moeten worden gelezen voordat een resultaat als uitspraak over productie-inzet wordt behandeld.

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

Christian Schnapka

Macstab Engineering

Christian Schnapka bouwt de open engineeringtools achter Macstab. De uitgebreide versies van deze onderzoeken publiceert hij op Medium, met elke meting, elk voorbehoud en elk negatief resultaat erbij.