> Windows Syscalls
ntoskrnl.exeT1497.001T1497T1106

NtIsProcessInJob

Tests whether a process is running inside a specific (or any) job object.

Prototype

NTSTATUS NtIsProcessInJob(
  HANDLE ProcessHandle,
  HANDLE JobHandle
);

Arguments

NameTypeDirDescription
ProcessHandleHANDLEinHandle to the process to test. Requires PROCESS_QUERY_LIMITED_INFORMATION. Often NtCurrentProcess() ((HANDLE)-1).
JobHandleHANDLEinOptional handle to a specific job. NULL asks "is the process in *any* job?" — the canonical sandbox-detection form.

Syscall IDs by Windows version

Windows versionSyscall IDBuild
Win10 15070x4Fwin10-1507
Win10 16070x4Fwin10-1607
Win10 17030x4Fwin10-1703
Win10 17090x4Fwin10-1709
Win10 18030x4Fwin10-1803
Win10 18090x4Fwin10-1809
Win10 19030x4Fwin10-1903
Win10 19090x4Fwin10-1909
Win10 20040x4Fwin10-2004
Win10 20H20x4Fwin10-20h2
Win10 21H10x4Fwin10-21h1
Win10 21H20x4Fwin10-21h2
Win10 22H20x4Fwin10-22h2
Win11 21H20x4Fwin11-21h2
Win11 22H20x4Fwin11-22h2
Win11 23H20x4Fwin11-23h2
Win11 24H20x4Fwin11-24h2
Server 20160x4Fwinserver-2016
Server 20190x4Fwinserver-2019
Server 20220x4Fwinserver-2022
Server 20250x4Fwinserver-2025

Kernel module

ntoskrnl.exeNtIsProcessInJob

Related APIs

IsProcessInJobNtCreateJobObjectNtAssignProcessToJobObjectNtQueryInformationJobObjectNtQueryInformationProcess

Syscall stub

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

NtIsProcessInJob carries SSN `0x4F` across every Windows 10 / 11 / Server build — a remarkable stability that makes it ideal for hardcoded syscall stubs. Despite the NTSTATUS return type, the Win32 wrapper `IsProcessInJob` exposes a BOOLEAN out-parameter: the kernel returns `STATUS_PROCESS_IN_JOB` (0x00000123) or `STATUS_PROCESS_NOT_IN_JOB` (0x00000124), both `NT_SUCCESS` values, so a naive `if (NT_SUCCESS(status))` check is meaningless. With `JobHandle == NULL`, the kernel walks the EPROCESS->Job pointer and answers about *any* containing job; with a real handle, it checks the specific job's nested-hierarchy. The implementation is `PsIsProcessInJob` in ntoskrnl.

Common malware usage

The textbook anti-sandbox check. Cuckoo Sandbox's monitor places the analysis target inside a job object so it can enforce timeouts and clean up child processes; older Joe Sandbox versions did the same; several SOC honeypot frameworks (Drakvuf agent, ANY.RUN's bridge) leave job-membership artifacts. Malware calls `NtIsProcessInJob(NtCurrentProcess(), NULL)`, and if the result is `STATUS_PROCESS_IN_JOB`, behaves benignly (exit cleanly, print fake banner, or branch into a decoy code path). The catch: legitimate execution contexts are *also* job-contained — every Chrome / Edge / Brave renderer, every UWP app, every WSL2 distro, every Docker-on-Windows container, and every PowerShell-launched-from-Task-Scheduler process lives in a job. Hardcoding "in-job means sandbox" therefore produces high false-positive rates and is increasingly avoided by modern loaders in favor of multi-signal scoring.

Detection opportunities

On its own, NtIsProcessInJob is benign and extremely common — Chrome alone calls it thousands of times per session. Detection value comes from *context*: an unsigned, recently-dropped binary calling NtIsProcessInJob with NULL job within the first second of execution, immediately followed by `NtTerminateProcess(NtCurrentProcess(), 0)` or by a long `NtDelayExecution`, is a strong sandbox-evasion signature. EDRs hook the userland thunk in kernel32 (`IsProcessInJob`) but a direct syscall bypasses that. Sysmon does not have a dedicated event; the best telemetry is ETW Threat-Intelligence `NtQueryInformation*` calls combined with process-tree timing. The Cuckoo / Joe Sandbox detection problem is well-studied — modern sandboxes spawn the sample *outside* their monitor job (via DETACHED_PROCESS or by reparenting through WMI) precisely to defeat this check.

Direct syscall examples

asmx64 direct stub

; Direct syscall stub for NtIsProcessInJob (SSN 0x4F, all builds)
NtIsProcessInJob PROC
    mov  r10, rcx          ; syscall convention
    mov  eax, 4Fh          ; SSN
    syscall
    ret
NtIsProcessInJob ENDP

cCuckoo / Joe Sandbox detection

// Anti-sandbox: bail out if we look like we're inside a monitor job.
// Beware: Chrome renderers, UWP apps and WSL2 all also report in-job.
#include <windows.h>

#define STATUS_PROCESS_IN_JOB     ((NTSTATUS)0x00000123L)
#define STATUS_PROCESS_NOT_IN_JOB ((NTSTATUS)0x00000124L)

typedef NTSTATUS (NTAPI *pNtIsProcessInJob)(HANDLE, HANDLE);

BOOL LooksSandboxed(void) {
    pNtIsProcessInJob NtIsProcessInJob = (pNtIsProcessInJob)GetProcAddress(
        GetModuleHandleA("ntdll.dll"), "NtIsProcessInJob");
    if (!NtIsProcessInJob) return FALSE;
    NTSTATUS s = NtIsProcessInJob((HANDLE)-1, NULL);
    return s == STATUS_PROCESS_IN_JOB;
}

int main(void) {
    if (LooksSandboxed()) { return 0; }  // benign exit
    // ...real payload...
    return 0;
}

rustdecoy branch on sandbox-positive

// Cargo: windows-sys = "0.59" (Win32_Foundation, Win32_System_Threading)
use windows_sys::Win32::Foundation::HANDLE;
use windows_sys::Win32::System::Threading::GetCurrentProcess;

const STATUS_PROCESS_IN_JOB: i32 = 0x00000123;

extern "system" {
    fn NtIsProcessInJob(Process: HANDLE, Job: HANDLE) -> i32;
}

fn in_any_job() -> bool {
    unsafe { NtIsProcessInJob(GetCurrentProcess(), std::ptr::null_mut()) == STATUS_PROCESS_IN_JOB }
}

fn main() {
    if in_any_job() {
        // Decoy: print something boring and exit 0.
        println!("hello world");
        return;
    }
    // real_payload();
}

MITRE ATT&CK mappings

Last verified: 2026-05-20