Tema 12
El debugging permite observar una muestra mientras se ejecuta, detenerla en puntos específicos, inspeccionar memoria, revisar argumentos de funciones y validar hipótesis sobre su comportamiento interno.
El debugging es una técnica de análisis dinámico avanzado. En lugar de observar la muestra solo desde afuera, el analista la ejecuta bajo control para detenerla, avanzar instrucción por instrucción, inspeccionar registros, examinar memoria y observar llamadas a funciones críticas.
En malware, el debugger ayuda a responder preguntas que el análisis estático y la sandbox no siempre resuelven: cuándo se descifra una configuración, qué argumentos recibe una API, dónde se desempaqueta un payload o qué condición evita que una rama se ejecute.
Como implica ejecución de código malicioso, debe realizarse en laboratorio aislado, con snapshots limpios y un plan claro de observación.
No toda muestra requiere debugging. Es una técnica poderosa, pero consume tiempo y puede activar riesgos si se usa sin objetivo.
Antes de abrir una muestra en el debugger, el entorno debe estar listo. El debugger no reemplaza el aislamiento del laboratorio.
La mayoría de los ejercicios de este curso se concentran en debugging de espacio de usuario. El debugging de kernel se usa para drivers, rootkits o fallas profundas del sistema, y requiere preparación adicional.
| Tipo | Uso común | Riesgo o complejidad |
|---|---|---|
| Usuario | Ejecutables, DLLs, procesos, APIs | Más accesible y suficiente para muchas muestras |
| Kernel | Drivers, rootkits, fallas privilegiadas | Mayor complejidad y posibilidad de bloquear el sistema |
| Remoto | Análisis desde otra máquina o VM | Requiere red y configuración controlada |
Un breakpoint detiene la ejecución en una dirección, función o condición. Permite inspeccionar estado justo antes o después de una acción importante.
Tipos comunes:
Colocar breakpoints en APIs permite observar acciones de alto nivel: archivos, registro, red, memoria, procesos o criptografía. La clave es revisar argumentos y contexto cuando la ejecución se detiene.
| Familia de API | Qué puede revelar | Dato importante |
|---|---|---|
| Archivos | Creación, lectura, escritura o borrado | Ruta, modo de acceso y proceso responsable |
| Registro | Persistencia o configuración | Clave, valor y datos escritos |
| Red | Conexiones y transferencia | Destino, puerto, buffer y frecuencia |
| Memoria | Asignación, permisos y código generado | Tamaño, protección y dirección resultante |
| Procesos | Ejecución, apertura o inyección | PID, permisos solicitados y ruta objetivo |
Stepping es avanzar controladamente por el código. Las acciones principales son entrar en una llamada, pasar por encima de una llamada o continuar hasta retornar.
Entrar en todas las llamadas produce ruido. Conviene entrar solo en funciones propias de la muestra o en rutinas críticas para la pregunta de análisis.
Los registros muestran el estado inmediato de ejecución. En x64, muchos argumentos de funciones se pasan por registros; por eso, revisar RCX, RDX, R8 y R9 en Windows x64 o RDI, RSI, RDX, RCX, R8 y R9 en System V puede revelar datos clave.
Los flags indican resultados de comparaciones y operaciones. Saltos condicionales dependen de ellos, así que son importantes para entender por qué se toma una rama.
El stack ayuda a reconstruir llamadas, argumentos, direcciones de retorno y variables locales. Durante debugging, revisar el stack puede explicar cómo se llegó a una función y qué datos temporales maneja.
Usos habituales:
La vista de memoria permite revisar regiones asignadas, permisos, módulos, strings y datos generados durante ejecución. En malware, muchas piezas importantes aparecen solo en memoria.
| Observación | Posible significado | Acción de análisis |
|---|---|---|
| Región RWX | Código generado o desempaquetado | Inspeccionar y considerar dump |
| Strings nuevas en memoria | Configuración descifrada | Buscar referencias y guardar evidencia |
| Buffer enviado por red | Beaconing o exfiltración | Correlacionar con PCAP |
| Módulo no esperado | DLL cargada o inyección | Revisar ruta, firma y exportaciones |
Un dump conserva una región de memoria, un módulo o un proceso completo para analizarlo luego. Es útil cuando el código real aparece desempaquetado durante ejecución o cuando la configuración queda descifrada temporalmente.
Al guardar dumps, registrar:
El flujo de ejecución describe qué instrucciones y ramas toma el programa. El debugger permite seguir ese flujo, pero el analista debe evitar perderse en rutas irrelevantes.
Recomendaciones:
Muchas muestras verifican entorno, privilegios, idioma, conectividad o presencia de herramientas. El debugging permite observar qué condición se evalúa y qué rama se toma.
Ejemplos de condiciones relevantes:
Modificar condiciones dentro del debugger puede servir para explorar rutas, pero debe documentarse claramente porque cambia la ejecución natural.
Las excepciones detienen ejecución por eventos como acceso inválido a memoria, instrucción ilegal, división por cero o breakpoint. En malware, una excepción puede ser error real, mecanismo anti-debugging o parte de un flujo controlado.
Al analizar un crash, registrar:
Cuando una muestra está empaquetada, el debugger puede ayudar a llegar al momento en que el código real aparece en memoria. El objetivo defensivo es observar y capturar el contenido desempaquetado para analizarlo con más claridad.
Señales durante ejecución:
Para entender comunicación, conviene combinar breakpoints en APIs de red con captura de tráfico. El debugger muestra buffers y argumentos; el PCAP muestra lo que efectivamente salió o intentó salir.
La persistencia se puede estudiar deteniendo llamadas a registro, tareas, servicios o escritura de archivos en ubicaciones de inicio. Esto permite ver exactamente qué valor se crea y de dónde sale.
| Mecanismo | Qué observar | Evidencia útil |
|---|---|---|
| Registro | Clave, valor y datos | Ruta de persistencia y proceso creador |
| Tarea programada | Comando, disparador y usuario | XML, logs o comandos asociados |
| Servicio | Nombre, binario y tipo de inicio | Configuración y privilegios |
| Archivo en startup | Ruta y contenido | Hash del archivo y enlace con muestra |
Algunas muestras intentan detectar o interferir con debuggers. Pueden consultar flags del proceso, medir tiempos, buscar ventanas o procesos de herramientas, provocar excepciones o comprobar diferencias de ejecución.
Señales comunes:
La respuesta debe ser metódica: primero confirmar que existe anti-debugging, luego documentar qué condición lo activa.
Un debugger permite cambiar registros, memoria o flujo. Esto puede ayudar a explorar ramas no tomadas, pero también altera el comportamiento natural de la muestra.
Si se modifica ejecución:
Una sesión de debugging puede generar mucha información. La documentación debe capturar lo esencial sin convertirse en una transcripción completa de cada instrucción.
El debugging agrega precisión al análisis de malware. Permite mirar dentro de la ejecución, capturar datos temporales, seguir decisiones y explicar comportamientos que desde afuera solo se ven como efectos.
En el próximo tema estudiaremos ofuscación, packing, anti-debugging, anti-VM y técnicas de evasión, para entender por qué algunas muestras intentan resistirse al análisis.