NtGetContextThread
Liest den CPU-Registerkontext (CONTEXT-Struktur) eines suspendierten Threads aus.
Prototyp
NTSTATUS NtGetContextThread( HANDLE ThreadHandle, PCONTEXT ThreadContext );
Argumente
| Name | Type | Dir | Description |
|---|---|---|---|
| ThreadHandle | HANDLE | in | Handle auf den Ziel-Thread. Erfordert THREAD_GET_CONTEXT-Zugriff. |
| ThreadContext | PCONTEXT | in/out | Architekturspezifische CONTEXT-Struktur. ContextFlags (Eingabe) wählt zurückgegebene Registergruppen; auf x64 muss die Struktur 16-Byte-aligned sein. |
Syscall-IDs pro Windows-Version
| Windows-Version | Syscall-ID | Build |
|---|---|---|
| Win10 1507 | 0xE3 | win10-1507 |
| Win10 1607 | 0xE6 | win10-1607 |
| Win10 1703 | 0xE9 | win10-1703 |
| Win10 1709 | 0xEA | win10-1709 |
| Win10 1803 | 0xEB | win10-1803 |
| Win10 1809 | 0xEC | win10-1809 |
| Win10 1903 | 0xED | win10-1903 |
| Win10 1909 | 0xED | win10-1909 |
| Win10 2004 | 0xF2 | win10-2004 |
| Win10 20H2 | 0xF2 | win10-20h2 |
| Win10 21H1 | 0xF2 | win10-21h1 |
| Win10 21H2 | 0xF3 | win10-21h2 |
| Win10 22H2 | 0xF3 | win10-22h2 |
| Win11 21H2 | 0xF8 | win11-21h2 |
| Win11 22H2 | 0xF9 | win11-22h2 |
| Win11 23H2 | 0xF9 | win11-23h2 |
| Win11 24H2 | 0xFB | win11-24h2 |
| Server 2016 | 0xE6 | winserver-2016 |
| Server 2019 | 0xEC | winserver-2019 |
| Server 2022 | 0xF7 | winserver-2022 |
| Server 2025 | 0xFB | winserver-2025 |
Kernel-Modul
Verwandte APIs
Syscall-Stub
4C 8B D1 mov r10, rcx B8 FB 00 00 00 mov eax, 0xFB 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
Die CONTEXT-Struktur ist architekturspezifisch und sperrig: auf x64 sind es 1232 Bytes (CONTEXT) plus ein erweiterter XSTATE-Bereich, dessen Größe von den aktivierten CPU-Features abhängt (AVX-512-Enclaves können sie über 2,5 KB drücken). Aufrufer müssen ContextFlags vor dem Aufruf setzen — CONTEXT_CONTROL (Rip, Rsp, EFlags), CONTEXT_INTEGER (Rax..R15), CONTEXT_SEGMENTS, CONTEXT_DEBUG_REGISTERS (DR0..DR7), CONTEXT_FLOATING_POINT, CONTEXT_XSTATE. Der Thread sollte suspendiert sein; das Lesen des Kontexts eines laufenden Threads liefert einen Snapshot, der bei Ankunft veraltet sein kann.
Häufige Malware-Nutzung
Die Lesehälfte der Thread-Hijacking-Primitive: suspendieren → Kontext holen → Rip/Rsp patchen → Kontext setzen → fortsetzen. Auch von Anti-Debug-Code genutzt, um DR0–DR3 eigener Threads zu lesen und vom Analysten gesetzte Hardware-Breakpoints zu erkennen (`if (ctx.Dr0 || ctx.Dr1 || ctx.Dr2 || ctx.Dr3) bail();`). Manche Sandboxes markieren Threads mit Sentinel-Werten in ungenutzten Segmentselektoren, und Packer prüfen darauf. Cobalt Strikes `inject`-BOFs, Sliver migrate, ScareCrow und die meisten Early-Bird-APC-Varianten gehen hier durch.
Erkennungsmöglichkeiten
Allein hat NtGetContextThread mäßiges Volumen — Debugger, .NET-Runtime, Profiler und Exception-Handler lesen den Kontext. Cross-Process-Lesungen auf nicht debuggte Ziele sind weit seltener; Microsoft-Windows-Threat-Intelligence-ETW-Telemetrie mit Prozessbeziehungskontext (Parent/Child, Signer) korrelieren. Die handlungsrelevanteste Detektion ist die *Sequenz* NtSuspendThread → NtGetContextThread → NtSetContextThread → NtResumeThread in kurzem Fenster auf einem Remote-Thread.
Direkte Syscall-Beispiele
cHardware-breakpoint anti-debug self-check
// Detect analyst-set DR0..DR3 on our own primary thread.
CONTEXT ctx = { .ContextFlags = CONTEXT_DEBUG_REGISTERS };
if (NT_SUCCESS(NtGetContextThread(NtCurrentThread(), &ctx))) {
if (ctx.Dr0 | ctx.Dr1 | ctx.Dr2 | ctx.Dr3) {
// Hardware breakpoint installed -> exit silently.
NtTerminateProcess(NtCurrentProcess(), 0);
}
}asmx64 stub (Win11 24H2)
NtGetContextThread PROC
mov r10, rcx ; ThreadHandle
mov eax, 0FBh ; Win11 24H2 SSN
syscall
ret
NtGetContextThread ENDPrustRead RIP of suspended thread
use windows_sys::Win32::System::Diagnostics::Debug::*;
unsafe fn read_rip(h_thread: isize) -> Option<u64> {
let mut ctx: CONTEXT = std::mem::zeroed();
ctx.ContextFlags = CONTEXT_CONTROL_AMD64; // RIP, RSP, SegCS, EFlags
// Direct-syscall wrapper omitted for brevity.
if nt_get_context_thread(h_thread, &mut ctx) >= 0 { Some(ctx.Rip) } else { None }
}MITRE ATT&CK-Mappings
Last verified: 2026-05-20