
Una guía sobre cómo escribir reglas YARA rápidas y con un uso eficiente de la memoria.
Escribir reglas YARA eficientes es esencial para mantener un velocidad de escaneo rápida y precisa. Esta guía proporciona principios clave y mejores prácticas para ayudarte a optimizar tus reglas, reducir cálculos innecesarios y evitar errores comunes. Incorpora conocimientos de expertos de la industria, incluidos Victor M. Alvarez, WXS, y contribuciones de la comunidad YARA.
Esta sección proporciona un resumen conciso de las mejores prácticas de rendimiento de YARA. Para explicaciones detalladas y ejemplos, consulta la guía completa a continuación.
"Piensa en YARA como un proceso de dos pasos: primero, buscar todos los patrones enumerados en las cadenas, y segundo, evaluar las condiciones. No puedes usar condiciones bien formadas para compensar cadenas mal elegidas."
— Wesley Shields
YARA sigue cuatro pasos principales al escanear un archivo:
YARA busca cadenas primero, lo que convierte la selección de cadenas en el factor más importante para la eficiencia de las reglas.
✅ Mejores prácticas para cadenas:
\x00\x00\x00\x00 aparece con demasiada frecuencia.nocase con cuidado – Genera exponencialmente más variaciones de búsqueda.YARA evalúa las condiciones secuencialmente y se detiene en el primer fallo.
✅ Mejores prácticas para condiciones:
filesize < X) antes que las condiciones costosas.for all i in (1..filesize) es ineficiente).@) en lugar de expresiones regulares para comprobaciones de secuencia.⚠ Nota: Las condiciones de expresiones regulares no se cortocircuitan y siempre se evalúan al final.
Módulos como pe, elf o magic deben analizar el archivo completo antes de la evaluación, lo que aumenta el tiempo de escaneo.
✅ Alternativas:
pe.is_pe, usa uint16(0) == 0x5A4D para identificar archivos PE.Las coincidencias excesivas ralentizan el escaneo y pueden provocar errores de "demasiadas coincidencias".
✅ Cómo corregir coincidencias ineficientes:
.*, .+ o {x,} sin un límite superior.@herrcore ha creado un útil video tutorial que cubre los temas tratados en esta guía de rendimiento.
Introducción a YARA: cómo escribir reglas YARA eficientes
Para comprender mejor qué y dónde se puede optimizar el rendimiento de YARA, es útil entender el proceso de escaneo. Básicamente se divide en 4 pasos que se explicarán de forma muy simplificada usando esta regla de ejemplo:
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
}
Este paso ocurre antes del escaneo en sí. YARA buscará los llamados átomos en las cadenas de búsqueda para alimentar el autómata Aho-Corasick. Los detalles se explican en el capítulo átomo, pero por ahora basta con saber que tienen un máximo de 4 bytes de longitud y que YARA los elige de forma bastante inteligente para evitar demasiadas coincidencias. En nuestro ejemplo, YARA podría elegir los siguientes 4 átomos:
<?phGETPOSTsser (de assert)Aquí ha comenzado el escaneo. Los pasos 2 a 4 se ejecutarán en todos los archivos. YARA buscará en cada archivo los 4 átomos definidos anteriormente mediante un árbol de prefijos llamado autómata Aho-Corasick. Cualquier coincidencia se entrega al motor de bytecode.
Si hay, por ejemplo, una coincidencia con sser, YARA comprobará si estaba precedido por una a y continúa con una t. Si es así, continuará con la expresión regular [\t ]{0,100}\(. Con este ingenioso enfoque, YARA evita usar un motor de expresiones regulares lento sobre los archivos completos y solo selecciona ciertas partes para examinarlas más de cerca.
Después de completar todo el emparejamiento de patrones, se comprueban las condiciones.
YARA tiene otro mecanismo de optimización para realizar la comprobación math.entropy, que consume mucha CPU, de nuestra regla de ejemplo solo si las 4 condiciones anteriores se cumplen. Se explica con más detalle en el capítulo Condiciones y evaluación de cortocircuito
Si se cumplen las condiciones, se informa de una coincidencia. El escaneo continúa con el siguiente archivo en el paso 2.
YARA extrae de las cadenas subcadenas cortas de hasta 4 bytes de longitud llamadas "átomos". Esos átomos pueden extraerse de cualquier lugar de la cadena, y YARA los busca al escanear el archivo; si encuentra uno de los átomos, verifica que la cadena realmente coincida.
Por ejemplo, considera estas cadenas:
/abc.*cde/
=> los átomos posibles son abc y cde; se puede usar uno u otro. Actualmente se prefiere el átomo abc porque tienen la misma calidad y es el primero de los dos.
/(one|two)three/
=> los átomos posibles son one, two, thre y hree; podemos buscar solo thre (o hree), o tanto one como two. Se prefiere el átomo thre porque dará lugar a menos coincidencias potenciales que one y two (estos son más cortos) y no contiene doble e (cuanto más única sea la letra, mejor).
YARA hace todo lo posible por seleccionar los mejores átomos de cada cadena, por ejemplo:
{ 00 00 00 00 [1-4] 01 02 03 04 }
=> aquí YARA usa el átomo 01 02 03 04, porque 00 00 00 00 es demasiado común
{ 01 02 [1-4] 01 02 03 04 }
=> se prefiere 01 02 03 04 sobre 01 02 porque es más largo
Por lo tanto, el punto importante es que las cadenas deben contener buenos átomos. Estas son cadenas malas porque contienen átomos demasiado cortos o demasiado comunes:
{00 00 00 00 [1-2] FF FF [1-2] 00 00 00 00}
{AB [1-2] 03 21 [1-2] 01 02}
/a.*b/
/a(c|d)/
Las peores cadenas son las que no contienen ningún átomo, como:
/\w.*\d/
/[0-9]+\n/