|9 min de lectura|Yvann Lièvre

Escribir una regla YARA para malware: de la muestra a una firma fiable (sin falsos positivos)

Recibes una muestra de malware, un análisis forense, un sandbox, un feed. Quieres detectar toda la familia en tu parque. Aquí tienes cómo escribir una regla YARA que atrape la amenaza sin dispararse con software legítimo, y cómo demostrarlo.

YARAMalwareDFIRDetection
Escribir una regla YARA para malware: de la muestra a una firma fiable (sin falsos positivos)

Recibes una muestra: un adjunto malicioso de una respuesta a incidentes, un binario detectado por tu sandbox, un fichero señalado por un feed de inteligencia de amenazas. La pregunta no es «¿qué es?» (el análisis lo dirá) sino «¿cuántas otras copias de esta familia duermen en mi parque?». YARA es la herramienta de referencia para responder: un lenguaje de reglas que describe patrones (cadenas, bytes, estructura) y los busca a gran escala en ficheros, memoria, un repositorio.

El escollo es el mismo que en toda detección: una regla demasiado laxa se dispara con software totalmente limpio (falso positivo, ahogas al analista), una regla demasiado estricta solo reconoce la muestra exacta y se pierde el resto de la familia (falso negativo, te crees cubierto). Este artículo muestra cómo escribir una regla que atrape la familia sin dar la voz de alarma en vano, y sobre todo cómo demostrarlo.

Por qué escribir tu propia regla

  • Amenazas recientes y dirigidas. Un malware visto en tu organización durante un análisis forense, una variante regional, un implante a medida: ninguna colección pública lo cubrirá a tiempo, si es que lo cubre alguna vez.
  • Tus propias muestras. Lo que producen tu sandbox y tus incidentes es material exclusivo. La regla que sale de ahí detecta lo que nadie más ve.
  • La precisión. Una regla genérica de terceros puede «coincidir» con una familia a costa de falsos positivos que no toleras. Escribir la tuya es ajustar ese umbral para tu entorno.

La anatomía de una regla YARA

Una regla tiene tres bloques: meta (los metadatos), strings (los patrones que se buscan) y condition (la lógica que los combina).

rule ACME_Stealer_Downloader {
    meta:
        description = "ACME Stealer - etapa de descarga"
        author      = "tu-equipo"
        reference   = "informe interno DFIR 2026-07"
        date        = "2026-07-16"
        hash        = "e3b0c44298fc1c149afbf4c8996fb924..."
 
    strings:
        $mz   = { 4D 5A }                       // cabecera PE "MZ"
        $s1   = "acme_stealer_v" ascii
        $s2   = "/gate.php?id=" ascii
        $pdb  = "C:\\build\\acme\\loader.pdb" ascii
 
    condition:
        $mz at 0 and 2 of ($s1, $s2, $pdb)
}

(El ejemplo es ilustrativo: importa más el método que la familia elegida.) El bloque meta documenta la regla y la hace utilizable (referencia, hash, fecha). El bloque strings lista los patrones, texto (ascii, wide), bytes ({ 4D 5A }) o expresiones regulares. El bloque condition es el corazón: decide, a partir de los patrones presentes, si el fichero coincide.

Partir de la muestra, no de una regla copiada

El reflejo es buscar una regla existente para la familia y reutilizarla. Dos motivos para desconfiar.

Primero, el rigor jurídico: una regla publicada bajo licencia copyleft (GPL) o sin licencia no puede entrar tal cual en un conjunto de reglas cerrado o revendido, contaminaría sus derechos. En cambio, el hecho que porta la muestra, tal cadena interna, tal ruta PDB, tal marcador de C2, no pertenece a nadie. La firma que derivas de ella es obra tuya, igual que una firma de antivirus no hereda los derechos del malware al que apunta.

Segundo, la calidad: una buena regla describe lo que caracteriza a la familia, no lo que aparece en un fichero cualquiera. Extraes las cadenas y secuencias de bytes de la muestra y conservas las que son distintivas. Herramientas como yarGen automatizan el primer borrador: extraen las cadenas y las comparan con una base de ficheros legítimos («goodware») para descartar las que aparecen por todas partes. Pero su salida es un borrador, la revisión humana sigue siendo indispensable.

Elegir buenas cadenas: el nervio de la cuestión

Aquí se gana o se pierde la fiabilidad.

  • Huye de las cadenas genéricas. Microsoft Corporation, GetProcAddress, una URL de biblioteca conocida: están en miles de ficheros limpios. Incluirlas es firmar falsos positivos.
  • Prefiere los marcadores únicos. Una cadena interna propia del autor del malware (acme_stealer_v), una ruta PDB de compilación, un mutex, un patrón de C2, un mensaje de error inusual. Son las huellas que la familia arrastra de muestra en muestra.
  • Ancla con la estructura. Para un ejecutable de Windows, imphash (el hash de la tabla de importaciones) es un anclaje fuerte: dos binarios compilados del mismo código fuente suelen compartirlo. Combinado con dos o tres cadenas distintivas, hace la regla precisa y resistente a las variantes.

La condición: ni demasiado laxa, ni demasiado estricta

La condición convierte patrones en veredicto. Algunos principios:

  • Acota. filesize < 500KB evita escanear ficheros grandes inútilmente y corta falsos positivos.
  • Verifica el tipo. uint16(0) == 0x5A4D confirma un PE antes de seguir.
  • Exige un quórum. 2 of ($s*) (dos patrones de varios) atrapa las variantes que no tienen todas las cadenas, sin dejar de ser discriminante. Exigir las cinco te limita a la muestra exacta.

El ajuste correcto está entre «un solo patrón» (demasiado ruido) y «todos los patrones» (sobreajuste sobre un fichero). Dos o tres marcadores distintivos, anclados por la estructura, suele ser el punto de equilibrio.

Validar no basta: hay que demostrar

YARA compila la regla y señala los errores de sintaxis:

yara mis_reglas.yar muestra.bin

Y un linter como yaraQA detecta los defectos clásicos, una regla que nunca puede coincidir, una expresión regular ruinosa en rendimiento. Necesario, pero insuficiente: «compila» no dice nada sobre «detecta bien».

La verdadera prueba es empírica y se reduce a dos tests:

  1. ¿La regla se dispara con toda la familia? Pásala por todo tu conjunto de muestras de la familia (retro-match). Si solo atrapa el fichero original, está sobreajustada, amplía las cadenas o baja el quórum.
  2. ¿Permanece muda ante software limpio? Pásala por un corpus benigno (goodware), tus binarios de sistema, tus aplicaciones legítimas. Cualquier disparo es un falso positivo que corregir antes de desplegar. Es el test que la mayoría de reglas públicas nunca han pasado.

Una regla que ha superado ambas pruebas vale infinitamente más que una «válida». Es la diferencia entre «compila» y «funciona, demostrado, sin ruido».

Las trampas que salen caras

  • La cadena goodware olvidada. La primera fuente de falsos positivos. El test sobre corpus benigno no es opcional.
  • La regla que no coincide con nada. Una cadena mal copiada, una codificación wide en lugar de ascii, y la regla nunca se dispara, un falso negativo silencioso. yaraQA atrapa una parte.
  • El rendimiento. Una expresión regular demasiado abierta o una cadena demasiado corta ralentiza todo un escaneo de parque. Prefiere patrones largos y específicos.
  • Los metadatos descuidados. Rellena hash, reference, date. Es lo que hace utilizable una alerta y mantenible una regla en el tiempo.

En resumen

Escribir una buena regla YARA es un método: partir de la muestra (no de una regla copiada), elegir cadenas distintivas ancladas por la estructura (no cadenas de biblioteca), ajustar la condición entre lo demasiado laxo y lo demasiado estricto, y demostrar empíricamente que atrapa la familia sin tocar el software limpio. El resto (compilación, lint, metadatos) es higiene.

Es exactamente la disciplina que aplicamos a escala en el feed YARA de ThreatClaw: cada regla se valida en el motor real, se somete a retro-match con sus muestras y se prueba contra un corpus benigno para cumplir la promesa más difícil de un feed, pocos falsos positivos, demostrados. Es lo que un simple volcado de reglas no puede mostrar.

Artículos relacionados