SSDT Hooking: Teoría y Práctica de la Técnica Clásica de Rootkits Windows
Análisis técnico de SSDT hooking en Windows. Cómo funciona la System Service Descriptor Table, cómo los rootkits la modifican para interceptar syscalls, la protección de PatchGuard, y técnicas de detección con Volatility y herramientas forenses.
La tabla que controla todo
Cada syscall en Windows pasa por la SSDT. Cuando un programa en user-mode llama a NtCreateFile (via ntdll.dll), el procesador ejecuta la instrucción syscall que transfiere el control al kernel. El kernel usa el número de syscall como índice en la SSDT para encontrar la dirección de la función que implementa esa syscall.
Si un rootkit modifica la entrada de la SSDT para NtQueryDirectoryFile (la syscall que lista archivos), puede interceptar todas las operaciones de listado de archivos en el sistema y filtrar las que no quiere que el usuario vea.
Arquitectura de la SSDT
Estructura en Windows
User Mode (ntdll.dll):
NtCreateFile()
mov r10, rcx
mov eax, 0x55 ← Syscall number (indice en SSDT)
syscall ← Transicion a kernel mode
Kernel Mode:
KiSystemCall64()
← Lee EAX (syscall number)
← Busca en KeServiceDescriptorTable[EAX]
← Obtiene direccion de la funcion real
← Llama a la funcion
KeServiceDescriptorTable (SSDT):
[0x00] → NtAccessCheck (ntoskrnl.exe + offset)
[0x01] → NtWorkerFactoryWorkerReady
...
[0x55] → NtCreateFile (ntoskrnl.exe + offset)
...
[0xFF] → NtQuerySystemInformation (ntoskrnl.exe + offset)
...
Total: ~460+ entradas en Windows 10/11
KeServiceDescriptorTable
// Estructura simplificada
typedef struct _KSERVICE_TABLE_DESCRIPTOR {
PULONG_PTR Base; // Array de punteros a funciones
PULONG Count; // Array de contadores de uso (opcional)
ULONG Limit; // Numero total de entradas
PUCHAR Number; // Array de parametros por syscall
} KSERVICE_TABLE_DESCRIPTOR;
// En Windows x64, la SSDT usa offsets relativos (no punteros absolutos)
// Base[index] contiene un offset de 32 bits desde la base de la tabla
// Funcion real = Base + (Base[index] >> 4)
Dos tablas: SSDT y ShadowSSDT
Windows tiene dos SSDTs:
| Tabla | Contenido | Accesible desde |
|---|---|---|
| KeServiceDescriptorTable (SSDT) | Syscalls de ntoskrnl.exe (NtCreateFile, NtQueryDirectoryFile, etc.) | Todos los procesos |
| KeServiceDescriptorTableShadow (Shadow SSDT) | Syscalls de win32k.sys (NtUserCreateWindow, NtGdiCreateBitmap, etc.) | Solo procesos GUI |
Los rootkits hookean la SSDT principal. Los exploits de escalada de privilegios frecuentemente apuntan a la Shadow SSDT (win32k.sys tiene más vulnerabilidades).
Cómo funciona el SSDT hooking
Proceso de hooking
// Pseudocodigo simplificado de SSDT hooking
// (NO funciona en Windows x64 con PatchGuard)
// 1. Localizar la SSDT
// En x86: KeServiceDescriptorTable es exportado por ntoskrnl
PKSERVICE_TABLE_DESCRIPTOR ssdt = KeServiceDescriptorTable;
// 2. Encontrar el indice de la syscall a hookear
// NtQueryDirectoryFile tiene indice 0x35 (varia por version de Windows)
ULONG index = 0x35;
// 3. Guardar el puntero original
original_NtQueryDirectoryFile = (PVOID)ssdt->Base[index];
// 4. Desactivar write protection del kernel
// El registro CR0 tiene un bit (WP) que protege paginas de solo lectura
__asm {
cli // Deshabilitar interrupciones
mov eax, cr0
and eax, NOT 0x10000 // Limpiar bit WP
mov cr0, eax
}
// 5. Reemplazar el puntero con nuestra funcion hook
ssdt->Base[index] = (ULONG_PTR)hooked_NtQueryDirectoryFile;
// 6. Reactivar write protection
__asm {
mov eax, cr0
or eax, 0x10000 // Restaurar bit WP
mov cr0, eax
sti // Habilitar interrupciones
}
Función hook
// Hook de NtQueryDirectoryFile para ocultar archivos
NTSTATUS hooked_NtQueryDirectoryFile(
HANDLE FileHandle,
HANDLE Event,
PIO_APC_ROUTINE ApcRoutine,
PVOID ApcContext,
PIO_STATUS_BLOCK IoStatusBlock,
PVOID FileInformation,
ULONG Length,
FILE_INFORMATION_CLASS FileInformationClass,
BOOLEAN ReturnSingleEntry,
PUNICODE_STRING FileName,
BOOLEAN RestartScan
) {
// 1. Llamar a la funcion original
NTSTATUS status = original_NtQueryDirectoryFile(
FileHandle, Event, ApcRoutine, ApcContext,
IoStatusBlock, FileInformation, Length,
FileInformationClass, ReturnSingleEntry,
FileName, RestartScan
);
if (NT_SUCCESS(status)) {
// 2. Filtrar los resultados
// Recorrer la lista de entradas de directorio
// Eliminar entradas cuyos nombres empiezan con ROOTKIT_PREFIX
filter_directory_entries(FileInformation, FileInformationClass);
}
return status;
}
Syscalls comúnmente hookeadas
| Syscall | Índice (Win10) | Qué oculta el hook |
|---|---|---|
NtQueryDirectoryFile | Variable | Archivos y directorios |
NtQuerySystemInformation | Variable | Procesos (class SystemProcessInformation) |
NtEnumerateKey | Variable | Claves de registro |
NtEnumerateValueKey | Variable | Valores de registro |
NtDeviceIoControlFile | Variable | Conexiones de red (via TDI/AFD) |
NtReadFile | Variable | Contenido de archivos (filtrar datos) |
NtQueryInformationProcess | Variable | Información de procesos |
NtTerminateProcess | Variable | Proteger el proceso del rootkit contra terminación |
PatchGuard: la defensa de Microsoft
Cómo funciona PatchGuard
PatchGuard (Kernel Patch Protection, KPP) es un componente del kernel de Windows x64 que protege la integridad de estructuras críticas:
Estructuras protegidas por PatchGuard:
├── SSDT (KeServiceDescriptorTable)
├── IDT (Interrupt Descriptor Table)
├── GDT (Global Descriptor Table)
├── MSR (Model Specific Registers)
├── System images (ntoskrnl.exe, hal.dll, ndis.sys)
├── Processor control regions (PRCB)
└── Kernel stacks
Funcionamiento:
- PatchGuard se inicializa durante el boot
- Toma snapshots de las estructuras protegidas
- A intervalos aleatorios (5-15 minutos), verifica que las estructuras no han cambiado
- Si detecta modificación: BSOD con código
CRITICAL_STRUCTURE_CORRUPTION(0x109) - Los intervalos y el código de verificación están ofuscados para dificultar bypass
Técnicas de bypass de PatchGuard
A lo largo de los años, investigadores han encontrado formas de bypassear PatchGuard:
| Técnica | Descripción | Estado |
|---|---|---|
| Timer manipulation | Identificar y desactivar los timers de PatchGuard | Parcheado en versiones recientes |
| DPC manipulation | Manipular Deferred Procedure Calls de PatchGuard | Parcheado |
| Exception handler hooking | Hookear el handler de excepciones que PatchGuard usa | Parcheado |
| Hypervisor interception | Usar VT-x para interceptar las verificaciones de PatchGuard | Funciona pero complejo |
| PatchGuard context identification | Identificar y manipular el contexto de PatchGuard en memoria | Cat-and-mouse con Microsoft |
| InfinityHook | Hooking via ETW callbacks dentro del kernel | Parcheado en builds recientes |
Microsoft actualiza PatchGuard regularmente. Cada bypass publicado es parcheado en la siguiente versión. Es una carrera continua.
Alternativas modernas al SSDT hooking
Dado que PatchGuard protege la SSDT, los rootkits modernos y los EDR usan estas alternativas:
| Técnica | Quién la usa | Detectable |
|---|---|---|
| Kernel callbacks (PsSetCreateProcessNotifyRoutine) | EDR + rootkits | Sí (verificar lista de callbacks) |
| Minifilter drivers | EDR + rootkits | Sí (fltMC.exe lista minifilters) |
| DKOM (Direct Kernel Object Manipulation) | Rootkits | Difícil (requiere memory forensics) |
| IRP hooking | Rootkits | Sí (verificar IRP dispatch tables) |
| Object callbacks (ObRegisterCallbacks) | EDR | Sí (verificar lista de callbacks) |
| ETW provider | EDR | Sí (verificar providers activos) |
| Inline hooking de funciones internas | Ambos | Medio (comparar código con disco) |
Detección de SSDT hooks
Con Volatility
# Plugin ssdt: compara direcciones en SSDT con rangos de modulos cargados
vol3 -f memory.dump windows.ssdt
# Output:
# Index Address Module Symbol
# 0x0055 0xfffff80012345678 ntoskrnl.exe NtCreateFile ← Normal
# 0x0035 0xfffff88001234000 rootkit.sys hooked_NtQueryDir ← HOOK!
# 0x00A1 0xfffff80012346000 ntoskrnl.exe NtOpenProcess ← Normal
# Si la direccion no apunta a ntoskrnl.exe: es un hook
# Si apunta a un modulo desconocido: rootkit
Manual: verificar rangos de direcciones
Direcciones normales en SSDT (Windows 10 x64):
ntoskrnl.exe se carga en el rango: 0xFFFFF800`10000000 - 0xFFFFF800`11000000 (aprox)
Si una entrada de la SSDT apunta a:
0xFFFFF880`01234000 ← Fuera de ntoskrnl → HOOK (apunta a un driver)
0xFFFFF800`10345678 ← Dentro de ntoskrnl → Normal
Con herramientas en vivo (pre-PatchGuard)
GMER: herramienta anti-rootkit que verifica SSDT hooks
Descargar: gmer.net
Ejecutar como admin
Tab "SSDT": muestra hooks en la SSDT y Shadow SSDT
Entradas en ROJO = hookeadas
Verificación de integridad
// Concepto: comparar SSDT en memoria con la version en disco
//
// 1. Leer ntoskrnl.exe del disco
// 2. Parsear su Export Table
// 3. Resolver las direcciones de las funciones de syscall
// 4. Comparar con las direcciones en la SSDT en memoria
// 5. Diferencias = hooks
//
// Limitacion: los offsets en x64 son relativos y dependen de KASLR
SSDT en Linux: sys_call_table
Equivalente Linux
Linux tiene un equivalente: sys_call_table, un array de punteros a funciones de syscalls.
// Rootkits Linux hookean sys_call_table de forma similar:
// 1. Encontrar sys_call_table en memoria del kernel
// 2. Desactivar write protection (CR0.WP o set_memory_rw)
// 3. Reemplazar entrada: sys_call_table[__NR_getdents64] = hooked_getdents64
// 4. Reactivar write protection
// Ejemplo: Diamorphine hookea getdents64 para ocultar archivos y procesos
Diferencias con Windows
| Aspecto | Windows SSDT | Linux sys_call_table |
|---|---|---|
| Protección | PatchGuard (x64) | No equivalente directo (KASLR + kptr_restrict dificultan encontrar la tabla) |
| Acceso | Solo via driver firmado | Requiere root + insmod |
| Formato | Offsets de 32-bit (x64) | Punteros absolutos |
| Número de syscalls | ~460 | ~440 |
| Detección | Volatility ssdt plugin | Volatility check_syscall, verificar /proc/kallsyms |
Impacto histórico del SSDT hooking
SSDT hooking fue LA técnica de rootkits en Windows durante una década (2000-2010). Definió cómo pensamos sobre rootkits de kernel y motivó la creación de PatchGuard. Aunque ya no es viable en Windows moderno, sus principios (interceptar el flujo de syscalls para filtrar información) siguen siendo la base de todas las técnicas de rootkit.
Entenderlo es necesario para:
- Analizar rootkits legacy que siguen apareciendo en sistemas antiguos
- Comprender por qué existen PatchGuard y HVCI
- Entender las alternativas modernas (DKOM, callbacks) que evolucionaron como respuesta
- Memory forensics con Volatility (el plugin ssdt es fundamental)
Mapeo MITRE ATT&CK
| Técnica | ID | Contexto |
|---|---|---|
| Rootkit | T1014 | SSDT hooking como mecanismo de ocultación |
| Modify System Image | T1601 | Modificación de la SSDT en memoria |
| Impair Defenses | T1562 | Hookear syscalls de seguridad para evadir EDR |
Fuentes y referencias
- Matrosov, A. et al. "Rootkits and Bootkits." No Starch Press, 2019.
- Hoglund, G. & Butler, J. "Rootkits: Subverting the Windows Kernel." Addison-Wesley, 2005.
- Russinovich, M. et al. "Windows Internals Part 1." Microsoft Press, 2017.
- Microsoft. "Kernel Patch Protection (PatchGuard)." Windows Hardware Developer Documentation.
- Volatility Foundation. "SSDT Plugin." Volatility 3 Documentation.
- GMER. "GMER: Rootkit Detector." http://www.gmer.net/
- j00ru. "PatchGuard Bypass Research." Google Project Zero.
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.