Parte: 6 — Análisis de malware · Fuente: Practical Malware Analysis (Sikorski & Honig) ⏱️ Duración estimada: 140 min · Nivel: Avanzado
Usar un desensamblador/decompilador para leer el código del malware y reconstruir su lógica: identificar la función main, seguir el grafo de llamadas, reconocer patrones de APIs, renombrar y anotar, y llegar al decompilado en pseudo-C. Ghidra (gratuito) e IDA son las herramientas centrales del análisis estático avanzado.
Al finalizar, el alumno podrá:
| # | Tema | Por qué importa |
|---|---|---|
| 1 | Carga y auto-análisis | Punto de partida del RE |
| 2 | Vistas: disasm, decompiler, graph | Distintos niveles de abstracción |
| 3 | Xrefs (referencias cruzadas) | Navegar de un string/API a su uso |
| 4 | Renombrado y comentarios | Hace legible un binario hostil |
| 5 | Reconocimiento de APIs y patrones | Identifica funcionalidad rápido |
| 6 | Resolución dinámica de APIs | Malware oculta imports en runtime |
| 7 | Scripting (Ghidra/IDAPython) | Automatiza tareas repetitivas |
El análisis estático avanzado —desensamblar y decompilar la muestra con IDA o Ghidra (Clases 131–132)— es el nivel más profundo y costoso del análisis de malware, y se recurre a él cuando las preguntas exigen entender exactamente qué hace el código: cómo cifra un ransomware, qué algoritmo usa un DGA, cómo desofusca sus cadenas, qué condiciones activan una rama. La ingeniería inversa de la Parte 5 se aplica aquí, pero con un adversario que quiere dificultar el análisis, de ahí las técnicas específicas de esta clase.
El trabajo empieza como en la Parte 5: cargar la muestra (ya desempaquetada, clase 147, si estaba
packed), dejar que el auto-análisis identifique funciones y genere la decompilación, y navegar por
las vistas (desensamblado, decompilador, grafo). Pero el análisis de malware es especialmente
dirigido por objetivos: rara vez se lee la muestra entera; se busca responder una pregunta
concreta. La brújula son las referencias cruzadas (xrefs) y las APIs de Windows: se localiza
una API interesante —CryptEncrypt, CreateRemoteThread, InternetOpenUrl— y se mira quién la
llama (xref), lo que lleva directamente a la función que hace lo que interesa. Y el trabajo, como
siempre en RE, es iterativo y anotado: se renombran funciones (FUN_00401230 → cifrar_ficheros)
y se comentan hallazgos, construyendo comprensión que mejora el análisis de lo siguiente.
El malware de Windows habla con el sistema operativo a través de la API de Windows, y reconocer los
patrones de APIs es lo que traduce ensamblador opaco en comportamiento comprensible. Ciertas
combinaciones son firmas de técnicas conocidas: VirtualAllocEx + WriteProcessMemory +
CreateRemoteThread es inyección de código en otro proceso; OpenProcess + VirtualAllocEx sobre
un proceso creado suspendido es process hollowing; RegSetValueEx en una clave Run es
persistencia; CryptAcquireContext + CryptEncrypt es cifrado (ransomware). Un analista
experimentado reconoce estas cadenas de un vistazo, y ese vocabulario de APIs —qué hace cada una, qué
combinaciones significan qué técnica— es buena parte de lo que distingue el análisis de malware de la
RE genérica.
El malware sabe que sus imports lo delatan (clase 143), así que los oculta con resolución dinámica de
APIs: en lugar de importar CreateRemoteThread normalmente (lo que aparecería en la IAT), la
resuelve en tiempo de ejecución —típicamente cargando la DLL con LoadLibrary y obteniendo la
dirección de la función con GetProcAddress, a menudo buscándola por un hash de su nombre en lugar
de por el nombre en claro, para que ni siquiera aparezca la cadena—. El efecto: la IAT del malware se
ve casi vacía, y el desensamblado muestra llamadas a direcciones calculadas en vez de a APIs con
nombre. Reconstruir qué API se está llamando —invirtiendo el algoritmo de hashing y precalculando los
hashes de todas las APIs para hacer una tabla de correspondencia— es una de las tareas más frecuentes y
características del análisis de malware avanzado (y la clase 158 la automatiza con emulación). El
scripting (GhidraScript, IDAPython) es indispensable para estas tareas repetitivas: desofuscar
cientos de cadenas cifradas aplicando la rutina de descifrado que se ha identificado, resolver todas
las APIs por hash de golpe, o anotar el binario en lote. La lección de la clase es que el análisis de
código de malware es RE de la Parte 5 más un catálogo de técnicas del adversario (resolución
dinámica, ofuscación de cadenas, anti-análisis) que hay que reconocer y revertir, y el scripting es lo
que lo hace escalable.
LoadLibrary+GetProcAddress en runtime. Característica clave: oculta capacidades al análisis estático.| Término | Definición concisa |
|---|---|
| Análisis estático avanzado | Desensamblar y decompilar la muestra |
| Auto-análisis | Identificación automática de funciones |
| Dirigido por objetivos | Buscar responder una pregunta, no leer todo |
| Xref | Referencia cruzada: quién llama a algo |
| API de Windows | Interfaz por la que el malware habla con el SO |
| Patrón de APIs | Combinación que revela una técnica conocida |
| Inyección de código | VirtualAllocEx + WriteProcessMemory + CreateRemoteThread |
| Process hollowing | Vaciar un proceso suspendido y reemplazar su código |
| Resolución dinámica de APIs | Obtener funciones en ejecución para ocultarlas |
| GetProcAddress | Resuelve la dirección de una función por nombre |
| API hashing | Buscar la API por un hash de su nombre |
| IAT vacía | Síntoma de resolución dinámica |
| GhidraScript / IDAPython | Scripting para tareas repetitivas |
| Desofuscación en lote | Aplicar la rutina de descifrado a muchas cadenas |
⚠️ Nota ética y de seguridad: el desensamblado es estático y no ejecuta la muestra, pero cárgala siempre desde la VM aislada. Nunca ejecutes la muestra desde el desensamblador (evita "run/debug" con binarios reales fuera del entorno controlado).
main.contact_c2) y comenta el propósito de sus variables.InternetConnect, CryptEncrypt, CreateRemoteThread) y desde ellos sigue xrefs a las rutinas que los invocan.GetProcAddress/API hashing y documenta cómo resuelve funciones.GetProcAddress.Entrega un proyecto de Ghidra anotado de una muestra con al menos 5 funciones renombradas, la rutina de C2 identificada y la configuración/IOCs extraídos del código, más un breve informe. Criterio de aceptación: otra persona puede abrir el proyecto y, siguiendo tus nombres y comentarios, explicar cómo la muestra contacta su C2 sin partir de cero.
| Síntoma / mensaje | Causa y cómo arreglar |
|---|---|
| Decompilado incoherente | Muestra empaquetada; desempácala antes de desensamblar |
No aparece main |
Runtime del compilador; localiza main desde WinMain/CRT |
| Faltan nombres de API | API hashing o resolución dinámica; reconstruye la tabla |
| Xrefs vacíos en un string | El string se construye en runtime; búscalo en el decompilado |
| Perderse en el grafo | Trabaja desde strings/imports hacia dentro, no al revés |
❓ ¿Ghidra o IDA? Ambos son excelentes. Ghidra es gratuito y su decompilador es muy bueno; IDA Pro es el estándar comercial. Aprende el flujo, no solo la herramienta.
❓ ¿Debo leer todo el binario? No. El análisis dirigido por objetivos (encontrar C2, cifrado, persistencia) es mucho más eficiente que leer linealmente.
❓ ¿Cómo trato el API hashing? Reconoce el algoritmo de hash, precomputa hashes de APIs comunes y mapea; hay scripts públicos que automatizan esto.
Clase 145 — El formato PE de Windows