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
| Name | Type | Dir | Description |
|---|---|---|---|
| ThreadHandle | HANDLE | in | Handle vers le thread à terminer. NULL signifie le thread courant. |
| ExitStatus | NTSTATUS | in | Code de sortie NTSTATUS enregistré pour le thread. |
IDs de syscalls par version de Windows
| Version de Windows | ID de syscall | Build |
|---|---|---|
| Win10 1507 | 0x53 | win10-1507 |
| Win10 1607 | 0x53 | win10-1607 |
| Win10 1703 | 0x53 | win10-1703 |
| Win10 1709 | 0x53 | win10-1709 |
| Win10 1803 | 0x53 | win10-1803 |
| Win10 1809 | 0x53 | win10-1809 |
| Win10 1903 | 0x53 | win10-1903 |
| Win10 1909 | 0x53 | win10-1909 |
| Win10 2004 | 0x53 | win10-2004 |
| Win10 20H2 | 0x53 | win10-20h2 |
| Win10 21H1 | 0x53 | win10-21h1 |
| Win10 21H2 | 0x53 | win10-21h2 |
| Win10 22H2 | 0x53 | win10-22h2 |
| Win11 21H2 | 0x53 | win11-21h2 |
| Win11 22H2 | 0x53 | win11-22h2 |
| Win11 23H2 | 0x53 | win11-23h2 |
| Win11 24H2 | 0x53 | win11-24h2 |
| Server 2016 | 0x53 | winserver-2016 |
| Server 2019 | 0x53 | winserver-2019 |
| Server 2022 | 0x53 | winserver-2022 |
| Server 2025 | 0x53 | winserver-2025 |
Module noyau
APIs liées
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 ENDPcSelf-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