AvanzadorootkitsSSDThookingkernelWindowsPatchGuard

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.

MalwareIntel Research··9 min lectura
Serie: Rootkits y Bootkits — Parte 3

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:

TablaContenidoAccesible 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
NtQueryDirectoryFileVariableArchivos y directorios
NtQuerySystemInformationVariableProcesos (class SystemProcessInformation)
NtEnumerateKeyVariableClaves de registro
NtEnumerateValueKeyVariableValores de registro
NtDeviceIoControlFileVariableConexiones de red (via TDI/AFD)
NtReadFileVariableContenido de archivos (filtrar datos)
NtQueryInformationProcessVariableInformación de procesos
NtTerminateProcessVariableProteger 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:

  1. PatchGuard se inicializa durante el boot
  2. Toma snapshots de las estructuras protegidas
  3. A intervalos aleatorios (5-15 minutos), verifica que las estructuras no han cambiado
  4. Si detecta modificación: BSOD con código CRITICAL_STRUCTURE_CORRUPTION (0x109)
  5. 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écnicaDescripciónEstado
Timer manipulationIdentificar y desactivar los timers de PatchGuardParcheado en versiones recientes
DPC manipulationManipular Deferred Procedure Calls de PatchGuardParcheado
Exception handler hookingHookear el handler de excepciones que PatchGuard usaParcheado
Hypervisor interceptionUsar VT-x para interceptar las verificaciones de PatchGuardFunciona pero complejo
PatchGuard context identificationIdentificar y manipular el contexto de PatchGuard en memoriaCat-and-mouse con Microsoft
InfinityHookHooking via ETW callbacks dentro del kernelParcheado 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écnicaQuién la usaDetectable
Kernel callbacks (PsSetCreateProcessNotifyRoutine)EDR + rootkitsSí (verificar lista de callbacks)
Minifilter driversEDR + rootkitsSí (fltMC.exe lista minifilters)
DKOM (Direct Kernel Object Manipulation)RootkitsDifícil (requiere memory forensics)
IRP hookingRootkitsSí (verificar IRP dispatch tables)
Object callbacks (ObRegisterCallbacks)EDRSí (verificar lista de callbacks)
ETW providerEDRSí (verificar providers activos)
Inline hooking de funciones internasAmbosMedio (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

AspectoWindows SSDTLinux sys_call_table
ProtecciónPatchGuard (x64)No equivalente directo (KASLR + kptr_restrict dificultan encontrar la tabla)
AccesoSolo via driver firmadoRequiere root + insmod
FormatoOffsets de 32-bit (x64)Punteros absolutos
Número de syscalls~460~440
DetecciónVolatility ssdt pluginVolatility 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écnicaIDContexto
RootkitT1014SSDT hooking como mecanismo de ocultación
Modify System ImageT1601Modificación de la SSDT en memoria
Impair DefensesT1562Hookear 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

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.