Performance YARA : atomes, chaînes et conditions
Pourquoi certaines règles YARA sont lentes et comment les corriger : atomes et préfiltre, bonnes et mauvaises chaînes, hex à octets fixes, regex ancrées, garde-fous.
Une seule règle lente peut faire ramper le scan de milliers de fichiers, car toutes les règles d’un jeu compilé partagent la même passe de recherche. Comprendre comment YARA cherche fait la différence entre une règle qui coûte des microsecondes et une règle qui domine le scan.
Comment se déroule un scan
Le scan se fait en deux temps :
- Recherche des motifs. À la compilation, YARA choisit dans chaque motif une courte séquence fixe d’au plus quatre octets, l’atome. Tous les atomes de toutes les règles sont placés dans un automate Aho-Corasick et les données sont parcourues une seule fois. Là où un atome apparaît, YARA vérifie le motif complet.
- Évaluation des conditions. Pour chaque règle, la condition est évaluée à partir des correspondances trouvées, des propriétés du fichier et des données des modules.
Le coût de la première phase dépend de la fréquence des atomes. Un atome comme E8 45 FF 0A est rare ; 00 00 apparaît des millions de fois dans n’importe quel binaire, et chaque occurrence déclenche une vérification.
Bons et mauvais atomes
| Motif | Qualité de l’atome | Pourquoi |
|---|---|---|
"EvilCorpUpdater" | Excellente | Texte long et rare |
{ 8B 45 FC 33 D2 F7 75 F8 } | Bonne | Octets de code fixes |
"abc" | Faible | Trois octets : trop court, trop fréquent |
{ 00 00 00 00 ?? ?? 00 00 } | Très faible | Seuls des zéros sont fixes |
{ ?? ?? ?? ?? [2-8] 4D } | Très faible | Un seul octet fixe |
/[a-z]{8}\.dll/ | Faible | Seul .dll est littéral |
/.*password=.*/ | Faible | .* initial et littéral court |
YARA-X avertit à la compilation pour certains motifs probablement lents ; l’éditeur affiche ces avertissements et le linter ajoute des heuristiques pour le reste.
Écrire des chaînes rapides
- Au moins quatre octets fixes. Pour du texte, préférez des chaînes distinctives de huit caractères ou plus. Pour de l’hexadécimal, gardez au moins une suite de quatre octets fixes consécutifs, idéalement au début.
- Évitez les octets courants. Les suites de
00,FF,90(NOP),CC(int3) ou d’espaces sont partout. - Jokers uniquement sur ce qui varie. Dans le code, mettez en joker les adresses relatives et valeurs immédiates, pas les opcodes.
nocase,xoretbase64sur des chaînes longues. Chacun démultiplie le motif en de nombreux atomes.- Ancrez les regex par des littéraux.
/evil[0-9]{2}\.exe/fournit l’atomeevil; une regex faite de classes n’en fournit aucun.
rule Fast_Code_Pattern
{
strings:
// Quatre octets fixes en tête, jokers seulement sur l'opérande rel32.
$decrypt = { 8A 04 0E 34 ?? 88 04 0F 41 81 F9 ?? ?? ?? ?? 72 }
$cfg = "cfg_version=" ascii
condition:
uint16(0) == 0x5A4D and filesize < 3MB and all of them
}
Les garde-fous d’abord
Les conditions court-circuitent de gauche à droite. Placez en tête les contrôles qui éliminent le plus de fichiers à moindre coût :
import "pe"
import "math"
rule Ordered_Condition
{
strings:
$a = "ReflectiveLoader" ascii
condition:
uint16(0) == 0x5A4D and // une lecture d'entier
filesize < 4MB and // aucune lecture
$a and // déjà calculé par le scan
pe.number_of_sections > 3 and // données du module
math.entropy(0, 0x1000) < 7.0 // calcul borné
}
Une limite filesize protège aussi des fichiers énormes qui contiendraient par hasard un atome.
Boucles et fonctions de modules
- Bouclez sur les occurrences (
for any i in (1..#a)), jamais sur chaque offset du fichier (for any i in (0..filesize)). math.entropy,hash.*et consorts sur(0, filesize)lisent tout le fichier : limitez la plage ou protégez l’appel.pe.imports()est peu coûteux une fois le fichier analysé, mais l’analyse elle-même est évitée pour les fichiers qui échouent à unuint16(0) == 0x5A4Dplacé avant.
Mesurer
Mesurez plutôt que de deviner :
- Chronométrez
yr scan rules.yar corpus/sur un corpus représentatif avant et après une modification. - Comparez le jeu complet avec et sans la règle suspecte.
- yaraQA détecte conditions impossibles, mauvais modificateurs et problèmes de performance ; YARA Forge l’utilise pour le paquet core dont provient cette bibliothèque, et chaque page de règle affiche le score qualité correspondant.
- Guide de référence : YARA Performance Guidelines.
Check-list
- Chaque motif a au moins quatre octets fixes consécutifs.
- Aucun motif n’est composé surtout de
00,FF,90,CCou d’espaces. nocase,xoretbase64seulement sur des chaînes de huit caractères ou plus.- Les regex contiennent un littéral d’au moins trois caractères et pas de
.*initial. - La condition commence par les magic bytes et une borne
filesize. - Les boucles parcourent des occurrences ; les fonctions de modules ont des plages bornées.
Collez votre règle dans le linter pour vérifier les points 1 à 6 automatiquement, puis testez-la dans l’éditeur. Pour tester systématiquement, poursuivez avec tests et CI.
FAQ
- Qu’est-ce qu’un atome dans YARA ?
- Une courte séquence fixe, jusqu’à quatre octets, que YARA extrait de chaque motif. Tous les atomes sont recherchés d’un coup ; le motif complet n’est vérifié que là où son atome apparaît.
- Pourquoi ma règle YARA est-elle lente ?
- Le plus souvent parce qu’un motif n’a pas de bon atome : chaîne de moins de quatre octets, hex composé surtout de jokers, octets très fréquents comme 00 00 00 00, ou regex sans partie littérale.
- L’ordre des conditions a-t-il une importance ?
- Oui. Les conditions sont évaluées de gauche à droite avec court-circuit : les contrôles peu coûteux comme filesize et les magic bytes doivent précéder appels de modules, boucles, entropie ou hash.