
Ein Leitfaden zum Schreiben schneller und speicherschonender YARA-Regeln.
Das Schreiben effizienter YARA-Regeln ist entscheidend, um eine schnelle und genaue Scan-Leistung zu gewährleisten. Dieser Leitfaden enthält wichtige Prinzipien und Best Practices, die Ihnen helfen, Ihre Regeln zu optimieren, unnötige Berechnungen zu reduzieren und häufige Fallstricke zu vermeiden. Er beinhaltet Erkenntnisse von Branchenexperten, darunter Victor M. Alvarez, WXS, und Beiträge aus der YARA-Community.
Dieser Abschnitt bietet eine kurze Zusammenfassung der YARA-Performance-Best-Practices. Für ausführliche Erklärungen und Beispiele siehe den vollständigen Leitfaden weiter unten.
„Betrachten Sie YARA als einen zweistufigen Prozess: Zuerst wird nach allen in den Strings aufgeführten Mustern gesucht, und zweitens werden die Bedingungen ausgewertet. Sie können gut formulierte Bedingungen nicht nutzen, um schlecht gewählte Strings auszugleichen.“
— Wesley Shields
YARA durchläuft beim Scannen einer Datei vier Hauptschritte:
YARA sucht zuerst nach Strings, was die String-Auswahl zum wichtigsten Einzelfaktor für die Effizienz von Regeln macht.
✅ Best Practices für Strings:
\x00\x00\x00\x00 zu häufig vor.nocase sorgfältig ein – Es erzeugt exponentiell mehr Suchvarianten.YARA wertet Bedingungen sequenziell aus und stoppt beim ersten Fehlschlag.
✅ Best Practices für Bedingungen:
filesize < X) vor teuren Bedingungen.for all i in (1..filesize) ist ineffizient).@) anstelle von Regex für Sequenzprüfungen.⚠ Hinweis: Regex-Bedingungen unterstützen kein Short-Circuit und werden immer zuletzt ausgewertet.
Module wie pe, elf oder magic müssen die gesamte Datei parsen, bevor die Auswertung erfolgt, was die Scan-Zeit erhöht.
✅ Alternativen:
pe.is_pe den Ausdruck uint16(0) == 0x5A4D, um PE-Dateien zu identifizieren.Übermäßige Übereinstimmungen verlangsamen das Scannen und können „too many matches“-Fehler auslösen.
✅ Beheben ineffizienter Übereinstimmungen:
.*, .+ oder {x,} ohne obere Grenze.@herrcore hat ein hilfreiches Video-Tutorial erstellt, das die in diesem Performance-Leitfaden behandelten Themen abdeckt.
Einführung in YARA – Effiziente YARA-Regeln schreiben
Um ein besseres Verständnis dafür zu bekommen, was und wo an der YARA-Leistung optimiert werden kann, ist es hilfreich, den Scan-Prozess zu verstehen. Er ist grundsätzlich in vier Schritte unterteilt, die anhand dieser Beispielregel stark vereinfacht erklärt werden:
import "math"
rule example_php_webshell_rule
{
meta:
description = "Just an example php webshell rule"
date = "2021/02/16"
strings:
$php_tag = "<?php"
$input1 = "GET"
$input2 = "POST"
$payload = /assert[\t ]{0,100}\(/
condition:
filesize < 20KB and
$php_tag and
$payload and
any of ( $input* ) and
math.entropy(500, filesize-500) >= 5
}
Dieser Schritt erfolgt vor dem eigentlichen Scan. YARA sucht nach sogenannten Atomen in den Suchstrings, um den Aho-Corasick-Automaten zu speisen. Die Details werden im Kapitel Atom erklärt, aber für jetzt reicht es zu wissen, dass sie maximal 4 Bytes lang sind und YARA sie ziemlich klug auswählt, um zu viele Übereinstimmungen zu vermeiden. In unserem Beispiel könnte YARA die folgenden 4 Atome auswählen:
<?phGETPOSTsser (aus assert)Hier hat der Scan begonnen. Die Schritte 2.-4. werden für alle Dateien ausgeführt. YARA sucht in jeder Datei nach den oben definierten 4 Atomen mithilfe eines Präfixbaums, dem sogenannten Aho-Corasick-Automaten. Alle Übereinstimmungen werden an die Bytecode-Engine übergeben.
Wenn es z. B. eine Übereinstimmung mit sser gibt, prüft YARA, ob ein a vorangestellt war und es mit einem t weitergeht. Wenn das zutrifft, wird mit dem Regex [\t ]{0,100}\( fortgefahren. Mit diesem cleveren Ansatz vermeidet YARA, mit einer langsamen Regex-Engine über die gesamten Dateien zu gehen, und wählt stattdessen bestimmte Teile zur genaueren Untersuchung aus.
Nachdem das gesamte Pattern Matching abgeschlossen ist, werden die Bedingungen geprüft.
YARA verfügt über einen weiteren Optimierungsmechanismus, um die CPU-intensive math.entropy-Prüfung aus unserer Beispielregel nur dann durchzuführen, wenn die 4 Bedingungen davor erfüllt sind. Näher erläutert wird dies im Kapitel Bedingungen und Short-Circuit-Auswertung.
Wenn die Bedingungen erfüllt sind, wird eine Übereinstimmung gemeldet. Der Scan wird mit der nächsten Datei in Schritt 2 fortgesetzt.
YARA extrahiert aus den Strings kurze Teilstrings mit einer Länge von bis zu 4 Bytes, die als „Atome“ bezeichnet werden. Diese Atome können an beliebiger Stelle innerhalb des Strings extrahiert werden, und YARA sucht beim Scannen der Datei nach diesen Atomen. Wenn es eines der Atome findet, überprüft es, ob der String tatsächlich übereinstimmt.
Betrachten Sie zum Beispiel diese Strings:
/abc.*cde/
=> mögliche Atome sind abc und cde, entweder das eine oder das andere kann verwendet werden. Das Atom abc wird derzeit bevorzugt, weil beide die gleiche Qualität haben und es das erste der beiden ist.
/(one|two)three/
=> mögliche Atome sind one, two, thre und hree. Wir können nach thre (oder hree) allein suchen oder sowohl nach one als auch nach two. Das Atom thre wird bevorzugt, weil es zu weniger potenziellen Übereinstimmungen führt als one und two (diese sind kürzer) und kein doppeltes e enthält (je eindeutiger der Buchstabe, desto besser).
YARA gibt sein Bestes, um die besten Atome aus jedem String auszuwählen, zum Beispiel:
{ 00 00 00 00 [1-4] 01 02 03 04 }
=> hier verwendet YARA das Atom 01 02 03 04, weil 00 00 00 00 zu häufig vorkommt.
{ 01 02 [1-4] 01 02 03 04 }
=> 01 02 03 04 wird gegenüber 01 02 bevorzugt, weil es länger ist.