> Windows Syscalls
ntoskrnl.exeT1562.001T1055.003T1106

NtTerminateThread

Termine le thread spécifié avec le code de sortie fourni. Un handle NULL termine le thread courant.

Prototype

NTSTATUS NtTerminateThread(
  HANDLE   ThreadHandle,
  NTSTATUS ExitStatus
);

Arguments

NameTypeDirDescription
ThreadHandleHANDLEinHandle vers le thread à terminer. NULL signifie le thread courant.
ExitStatusNTSTATUSinCode de sortie NTSTATUS enregistré pour le thread.

IDs de syscalls par version de Windows

Version de WindowsID de syscallBuild
Win10 15070x53win10-1507
Win10 16070x53win10-1607
Win10 17030x53win10-1703
Win10 17090x53win10-1709
Win10 18030x53win10-1803
Win10 18090x53win10-1809
Win10 19030x53win10-1903
Win10 19090x53win10-1909
Win10 20040x53win10-2004
Win10 20H20x53win10-20h2
Win10 21H10x53win10-21h1
Win10 21H20x53win10-21h2
Win10 22H20x53win10-22h2
Win11 21H20x53win11-21h2
Win11 22H20x53win11-22h2
Win11 23H20x53win11-23h2
Win11 24H20x53win11-24h2
Server 20160x53winserver-2016
Server 20190x53winserver-2019
Server 20220x53winserver-2022
Server 20250x53winserver-2025

Module noyau

ntoskrnl.exeNtTerminateThread

APIs liées

TerminateThreadExitThreadNtTerminateProcessNtSuspendThreadRtlExitUserThread

Stub du syscall

4C 8B D1            mov r10, rcx
B8 53 00 00 00      mov eax, 0x53
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

SSN agréablement stable — 0x53 de Windows 10 1507 jusqu'à Windows 11 24H2 — car NtTerminateThread se situe tôt dans la SSDT alphabétique et peu de routines en amont ont été ajoutées. L'implémentation noyau passe par PsTerminateThreadByPointer, décrémente la rundown reference, signale les waiters et finit par récolter l'objet thread. Appelé avec un handle NULL, le noyau substitue le thread courant (sémantique ZwCurrentThread / (HANDLE)-2).

Usage courant par les malwares

Trois schémas classiques. (1) Stopper une course : terminer un thread de scan EDR en plein scan pour qu'une écriture disque se termine avant la re-vérification. (2) Nettoyage de stub : après détournement d'un thread (NtSetContextThread vers shellcode), le payload finit par appeler NtTerminateThread(NULL, 0) pour jeter le thread détourné sans invoquer la chaîne de retour désormais corrompue. (3) Suicide sur détection de tampering : beaucoup de crypters appellent NtTerminateThread sur eux-mêmes dès qu'ils détectent un debugger attaché pour priver l'analyste d'un processus vivant. Souvent couplé à NtTerminateProcess pour un auto-effacement complet.

Opportunités de détection

L'auto-terminaison est du bruit invisible. La terminaison inter-processus d'un thread d'*un autre* processus est rare et porteuse de signal — la plupart du code légitime appelle plutôt NtTerminateProcess. À capter via Microsoft-Windows-Threat-Intelligence ETW (EtwTiLogTerminateThread sur certains builds) ou un PsSetCreateThreadNotifyRoutine guettant des valeurs TerminationStatus inhabituelles depuis des PID non-système. Sur Windows moderne, le signal le plus utile est la *corrélation* : NtOpenThread inter-processus suivi en quelques millisecondes par un NtTerminateThread visant un PID de produit de sécurité.

Exemples de syscalls directs

asmx64 stub (stable across builds)

; SSN 0x53 — stable Win10 1507 .. Win11 24H2.
NtTerminateThread PROC
    mov  r10, rcx
    mov  eax, 53h
    syscall
    ret
NtTerminateThread ENDP

cSelf-terminate after payload

// At the tail of injected shellcode: cleanly exit the hijacked thread so the
// stack/return-address damage from the hijack never executes.
static VOID PayloadEpilogue(VOID) {
    // ... shellcode work ...
    typedef NTSTATUS (NTAPI *pNtTerminateThread)(HANDLE, NTSTATUS);
    pNtTerminateThread NtTerm = (pNtTerminateThread)
        GetProcAddress(GetModuleHandleA("ntdll.dll"), "NtTerminateThread");
    NtTerm(NULL, 0);   // NULL = current thread
}

rustDirect syscall, current thread

use std::arch::asm;

#[inline(never)]
unsafe fn nt_terminate_current_thread() -> ! {
    asm!(
        "mov r10, rcx",
        "mov eax, 0x53",
        "syscall",
        in("rcx") 0usize,    // ThreadHandle = NULL -> current
        in("rdx") 0usize,    // ExitStatus  = 0
        options(noreturn),
    );
}

Mappings MITRE ATT&CK

Last verified: 2026-05-20