Rendimiento en YARA: átomos, cadenas y condiciones
Por qué algunas reglas YARA son lentas y cómo arreglarlas: átomos y prefiltro, cadenas buenas y malas, hex con bytes fijos, regex ancladas y comprobaciones baratas primero.
Una sola regla lenta puede frenar el escaneo de miles de archivos, porque todas las reglas de un conjunto compilado comparten la misma pasada de búsqueda.
Cómo funciona un escaneo
- Búsqueda de patrones: al compilar, YARA elige de cada patrón una secuencia fija de hasta cuatro bytes, el átomo. Todos los átomos entran en un autómata Aho-Corasick y los datos se recorren una vez; donde aparece un átomo, se verifica el patrón completo.
- Evaluación de condiciones con las coincidencias encontradas, las propiedades del archivo y los datos de módulos.
El coste depende de lo frecuentes que sean los átomos: E8 45 FF 0A es raro; 00 00 aparece millones de veces.
Átomos buenos y malos
| Patrón | Calidad | Por qué |
|---|---|---|
"EvilCorpUpdater" | Excelente | Texto largo y raro |
{ 8B 45 FC 33 D2 F7 75 F8 } | Buena | Bytes de código fijos |
"abc" | Mala | Tres bytes, demasiado frecuente |
{ 00 00 00 00 ?? ?? 00 00 } | Muy mala | Solo ceros fijos |
/[a-z]{8}\.dll/ | Mala | Solo .dll es literal |
YARA-X avisa al compilar de algunos patrones lentos; el editor muestra esos avisos y el linter añade heurísticas.
Cadenas rápidas
- Al menos cuatro bytes fijos consecutivos, idealmente al principio.
- Evita bytes comunes:
00,FF,90,CC, espacios. - Comodines solo en lo que cambia (direcciones, valores inmediatos), no en los opcodes.
nocase,xorybase64solo en cadenas largas.- Ancla las regex con literales.
rule Fast_Code_Pattern
{
strings:
$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
}
Primero lo barato
import "pe"
import "math"
rule Ordered_Condition
{
strings:
$a = "ReflectiveLoader" ascii
condition:
uint16(0) == 0x5A4D and
filesize < 4MB and
$a and
pe.number_of_sections > 3 and
math.entropy(0, 0x1000) < 7.0
}
Un límite de filesize también protege frente a archivos enormes que contengan un átomo por casualidad.
Bucles y funciones de módulos
Recorre coincidencias (for any i in (1..#a)), nunca cada offset (0..filesize). math.entropy y hash.* sobre (0, filesize) leen todo el archivo: acota el rango o protégelo.
Medir
Cronometra yr scan rules.yar corpus/ antes y después de un cambio, compara el conjunto con y sin la regla sospechosa y usa yaraQA para detectar problemas conocidos.
Lista de comprobación
- Cada patrón tiene cuatro o más bytes fijos consecutivos.
- Ningún patrón está hecho sobre todo de
00,FF,90,CCo espacios. nocase,xorybase64solo en cadenas de ocho caracteres o más.- Las regex tienen un literal de tres o más caracteres y ningún
.*inicial. - La condición empieza con magic bytes y un límite de
filesize. - Los bucles recorren coincidencias y las funciones usan rangos acotados.
Comprueba tu regla con el linter y sigue con pruebas y CI.
FAQ
- ¿Qué es un átomo en YARA?
- Una secuencia fija corta, de hasta cuatro bytes, que YARA extrae de cada patrón. Todos los átomos se buscan a la vez y el patrón completo solo se verifica donde aparece su átomo.
- ¿Por qué mi regla YARA es lenta?
- Casi siempre porque un patrón no tiene un buen átomo: cadena de menos de cuatro bytes, hex casi todo comodines, bytes muy comunes como 00 00 00 00 o regex sin parte literal.
- ¿Importa el orden de la condición?
- Sí. Se evalúa de izquierda a derecha con cortocircuito, así que filesize y los magic bytes deben ir antes que módulos, bucles, entropía o hashes.