NtSystemDebugControl
Leitet Kerneldebugger-artige Anfragen weiter (Kernel-R/W, Control Space, Breakpoints, Profiler), ausgewählt über die SysDbgCommand-Enum.
Prototyp
NTSTATUS NtSystemDebugControl( SYSDBG_COMMAND Command, PVOID InputBuffer, ULONG InputBufferLength, PVOID OutputBuffer, ULONG OutputBufferLength, PULONG ReturnLength );
Argumente
| Name | Type | Dir | Description |
|---|---|---|---|
| Command | SYSDBG_COMMAND | in | Operations-Selektor: SysDbgReadVirtual, SysDbgWriteVirtual, SysDbgReadPhysical, SysDbgWritePhysical, SysDbgReadControlSpace, SysDbgGetTriageDump, SysDbgBreakPoint usw. |
| InputBuffer | PVOID | in | Befehlsspezifischer Eingabepuffer (üblicherweise ein SYSDBG_VIRTUAL- oder SYSDBG_PHYSICAL-Deskriptor mit Address/Buffer/Request). |
| InputBufferLength | ULONG | in | Größe von InputBuffer in Bytes. |
| OutputBuffer | PVOID | out | Befehlsspezifischer Ausgabepuffer (z. B. empfängt Daten für SysDbgReadVirtual). |
| OutputBufferLength | ULONG | in | Größe von OutputBuffer in Bytes. |
| ReturnLength | PULONG | out | Optional. Erhält die Anzahl tatsächlich in OutputBuffer geschriebener Bytes. |
Syscall-IDs pro Windows-Version
| Windows-Version | Syscall-ID | Build |
|---|---|---|
| Win10 1507 | 0x1A1 | win10-1507 |
| Win10 1607 | 0x1AA | win10-1607 |
| Win10 1703 | 0x1B0 | win10-1703 |
| Win10 1709 | 0x1B3 | win10-1709 |
| Win10 1803 | 0x1B5 | win10-1803 |
| Win10 1809 | 0x1B6 | win10-1809 |
| Win10 1903 | 0x1B7 | win10-1903 |
| Win10 1909 | 0x1B7 | win10-1909 |
| Win10 2004 | 0x1BD | win10-2004 |
| Win10 20H2 | 0x1BD | win10-20h2 |
| Win10 21H1 | 0x1BD | win10-21h1 |
| Win10 21H2 | 0x1BF | win10-21h2 |
| Win10 22H2 | 0x1BF | win10-22h2 |
| Win11 21H2 | 0x1C9 | win11-21h2 |
| Win11 22H2 | 0x1CD | win11-22h2 |
| Win11 23H2 | 0x1CD | win11-23h2 |
| Win11 24H2 | 0x1D0 | win11-24h2 |
| Server 2016 | 0x1AA | winserver-2016 |
| Server 2019 | 0x1B6 | winserver-2019 |
| Server 2022 | 0x1C5 | winserver-2022 |
| Server 2025 | 0x1D0 | winserver-2025 |
Kernel-Modul
Verwandte APIs
Syscall-Stub
4C 8B D1 mov r10, rcx B8 D0 01 00 00 mov eax, 0x1D0 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
Undokumentierte Hinweise
NtSystemDebugControl ist ein Multiplexer für debuggerartige Kerneloperationen. Die Command-Enum (SYSDBG_COMMAND / SysDbgCommand) wählt zwischen virtuellem/physikalischem Speicher lesen und schreiben, Control-Space-Zugriff, MSR-Lesen, Profiler-Steuerung, Breakpoint-Installation, Triage-Dump-Abruf und mehreren Legacy-Befehlen. *Entscheidend*: auf Free-/Retail-Builds hat Microsoft die wirklich mächtigen Befehle schrittweise eingeschränkt: SysDbgReadVirtual, SysDbgWriteVirtual, SysDbgReadPhysical und SysDbgWritePhysical liefern STATUS_NOT_IMPLEMENTED zurück, sofern das System nicht einen Debug-(Checked-)Kernel ausführt oder mit `/DEBUG` und aktivem Kernel-Debugger gestartet wurde. Auf einem normalen Win10-/Win11-Desktop sind diese Bytes wirkungslos. Der Aufrufer benötigt zusätzlich SeDebugPrivilege.
Häufige Malware-Nutzung
Historisch — Windows XP und frühes Vista — bot NtSystemDebugControl mit SysDbgReadVirtual/WriteVirtual eine saubere Userland-zu-Kernel-R/W-Primitive, die mehrere Rootkits ausnutzten. Rustock und der Kernel-Treiber von BlackEnergy 2 werden oft als Beispiele genannt; zahlreiche Forschungs-PoCs derselben Ära nutzten sie für SSDT-Patching und Manipulation an Kernelstrukturen. Seit Vista x64 + PatchGuard + Free-Build-Restriktion ist dieser Weg auf modernen Systemen praktisch geschlossen. Moderne Malware missbraucht NtSystemDebugControl nicht mehr für Kernel-R/W — der Pfad ist zu. Indirekte Nutzungen halten sich: SysDbgGetTriageDump kann von Anti-Analyse-Code aufgerufen werden, um die Anwesenheit eines Kernel-Debuggers oder aktiven Profilers zu erkennen.
Erkennungsmöglichkeiten
Auf einem modernen System ist *jeder* erfolgreiche Aufruf von NtSystemDebugControl aus einem Nicht-Debugger-Prozess verdächtig. ETW Microsoft-Windows-Kernel-Audit-API-Calls deckt die privilegierte Debugger-Oberfläche ab, und die Nutzung von SeDebugPrivilege erscheint in der Sicherheitsauditierung (Event ID 4673). EDR-seitig ntdll!NtSystemDebugControl hooken, den Befehl dekodieren und SysDbgReadVirtual / SysDbgWriteVirtual / SysDbgReadControlSpace / SysDbgReadMsr unabhängig vom Rückgabestatus als hochkonfidente Indikatoren behandeln. Aufrufe, die STATUS_NOT_IMPLEMENTED zurückliefern, sind selbst ein loggenswertes Sondierungssignal.
Direkte Syscall-Beispiele
asmx64 direct stub (Win11 24H2 SSN)
; Direct syscall stub for NtSystemDebugControl (SSN 0x1D0 on Win11 24H2 / Server 2025)
NtSystemDebugControl PROC
mov r10, rcx ; syscall convention
mov eax, 1D0h ; SSN for win11-24h2
syscall
ret
NtSystemDebugControl ENDPcSysDbgReadVirtual sketch (gated on free builds)
// Read N bytes from a kernel virtual address.
// On a stock Win10/Win11 system this returns STATUS_NOT_IMPLEMENTED.
// Only works against a checked kernel or with the system booted /DEBUG.
typedef enum _SYSDBG_COMMAND {
SysDbgReadVirtual = 8,
SysDbgWriteVirtual = 9,
SysDbgReadPhysical = 10,
SysDbgWritePhysical = 11,
SysDbgReadControlSpace = 12,
SysDbgGetTriageDump = 29,
} SYSDBG_COMMAND;
typedef struct _SYSDBG_VIRTUAL {
PVOID Address;
PVOID Buffer;
ULONG Request;
} SYSDBG_VIRTUAL, *PSYSDBG_VIRTUAL;
// caller must have SeDebugPrivilege enabled
BYTE buf[16] = { 0 };
SYSDBG_VIRTUAL in = {
.Address = (PVOID)0xfffff80000000000ULL, // some kernel VA
.Buffer = buf,
.Request = sizeof(buf),
};
ULONG returned = 0;
NTSTATUS s = NtSystemDebugControl(SysDbgReadVirtual,
&in, sizeof(in),
NULL, 0,
&returned);
// On a free build: s == STATUS_NOT_IMPLEMENTED (0xC0000002).rustwindows-sys + naked syscall stub
// Cargo: windows-sys = "0.59"
use std::arch::asm;
#[unsafe(naked)]
unsafe extern "system" fn nt_system_debug_control_stub() {
asm!(
"mov r10, rcx",
"mov eax, 0x1D0", // Win11 24H2; resolve dynamically for other builds
"syscall",
"ret",
options(noreturn),
);
}MITRE ATT&CK-Mappings
Last verified: 2026-05-20