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,.
La carrera armamentística entre malware y antivirus
TL;DR: La evasión de antivirus emplea técnicas como packers y ofuscación para ocultar código malicioso y evitar su detección por firmas o comportamiento. A diferencia de un archivo estándar, un ejecutable empaquetado utiliza un stub para cargar el contenido original en memoria, técnica que ha evolucionado constantemente durante más de tres décadas. Identificar el punto de entrada original (OEP) es la recomendación fundamental para realizar un análisis de malware efectivo y desarmar estas protecciones.
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
Anatomia de un PE: ejecutables de Windows
Fileless malware en Windows: PowerShell, .NET y WMI
AMSI Bypass: Técnicas de Evasión y Contramedidas Defensivas
Analisis de DLLs y Handles en Memoria: dlllist, handles
Analisis de Procesos en Memoria Windows: pslist, pstree
Registro de Windows en memoria: hivelist y printkey
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.