NtSetSystemInformation
Setter noyau générique sélectionné par SYSTEM_INFORMATION_CLASS — porte d'entrée pour SystemDebugControl, chargement de pilotes GDI, etc.
Prototype
NTSTATUS NtSetSystemInformation( SYSTEM_INFORMATION_CLASS SystemInformationClass, PVOID SystemInformation, ULONG SystemInformationLength );
Arguments
| Name | Type | Dir | Description |
|---|---|---|---|
| SystemInformationClass | SYSTEM_INFORMATION_CLASS | in | Énum sélectionnant l'opération, ex. SystemLoadGdiDriverInformation (26), SystemDebugControl (37), SystemRegistryQuotaInformation. |
| SystemInformation | PVOID | in | Tampon d'entrée propre à la classe (ex. SYSTEM_GDI_DRIVER_INFORMATION, SYSTEM_LOAD_GDI_DRIVER_INFORMATION). |
| SystemInformationLength | ULONG | in | Taille en octets du tampon SystemInformation. |
IDs de syscalls par version de Windows
| Version 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 |
Module noyau
APIs liées
Stub du 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
Notes non documentées
Contrairement à la plupart de ses voisins, le SSN de NtSetSystemInformation glisse à chaque release : `0x18E` en 1507, `0x1A4` en 1903/1909, `0x1AA` en 2004-21H1, `0x1AC` en 21H2/22H2, puis `0x1B5`/`0x1B9`/`0x1BC` sous Win11. Tout stub codé en dur *doit* s'accompagner d'une vérification de build ou d'une résolution dynamique. La fonction est le pendant en écriture de NtQuerySystemInformation, et les contrôles d'accès dépendent du `SYSTEM_INFORMATION_CLASS` choisi : la plupart des classes exigent SeTcbPrivilege, SeLoadDriverPrivilege ou SeDebugPrivilege.
Usage courant par les malwares
Deux abus notables. (1) **`SystemLoadGdiDriverInformation` (26)** chargeait historiquement un pilote GDI mode noyau à partir d'un chemin UNICODE_STRING fourni par l'appelant — vecteur classique de chargement de pilote non signé/exploitable avant KMCS. Windows moderne bloque la voie non signée sous HVCI/Vulnerable Driver Blocklist, mais les acteurs continuent à l'appeler dans les chaînes BYOVD où le pilote est lui-même signé. (2) **`SystemDebugControl` (37)** avec les sous-commandes `SysDbgReadVirtual` / `SysDbgWriteVirtual` permet à un appelant détenant `SeDebugPrivilege` de lire ou écrire en mémoire noyau sans charger de pilote — utilisé par certains rootkits et outils red-team pour des patchs noyau discrets quand l'EDR a déjà neutralisé la surface évidente de chargement de pilote. Quelques familles altèrent aussi `SystemRegistryQuotaInformation` pour saturer le registre et désactiver les composants Windows dépendant des quotas.
Opportunités de détection
Les appels à `NtSetSystemInformation` sont peu fréquents hors OS — les heuristiques volumétriques fonctionnent. La meilleure source est l'ETW `ImageLoad` Microsoft-Windows-Kernel-General couplé au callback noyau PsSetLoadImageNotifyRoutine, qui se déclenche dès qu'un pilote noyau est chargé via la classe 26 — Defender Application Control et la Microsoft Vulnerable Driver Blocklist le consomment pour bloquer les pilotes connus comme `gdrv.sys`, `RTCore64.sys`, `dbutil_2_3.sys`. Auditer `Audit Privilege Use` (Event ID 4673) pour SeLoadDriverPrivilege et SeDebugPrivilege, et guetter les appelants inattendus (autre que System, services.exe) invoquant NtSetSystemInformation. Les syscalls directs ne peuvent pas supprimer la notification de chargement de pilote, quoi qu'il fasse en user-mode.
Exemples de syscalls directs
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.)Mappings MITRE ATT&CK
Last verified: 2026-05-20