NtTerminateJobObject
Termine atomiquement chaque processus actuellement assigné à un job object.
Prototype
NTSTATUS NtTerminateJobObject( HANDLE JobHandle, NTSTATUS ExitStatus );
Arguments
| Name | Type | Dir | Description |
|---|---|---|---|
| JobHandle | HANDLE | in | Handle vers le job object, requérant l'accès JOB_OBJECT_TERMINATE. Tous les processus du job — et de tout job enfant imbriqué — sont tués. |
| ExitStatus | NTSTATUS | in | Code de sortie rapporté pour chaque processus terminé via GetExitCodeProcess. |
IDs de syscalls par version de Windows
| Version de Windows | ID de syscall | Build |
|---|---|---|
| Win10 1507 | 0x1A2 | win10-1507 |
| Win10 1607 | 0x1AB | win10-1607 |
| Win10 1703 | 0x1B1 | win10-1703 |
| Win10 1709 | 0x1B5 | win10-1709 |
| Win10 1803 | 0x1B7 | win10-1803 |
| Win10 1809 | 0x1B8 | win10-1809 |
| Win10 1903 | 0x1B9 | win10-1903 |
| Win10 1909 | 0x1B9 | win10-1909 |
| Win10 2004 | 0x1BF | win10-2004 |
| Win10 20H2 | 0x1BF | win10-20h2 |
| Win10 21H1 | 0x1BF | win10-21h1 |
| Win10 21H2 | 0x1C1 | win10-21h2 |
| Win10 22H2 | 0x1C1 | win10-22h2 |
| Win11 21H2 | 0x1CB | win11-21h2 |
| Win11 22H2 | 0x1CF | win11-22h2 |
| Win11 23H2 | 0x1CF | win11-23h2 |
| Win11 24H2 | 0x1D2 | win11-24h2 |
| Server 2016 | 0x1AB | winserver-2016 |
| Server 2019 | 0x1B8 | winserver-2019 |
| Server 2022 | 0x1C7 | winserver-2022 |
| Server 2025 | 0x1D2 | winserver-2025 |
Module noyau
APIs liées
Stub du syscall
4C 8B D1 mov r10, rcx B8 D2 01 00 00 mov eax, 0x1D2 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
NtTerminateJobObject est le côté noyau de `TerminateJobObject`. Le noyau parcourt la liste de processus du job (sous PspJobLock) et émet `PspTerminateProcess` contre chacun, donc le kill est effectivement atomique du point de vue d'un processus unique — aucune fenêtre de course où un enfant pourrait se sortir du job. Le SSN bouge à chaque release majeure (`0x1B9` Win10 1903, `0x1BF` 2004, `0x1D2` Win11 24H2 / Server 2025), la résolution dynamique est donc obligatoire pour les payloads cross-build. Le caller légitime emblématique est le processus du navigateur Chromium recyclant ses jobs renderer / GPU / utility, et `cmd /c taskkill /T /F` sur une racine d'arbre de processus en job.
Usage courant par les malwares
Relativement rare dans l'outillage offensif — la plupart des attaquants préfèrent `NtTerminateProcess` contre des processus EDR nommés individuellement (Conti, LockBit, BlackCat font tous cela). Là où NtTerminateJobObject *apparaît* : (1) ransomwares anti-analyse qui, une fois détecté et obtenu un handle sur leur job conteneur Cuckoo / Joe Sandbox, tuent toute la cohorte sandbox pour perturber la collecte d'artefacts ; (2) backdoors custom qui enveloppent des helpers user-mode victimes dans un job précisément pour pouvoir les démonter en un seul syscall à la désinstallation ; (3) outillage red-team qui, ayant abusé PROCESS_SET_QUOTA / JOB_OBJECT_ASSIGN_PROCESS pour amener un sensor EDR dans un job contrôlé, tue le job entier pour contourner l'auto-protection par processus. La technique est bruyante, facile à détecter et quasi jamais vue dans les loaders commodity.
Opportunités de détection
ETW `Microsoft-Windows-Kernel-Process/ProcessStop` se déclenche une fois par processus tué avec un cluster de timestamps très rapprochés et partagés — la preuve évidente d'une termination au niveau job versus une boucle `taskkill` séquentielle. Les callbacks PsSetCreateProcessNotifyRoutineEx voient le même motif. Sysmon Event ID 5 (`ProcessTerminate`) n'a pas le champ PID terminateur mais la rafale temporelle reste caractéristique. Règle haute fidélité : 5+ processus du même job finissant dans une fenêtre de 50 ms, terminés par un processus hors de leur chaîne parente. L'auto-protection EDR (PPL sur `MsMpEng.exe`, flag de processus protégé Defender sur `MsSense.exe`) empêche NtTerminateJobObject de tuer Defender / MDE même depuis SYSTEM — faisant de cette technique une impasse connue contre les EDR modernes protected-process.
Exemples de syscalls directs
asmx64 stub (Win11 24H2 SSN 0x1D2)
; Direct syscall stub for NtTerminateJobObject
NtTerminateJobObject PROC
mov r10, rcx ; syscall convention
mov eax, 1D2h ; SSN (Win11 24H2 / Server 2025)
syscall
ret
NtTerminateJobObject ENDPcBrowser-style sandbox recycle
// Recycle a renderer cohort: open the named job we own and terminate it.
#include <windows.h>
DWORD RecycleSandbox(const wchar_t *job_name) {
HANDLE h = OpenJobObjectW(JOB_OBJECT_TERMINATE, FALSE, job_name);
if (!h) return GetLastError();
DWORD err = 0;
if (!TerminateJobObject(h, 0xDEAD0001)) // STATUS-style exit
err = GetLastError();
CloseHandle(h);
return err;
}cAnti-sandbox: tear down Cuckoo monitor cohort
// Hostile (defensive PoC): if we detect we're inside a sandbox job and
// can open a handle to it with TERMINATE rights, kill every sibling.
// In practice the monitor strips JOB_OBJECT_TERMINATE from descendants —
// this rarely works, hence why ransomware prefers per-process killing.
#include <windows.h>
typedef NTSTATUS (NTAPI *pNtTerminateJobObject)(HANDLE, NTSTATUS);
BOOL NukeContainingJob(void) {
// Acquire a handle via OpenProcess + duplicating the job from a sibling
// is a non-trivial dance; abbreviated here.
HANDLE h_job = /* ... */ NULL;
if (!h_job) return FALSE;
pNtTerminateJobObject NtTerminateJobObject = (pNtTerminateJobObject)GetProcAddress(
GetModuleHandleA("ntdll.dll"), "NtTerminateJobObject");
return NtTerminateJobObject(h_job, 0) == 0;
}Mappings MITRE ATT&CK
Last verified: 2026-05-20