Evasión de Antivirus: Ofuscación, Packers y Crypters
Análisis técnico de técnicas de evasión de antivirus en Windows. Packers (UPX, Themida, VMProtect), crypters, ofuscación de código, polimorfismo, metamorfismo y cómo los analistas identifican y deshacen estas protecciones.
La carrera armamentística entre malware y antivirus
Los antivirus detectan malware de tres formas: firmas (hash del archivo), heurísticas (patrones de código sospechoso) y behavioral (comportamiento en ejecución). El malware responde con tres contramedidas: packers (cambiar el hash), ofuscación (ocultar patrones de código) y técnicas anti-sandbox (evadir análisis behavioral).
Esta carrera lleva más de tres décadas y no tiene ganador definitivo. Cada mejora en detección produce una mejora en evasión, y viceversa. Este artículo analiza las técnicas de evasión desde la perspectiva del analista que necesita entenderlas para deshacerlas.
Packers: comprimir para ocultar
Concepto
Un packer toma un ejecutable PE y lo comprime o cifra. El resultado es un nuevo PE que contiene:
- Stub de descompresión: código que se ejecuta primero
- Datos comprimidos/cifrados: el PE original
- Al ejecutarse: el stub descomprime el PE original en memoria y le transfiere el control
PE Original (detectable) → PE Empaquetado (no detectable por firma)
┌──────────────────┐ ┌──────────────────────────┐
│ .text (código) │ PACK → │ .UPX0 (vacía, se llena) │
│ .data (datos) │ │ .UPX1 (datos comprimidos)│
│ .rsrc (recursos) │ │ Stub descompresión │
└──────────────────┘ └──────────────────────────┘
Entry point → Stub → Descomprime → OEP
Packers comunes
| Packer | Tipo | Uso | Detección |
|---|---|---|---|
| UPX | Compresión (open source) | Malware commodity, reducir tamaño | Trivial: upx -d para desempaquetar |
| Themida/WinLicense | Protector comercial | Malware avanzado, software legítimo | Difícil: virtualización de código |
| VMProtect | Protector comercial | Malware avanzado, juegos | Muy difícil: VM-based obfuscation |
| ASPack | Compresión | Malware legacy | Fácil: herramientas automáticas |
| MPRESS | Compresión | Malware moderado | Fácil-Medio |
| Enigma Protector | Protector | Malware + software legítimo | Medio |
| Obsidium | Protector | Malware moderado | Medio |
| PECompact | Compresión | Legacy | Fácil |
Indicadores de packing en el PE
| Indicador | Valor normal | Valor empaquetado | Herramienta |
|---|---|---|---|
| Entropía de .text | 5.5 - 6.5 | 7.0 - 7.99 | pestudio, DIE |
| Número de imports | 20-200+ | 1-5 (solo GetProcAddress, LoadLibrary) | pestudio, pefile |
| Nombres de secciones | .text, .data, .rsrc | .UPX0, .vmp0, .themida, .enigma | DIE, CFF Explorer |
| Entry point | Inicio de .text | Última sección o sección con nombre de packer | PE-bear |
| Tamaño raw vs virtual | Similar | Raw mucho menor que virtual (se expande en memoria) | pefile |
Desempaquetado (unpacking)
Método 1: Automático con UPX
upx -d packed_sample.exe -o unpacked_sample.exe
Solo funciona con UPX no modificado. Muchas variantes de malware modifican UPX headers para que la herramienta oficial falle.
Método 2: Dump de memoria
- Ejecutar el sample en una sandbox o debugger
- Esperar a que el stub descomprima el payload en memoria
- Dumpar la región de memoria que contiene el PE descomprimido
- Reconstruir el PE (fix imports con Scylla/ImpRec)
Método 3: Debugging manual
- Cargar en x64dbg
- Ejecutar hasta el entry point del packer
- Buscar el OEP (Original Entry Point): el punto donde el stub transfiere control al código original
- Breakpoint en el OEP
- Dumpar la imagen en memoria
- Reconstruir IAT (Import Address Table) con Scylla
Encontrar el OEP
Técnicas para identificar el OEP en un PE empaquetado:
| Técnica | Descripción |
|---|---|
| ESP trick | Breakpoint hardware en el valor de ESP al inicio. Cuando se restaura (ret o jmp), estás cerca del OEP |
| Tail jump | Buscar un jmp largo al final del stub que salta a una dirección distante (el OEP) |
| Section permissions | Breakpoint en VirtualProtect: cuando el stub cambia permisos de la sección de código a RX, el unpacking terminó |
| API calls | Breakpoint en APIs que el malware real llamaría (no el stub): cuando se llaman, el código original está ejecutándose |
Crypters: cifrar para evadir
Concepto
Un crypter cifra el payload con una clave y genera un nuevo ejecutable que contiene:
- Stub de descifrado: código que descifra el payload
- Payload cifrado: el malware original cifrado
- Clave: embebida en el stub o derivada de una fuente
Payload original → [Cifrado AES/RC4/XOR] → Payload cifrado
↓
┌─────────────────────┐
│ Nuevo ejecutable: │
│ ├─ Stub descifrado │
│ ├─ Clave (embebida) │
│ └─ Payload cifrado │
└─────────────────────┘
Crypters FUD (Fully Undetectable)
El underground vende crypters como servicio:
| Tier | Precio típico | Garantía | Frecuencia de actualización |
|---|---|---|---|
| Free/público | 0 USD | Ninguna (detectado en horas) | Nunca |
| Budget | 10-50 USD/mes | "FUD en momento de venta" | Semanal |
| Premium | 50-200 USD/mes | FUD garantizado, re-crypt si detectan | Diaria |
| Private | 200-1000 USD/mes | FUD exclusivo, pocos clientes | Continua |
Los crypters FUD se testean contra VirusTotal (o servicios alternativos que no reportan a los vendors como antiscan.me). Cuando una detección aparece, el operador actualiza el stub.
Cifrados comunes en crypters
| Cifrado | Uso | Detección |
|---|---|---|
| XOR simple | Crypters básicos | Trivial: patrón XOR visible en la entropía |
| RC4 | Crypters medios | Medio: clave embebida, buscar patrón RC4 |
| AES | Crypters avanzados | Difícil: requiere encontrar la clave |
| Custom cipher | Crypters premium | Variable: depende de la implementación |
Ofuscación de código
Nivel de código fuente
| Técnica | Descripción | Impacto en análisis |
|---|---|---|
| Renaming | Variables y funciones con nombres aleatorios | Dificulta lectura pero no análisis automatizado |
| Control flow flattening | Convertir if/else/loops en un switch gigante | Dificulta seguir la lógica del programa |
| Dead code insertion | Añadir código que nunca se ejecuta | Incrementa tamaño y confunde heurísticas |
| String encryption | Cifrar strings en compile-time, descifrar en runtime | Oculta URLs, claves, mensajes |
| Opaque predicates | Condicionales que siempre evalúan igual pero parecen variables | Confunde análisis estático |
| API hashing | Reemplazar nombres de API por hashes | Oculta imports del análisis estático |
Nivel de binario
| Técnica | Descripción |
|---|---|
| Instruction substitution | Reemplazar mov eax, 0 por xor eax, eax (equivalentes) |
| Register reassignment | Usar registros diferentes en cada compilación |
| Junk code insertion | Insertar instrucciones que no afectan el resultado (nops, push/pop) |
| Code transposition | Reordenar bloques de código con jumps |
Polimorfismo y metamorfismo
Polimorfismo
El malware polimórfico cambia su apariencia (cifrado del cuerpo) en cada instancia pero mantiene el mismo código funcional subyacente:
Instancia 1: [Stub A] + [Payload cifrado con Key1]
Instancia 2: [Stub B] + [Payload cifrado con Key2]
Instancia 3: [Stub C] + [Payload cifrado con Key3]
Cada instancia tiene un hash diferente y un stub diferente,
pero el payload descifrado es identico.
Ejemplos históricos: Storm Worm, Virut, Sality.
Metamorfismo
El malware metamórfico reescribe su propio código en cada generación, produciendo funcionalmente equivalente pero estructuralmente diferente:
Generacion 1: mov eax, 5 / add eax, 3
Generacion 2: push 5 / pop eax / sub eax, -3
Generacion 3: xor eax, eax / or eax, 8
Las tres generaciones producen eax=8, pero el codigo es diferente.
El metamorfismo verdadero es raro en malware moderno por su complejidad. La mayoría del malware usa polimorfismo (cifrado variable) o packers comerciales.
Anti-análisis: más allá de la evasión de firmas
Anti-debugging
| Técnica | API/Método | Bypass |
|---|---|---|
IsDebuggerPresent | Checks PEB.BeingDebugged flag | Patchear PEB.BeingDebugged a 0 |
NtQueryInformationProcess(ProcessDebugPort) | Query al kernel | Hook en ntdll o ScyllaHide plugin |
| Timing checks | GetTickCount delta | NOP los checks |
| INT 2D | Excepción que se comporta diferente en debugger | Ignorar la excepción |
| Hardware breakpoint detection | GetThreadContext lee DR0-DR7 | Clear hardware breakpoints |
Anti-sandbox
| Técnica | Qué detecta | Bypass (sandbox) |
|---|---|---|
| Check CPU count | Sandboxes suelen tener 1-2 CPUs | Configurar sandbox con 4+ CPUs |
| Check RAM | Sandboxes suelen tener 2 GB | Configurar 8+ GB |
| Check disk size | Sandboxes tienen discos pequeños | Disco virtual de 100+ GB |
| Check screen resolution | Resoluciones atípicas | Resolución estándar (1920x1080) |
| Check recent files | Sandbox vacía no tiene archivos recientes | Popular con documentos falsos |
| Check username | "admin", "user", "sandbox", "malware" | Username realista |
| Sleep acceleration | Sandbox acelera los Sleep() | Emular sleep real |
| Mouse movement | Sin movimiento de ratón | Simular movimiento |
| Check processes | VMware Tools, VBoxService, Wireshark | Ocultar procesos de análisis |
| CPUID check | Hypervisor present bit | Enmascarar CPUID |
Herramientas del analista
| Herramienta | Uso |
|---|---|
| Detect It Easy (DIE) | Identificar packer, compilador, linker |
| Exeinfo PE | Detección de packers con base de datos extensa |
| pestudio | Triage rápido: imports, strings, entropía, indicadores |
| x64dbg | Debugging dinámico para unpacking manual |
| Scylla | Reconstrucción de IAT tras dump de memoria |
| pe-unmapper | Conversión de dump de memoria a PE válido |
| de4dot | Deobfuscador para .NET (Confuser, SmartAssembly, etc.) |
| CAPA | Detección de capacidades (incluye packing indicators) |
| Entropy analysis (binwalk, pestudio) | Identificar secciones cifradas/comprimidas |
Mapeo MITRE ATT&CK
| Técnica | ID | Descripción |
|---|---|---|
| Obfuscated Files or Information | T1027 | Ofuscación general |
| Software Packing | T1027.002 | Uso de packers |
| Compile After Delivery | T1027.004 | Compilar payload en el sistema objetivo |
| Indicator Removal from Tools | T1027.005 | Eliminar indicadores del binario |
| Dynamic API Resolution | T1027.007 | Resolver APIs en runtime |
| Stripped Payloads | T1027.008 | Eliminar símbolos y debug info |
| Embedded Payloads | T1027.009 | Payload embebido en recurso |
| Virtualization/Sandbox Evasion | T1497 | Anti-sandbox checks |
| Debugger Evasion | T1622 | Anti-debugging |
Fuentes y referencias
- Sikorski, M. & Honig, A. "Practical Malware Analysis." No Starch Press, 2012.
- Andriesse, D. "Practical Binary Analysis." No Starch Press, 2018.
- horsicq. "Detect It Easy." https://github.com/horsicq/Detect-It-Easy
- x64dbg. "x64/x32 debugger." https://x64dbg.com/
- NtQuery. "Scylla: Import Reconstruction." https://github.com/NtQuery/Scylla
- Mandiant. "CAPA: Malware Capability Detection." https://github.com/mandiant/capa
- MITRE ATT&CK. "Obfuscated Files or Information (T1027)." https://attack.mitre.org/techniques/T1027/
- MITRE ATT&CK. "Virtualization/Sandbox Evasion (T1497)." https://attack.mitre.org/techniques/T1497/
- UPX. "The Ultimate Packer for eXecutables." https://upx.github.io/
Preguntas frecuentes
Libros recomendados
Artículos relacionados
Anatomía de un PE: Entendiendo los Ejecutables de Windows para Análisis de Malware
Fileless Malware en Windows: PowerShell, .NET y WMI como Armas
AMSI Bypass: Técnicas de Evasión y Contramedidas Defensivas
Analisis de DLLs y Handles en Memoria: dlllist, handles y Deteccion de Inyeccion
Analisis de Procesos en Memoria Windows: pslist, pstree y Deteccion de Anomalias
Registro de Windows en Memoria: hivelist, printkey y Extraccion de Artefactos
Este contenido tiene fines exclusivamente educativos y de investigación en ciberseguridad defensiva. No se proporcionan binarios maliciosos ni payloads ejecutables. El uso indebido de esta información es responsabilidad exclusiva del usuario. Leer disclaimer completo.