> Windows Syscalls
ntoskrnl.exeT1106T1564

NtAssignProcessToJobObject

Attaches a process to a job object so that the job's limits, accounting and termination policy apply to it.

Prototype

NTSTATUS NtAssignProcessToJobObject(
  HANDLE JobHandle,
  HANDLE ProcessHandle
);

Arguments

NameTypeDirDescription
JobHandleHANDLEinHandle to the target job (JOB_OBJECT_ASSIGN_PROCESS required).
ProcessHandleHANDLEinHandle to the process being assigned (PROCESS_SET_QUOTA | PROCESS_TERMINATE). Must not already be in an incompatible job (nested jobs were relaxed in Win8+).

Syscall IDs by Windows version

Windows versionSyscall IDBuild
Win10 15070x8Bwin10-1507
Win10 16070x8Bwin10-1607
Win10 17030x8Cwin10-1703
Win10 17090x8Cwin10-1709
Win10 18030x8Dwin10-1803
Win10 18090x8Dwin10-1809
Win10 19030x8Dwin10-1903
Win10 19090x8Dwin10-1909
Win10 20040x8Fwin10-2004
Win10 20H20x8Fwin10-20h2
Win10 21H10x8Fwin10-21h1
Win10 21H20x8Fwin10-21h2
Win10 22H20x8Fwin10-22h2
Win11 21H20x8Fwin11-21h2
Win11 22H20x8Fwin11-22h2
Win11 23H20x8Fwin11-23h2
Win11 24H20x91win11-24h2
Server 20160x8Bwinserver-2016
Server 20190x8Dwinserver-2019
Server 20220x8Fwinserver-2022
Server 20250x91winserver-2025

Kernel module

ntoskrnl.exeNtAssignProcessToJobObject

Related APIs

AssignProcessToJobObjectCreateJobObjectWIsProcessInJobNtCreateJobObjectNtSetInformationJobObjectNtQueryInformationJobObject

Syscall stub

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

Undocumented notes

NtAssignProcessToJobObject is the wiring step that turns a freshly created job into something that actually affects a process. Once assigned, the process inherits every limit set on the job (working-set caps, UI restrictions, CPU rate, breakaway policy) and contributes to the job's accounting. Before Windows 8, a process could be in at most one job; nested jobs since Win8 mean the kernel walks a job chain on every check. The classic sandbox pattern is `NtCreateJobObject → NtSetInformationJobObject(limits + UI restrictions) → NtCreateUserProcess(suspended) → NtAssignProcessToJobObject → NtResumeThread`.

Common malware usage

Defensive in the vast majority of cases. The offensive interest is sandbox-aware: if the job allows JOB_OBJECT_LIMIT_BREAKAWAY_OK, a child spawned with CREATE_BREAKAWAY_FROM_JOB escapes the container; many AppContainer and Chromium sandbox bypasses pivot on this fact. A few red-team frameworks call NtAssignProcessToJobObject on their own implant to attach a KILL_ON_JOB_CLOSE policy so closing the implant handle reaps every spawned helper — useful for clean withdrawal. Weak signal in isolation, meaningful only in chain with NtSetInformationJobObject and policy queries.

Detection opportunities

No dedicated Sysmon event. ETW Microsoft-Windows-Kernel-Process records changes to a process's job membership; pairing the assignment with the originating process (who owns JobHandle?) is the actionable signal. EDR-side hooks on NtAssignProcessToJobObject should correlate with the immediately preceding NtCreateJobObject and any NtSetInformationJobObject calls that set BREAKAWAY_OK or KILL_ON_JOB_CLOSE. The high-value detection is a process attaching itself to a fresh job and then immediately spawning children with CREATE_BREAKAWAY_FROM_JOB — that is sandbox-escape shape, not normal sandbox shape.

Direct syscall examples

asmx64 direct stub (Win11 24H2 SSN)

; Direct syscall stub for NtAssignProcessToJobObject (SSN 0x91 on Win11 24H2 / Server 2025)
NtAssignProcessToJobObject PROC
    mov  r10, rcx          ; syscall convention
    mov  eax, 091h         ; SSN for win11-24h2
    syscall
    ret
NtAssignProcessToJobObject ENDP

cSandbox-spawn skeleton (step 2 — assign suspended child)

// Continued from NtCreateJobObject / NtSetInformationJobObject sandbox setup.
// Spawn the target suspended, attach to the job, only then resume.
PROCESS_INFORMATION pi = { 0 };
STARTUPINFOW si = { sizeof(si) };
CreateProcessW(L"C:\\Windows\\System32\\notepad.exe",
               NULL, NULL, NULL, FALSE,
               CREATE_SUSPENDED,
               NULL, NULL, &si, &pi);

NTSTATUS s = NtAssignProcessToJobObject(hJob, pi.hProcess);
if (!NT_SUCCESS(s)) {
    TerminateProcess(pi.hProcess, 1);
    return s;
}

NtResumeThread(pi.hThread, NULL);   // job limits are now in effect for the child

rustwindows-sys + naked syscall stub

// Cargo: windows-sys = "0.59"  (Win32_System_JobObjects)
use std::arch::asm;

#[unsafe(naked)]
unsafe extern "system" fn nt_assign_process_to_job_object_stub() {
    asm!(
        "mov r10, rcx",
        "mov eax, 0x91",    // Win11 24H2; resolve dynamically for other builds
        "syscall",
        "ret",
        options(noreturn),
    );
}

MITRE ATT&CK mappings

Last verified: 2026-05-20