> Windows Syscalls
ntoskrnl.exeT1055.003T1055.004T1106

NtSetContextThread

Setzt den CPU-Registerkontext eines Threads — die Kernel-Primitive hinter Thread-Hijacking und Shellcode-Umleitung.

Prototyp

NTSTATUS NtSetContextThread(
  HANDLE    ThreadHandle,
  PCONTEXT  ThreadContext
);

Argumente

NameTypeDirDescription
ThreadHandleHANDLEinHandle auf den Ziel-Thread. Erfordert THREAD_SET_CONTEXT-Zugriff (und idealerweise THREAD_SUSPEND_RESUME).
ThreadContextPCONTEXTinVollständig befüllte architekturspezifische CONTEXT-Struktur (1232 B auf x64 plus optional XSTATE). ContextFlags wählt anzuwendende Registergruppen.

Syscall-IDs pro Windows-Version

Windows-VersionSyscall-IDBuild
Win10 15070x16Fwin10-1507
Win10 16070x178win10-1607
Win10 17030x17Ewin10-1703
Win10 17090x181win10-1709
Win10 18030x183win10-1803
Win10 18090x184win10-1809
Win10 19030x185win10-1903
Win10 19090x185win10-1909
Win10 20040x18Bwin10-2004
Win10 20H20x18Bwin10-20h2
Win10 21H10x18Bwin10-21h1
Win10 21H20x18Dwin10-21h2
Win10 22H20x18Dwin10-22h2
Win11 21H20x195win11-21h2
Win11 22H20x198win11-22h2
Win11 23H20x198win11-23h2
Win11 24H20x19Awin11-24h2
Server 20160x178winserver-2016
Server 20190x184winserver-2019
Server 20220x193winserver-2022
Server 20250x19Awinserver-2025

Kernel-Modul

ntoskrnl.exeNtSetContextThread

Verwandte APIs

SetThreadContextWow64SetThreadContextNtGetContextThreadNtContinueNtQueueApcThreadAddVectoredExceptionHandler

Syscall-Stub

4C 8B D1            mov r10, rcx
B8 9A 01 00 00      mov eax, 0x19A
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 wirkmächtige Hälfte des Kontext-Paares. Der Kernel validiert den CONTEXT — CS muss ein zulässiger User-Mode-Selektor sein, EFlags hat reservierte Bits maskiert, und auf CET-fähigen Systemen (Windows 10 20H2+ mit HW-Shadow-Stack) werden SSP/Ssp-Anpassungen von KeVerifyContextRecord saniert. Die CONTEXT-Struktur ist *architekturspezifisch*: 1232 Bytes auf x64, 716 auf x86, ~880 auf ARM64 — und Wow64SetThreadContext existiert, um x86-auf-x64 zu überbrücken, indem es das 32-Bit-CONTEXT in den entsprechenden WOW64-Bereich schreibt. Auf Builds mit erzwungenem CET können Schreibvorgänge auf Rip, die auf nicht CFG/IBT-getaggten Code zeigen, mit STATUS_SET_CONTEXT_DENIED fehlschlagen.

Häufige Malware-Nutzung

Die kanonische Shellcode-Injection-Primitive (T1055.003 Thread Execution Hijacking). Vollständige Sequenz: NtAllocateVirtualMemory(RWX) → NtWriteVirtualMemory(shellcode) → NtOpenThread → NtSuspendThread → NtGetContextThread → ctx.Rip = shellcode → NtSetContextThread → NtResumeThread. Varianten: (a) Early Bird — eine APC einreihen, dann Kontext setzen, um sie beim ersten alertablen Wait auszulösen. (b) Hardware-Breakpoint-Hooking — DR0..DR3 mit Adressen von Zielfunktionen und DR7 mit Steuerbits schreiben, dann die entstehenden #DB-Exceptions in einem VEH-Handler verarbeiten, um Userland-Hooks zu implementieren, die für Inline-Hook-Scanner unsichtbar sind. (c) CET-Bypass-Versuche, die XSTATE-/Shadow-Stack-Pointer-Felder missbrauchen.

Erkennungs­möglichkeiten

NtSetContextThread auf einen Remote-Thread ist eines der signalstärksten Ereignisse in Windows. Microsoft-Windows-Threat-Intelligence-ETW exponiert EtwTiLogSetContextThread mit Quell-/Ziel-PID und neuem Rip — auf jeden Cross-Process-Aufruf alarmieren, dessen neues Rip auf private (nicht image-backed) Memory zeigt. EDRs hooken üblicherweise im User-Mode per Inline-Patch in ntdll!NtSetContextThread; direkte Syscalls umgehen das, TI-ETW bleibt. CET / Shadow-Stack auf unterstützten CPUs macht das klassische Rip-Umschreiben weniger zuverlässig und bringt fehlgeschlagene Versuche als Bugchecks vom Typ KERNEL_SECURITY_CHECK_FAILURE zu Tage, wenn der Angreifer den neuen Kontext fehlerhaft konfiguriert.

Direkte Syscall-Beispiele

cClassic SetThreadContext shellcode hijack

// Assumes shellcode already written to remoteShellcode in target process.
CONTEXT ctx = { .ContextFlags = CONTEXT_FULL };
NtSuspendThread(hThread, NULL);
NtGetContextThread(hThread, &ctx);
ctx.Rip = (DWORD64)remoteShellcode;     // redirect on resume
NtSetContextThread(hThread, &ctx);
NtResumeThread(hThread, NULL);

cHardware-breakpoint hook install

// Install a userland hook on a target function via DR0 + #DB VEH handler.
CONTEXT ctx = { .ContextFlags = CONTEXT_DEBUG_REGISTERS };
NtGetContextThread(hTargetThread, &ctx);
ctx.Dr0 = (DWORD64)pTargetFn;
ctx.Dr7 = (1ULL << 0)  /* L0 */ |
          (0ULL << 16) /* RW0=00 execute */ |
          (0ULL << 18) /* LEN0=00 1-byte */;
NtSetContextThread(hTargetThread, &ctx);
// AddVectoredExceptionHandler then catches EXCEPTION_SINGLE_STEP at pTargetFn.

rustx64 stub (Win11 24H2)

use std::arch::asm;

#[unsafe(naked)]
unsafe extern "system" fn nt_set_context_thread_stub() {
    asm!(
        "mov r10, rcx",
        "mov eax, 0x19A",        // Win11 24H2 SSN
        "syscall",
        "ret",
        options(noreturn),
    );
}

MITRE ATT&CK-Mappings

Last verified: 2026-05-20