> Windows Syscalls
ntoskrnl.exeT1134.004T1106T1055

NtCreateUserProcess

Erzeugt einen neuen User-Mode-Prozess und dessen initialen Thread aus einem Executable-Image.

Prototyp

NTSTATUS NtCreateUserProcess(
  PHANDLE              ProcessHandle,
  PHANDLE              ThreadHandle,
  ACCESS_MASK          ProcessDesiredAccess,
  ACCESS_MASK          ThreadDesiredAccess,
  POBJECT_ATTRIBUTES   ProcessObjectAttributes,
  POBJECT_ATTRIBUTES   ThreadObjectAttributes,
  ULONG                ProcessFlags,
  ULONG                ThreadFlags,
  PRTL_USER_PROCESS_PARAMETERS ProcessParameters,
  PPS_CREATE_INFO      CreateInfo,
  PPS_ATTRIBUTE_LIST   AttributeList
);

Argumente

NameTypeDirDescription
ProcessHandlePHANDLEoutErhält ein Handle auf das neue Prozessobjekt.
ThreadHandlePHANDLEoutErhält ein Handle auf den Haupt-Thread des neuen Prozesses.
ProcessDesiredAccessACCESS_MASKinGewünschte Zugriffsmaske für das zurückgegebene Prozess-Handle (z. B. PROCESS_ALL_ACCESS).
ThreadDesiredAccessACCESS_MASKinGewünschte Zugriffsmaske für das zurückgegebene Thread-Handle (z. B. THREAD_ALL_ACCESS).
ProcessObjectAttributesPOBJECT_ATTRIBUTESinOptionale OBJECT_ATTRIBUTES für das Prozessobjekt (Name, Security-Descriptor, Root-Verzeichnis).
ThreadObjectAttributesPOBJECT_ATTRIBUTESinOptionale OBJECT_ATTRIBUTES für das primäre Thread-Objekt.
ProcessFlagsULONGinPROCESS_CREATE_FLAGS_* (BREAKAWAY, INHERIT_HANDLES, NO_DEBUG_INHERIT, SUSPENDED, ...).
ThreadFlagsULONGinTHREAD_CREATE_FLAGS_* (CREATE_SUSPENDED, SKIP_THREAD_ATTACH, HIDE_FROM_DEBUGGER, ...).
ProcessParametersPRTL_USER_PROCESS_PARAMETERSinParameterblock von RtlCreateProcessParametersEx (Image-Pfad, Kommandozeile, Environment, Standard-Handles).
CreateInfoPPS_CREATE_INFOin/outPS_CREATE_INFO-Zustandsmaschine: Eingabe PsCreateInitialState, Ausgabe Endzustand plus geöffnete Image-Section-/Datei-Handles.
AttributeListPPS_ATTRIBUTE_LISTinArray von PS_ATTRIBUTE-Einträgen: ImageName, ParentProcess, MitigationOptions, JobList, Token, ChildProcessPolicy, ...

Syscall-IDs pro Windows-Version

Windows-VersionSyscall-IDBuild
Win10 15070xBAwin10-1507
Win10 16070xBDwin10-1607
Win10 17030xC0win10-1703
Win10 17090xC1win10-1709
Win10 18030xC2win10-1803
Win10 18090xC3win10-1809
Win10 19030xC4win10-1903
Win10 19090xC4win10-1909
Win10 20040xC8win10-2004
Win10 20H20xC8win10-20h2
Win10 21H10xC8win10-21h1
Win10 21H20xC9win10-21h2
Win10 22H20xC9win10-22h2
Win11 21H20xCEwin11-21h2
Win11 22H20xCFwin11-22h2
Win11 23H20xCFwin11-23h2
Win11 24H20xD1win11-24h2
Server 20160xBDwinserver-2016
Server 20190xC3winserver-2019
Server 20220xCDwinserver-2022
Server 20250xD1winserver-2025

Kernel-Modul

ntoskrnl.exeNtCreateUserProcess

Verwandte APIs

CreateProcessWCreateProcessAsUserWCreateProcessWithTokenWCreateProcessWithLogonWNtCreateProcessNtCreateProcessExRtlCreateProcessParametersEx

Syscall-Stub

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

Undokumentierte Hinweise

NtCreateUserProcess ist seit Vista der moderne Kernel-Entrypoint unter der gesamten Win32-CreateProcess*-Familie. Es ersetzt die Legacy-Choreographie NtCreateProcess / NtCreateProcessEx + NtCreateThread + LdrLoadDll durch eine einzelne Kerneltransaktion, die das Image öffnet, die Section baut, das PEB primiert, Mitigations anwendet und den Initial-Thread startet. Die SSN driftet fast bei jedem Build (0xBA → 0xD1 im unterstützten Fenster), weil benachbarte Syscalls eingefügt oder entfernt werden; dynamische Auflösung ist Pflicht. Der 11-Parameter-Prototyp wird von zwei großen Strukturen dominiert: PS_CREATE_INFO (Zustandsmaschine, die der Kernel beim Image-Parsing durchläuft) und PS_ATTRIBUTE_LIST (Träger für alles, was die Legacy-`CreateProcess`-Parameter lpStartupInfo / lpProcessAttributes / Token / Job einzeln transportiert haben).

Häufige Malware-Nutzung

Zwei prominente Missbräuche. **(1) PPID-Spoofing (T1134.004)**: PS_ATTRIBUTE_PARENT_PROCESS in der AttributeList auf ein dupliziertes Handle eines beliebigen mit OpenProcess(PROCESS_CREATE_PROCESS) erreichbaren Prozesses setzen. Das Kind erscheint in Process Explorer, Sysmon Event ID 1 und EDR-Prozessbäumen unter diesem Parent — Klassiker, um einen Beacon unter explorer.exe oder services.exe zu verstecken. **(2) Mitigation-Downgrade / Child-Process-Policy-Missbrauch**: PS_ATTRIBUTE_MITIGATION_OPTIONS erlaubt es, Mitigations am Kind zu *aktivieren* (Block-Non-Microsoft-DLLs, um EDR-Injection in einen Helfer-Prozess zu verhindern, ist ein dokumentierter Red-Team-Trick) oder kombiniert mit PS_ATTRIBUTE_CHILD_PROCESS_POLICY weitere Kinder zu verbieten und Analyse zu erschweren. Subtiler dritter Effekt: NtCreateUserProcess direkt aufzurufen umgeht kernel32!CreateProcessInternalW, wo viele EDRs ihre User-Mode-Telemetrie-Hook platzieren.

Erkennungs­möglichkeiten

Kernel-Telemetrie ist hier exzellent. PsSetCreateProcessNotifyRoutineEx2 feuert bei jedem erfolgreichen Return mit einem PS_CREATE_NOTIFY_INFO, das die *echte* Parent-PID enthält (`CreatingThreadId.UniqueProcess`), unabhängig von jedem PS_ATTRIBUTE_PARENT_PROCESS-Spoof. Sysmon Event ID 1 zeichnet sowohl `ParentProcessGuid` (aus PEB-ProcessParameters) als auch den kernelseitig ermittelten Erzeuger auf — abweichende Werte sind ein hochauflösendes Spoof-Signal. Die ETW-Events `Microsoft-Windows-Kernel-Process/ProcessStart` exponieren dieselben Felder. EDRs, die nur CreateProcessInternalW oder NtCreateProcessEx hooken, verpassen Direct-Syscall-Aufrufer — beide Flächen prüfen.

Direkte Syscall-Beispiele

asmx64 direct stub (Win11 24H2)

; Direct syscall stub for NtCreateUserProcess (SSN 0xD1 on 24H2/2025)
; SSN moves nearly every release — resolve dynamically.
NtCreateUserProcess PROC
    mov  r10, rcx          ; syscall convention
    mov  eax, 0D1h         ; SSN
    syscall
    ret
NtCreateUserProcess ENDP

cPPID-spoof skeleton

// Minimal PPID-spoof skeleton: launch notepad.exe as a child of explorer.exe.
// Error handling and full PS_ATTRIBUTE / RTL_USER_PROCESS_PARAMETERS setup omitted for brevity.
#include <windows.h>
#include <winternl.h>

#define PROC_THREAD_ATTRIBUTE_PARENT_PROCESS 0x00020000

void SpoofParent(DWORD parent_pid) {
    SIZE_T attr_size = 0;
    InitializeProcThreadAttributeList(NULL, 1, 0, &attr_size);
    LPPROC_THREAD_ATTRIBUTE_LIST attr =
        (LPPROC_THREAD_ATTRIBUTE_LIST)HeapAlloc(GetProcessHeap(), 0, attr_size);
    InitializeProcThreadAttributeList(attr, 1, 0, &attr_size);

    HANDLE parent = OpenProcess(PROCESS_CREATE_PROCESS, FALSE, parent_pid);
    UpdateProcThreadAttribute(attr, 0, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS,
                              &parent, sizeof(HANDLE), NULL, NULL);

    STARTUPINFOEXW si = { 0 };
    si.StartupInfo.cb = sizeof si;
    si.lpAttributeList = attr;
    PROCESS_INFORMATION pi;

    // CreateProcess wraps NtCreateUserProcess; the AttributeList carries
    // PS_ATTRIBUTE_PARENT_PROCESS through to the kernel.
    CreateProcessW(L"C:\\Windows\\System32\\notepad.exe", NULL, NULL, NULL,
                   FALSE, EXTENDED_STARTUPINFO_PRESENT,
                   NULL, NULL, (LPSTARTUPINFOW)&si, &pi);

    DeleteProcThreadAttributeList(attr);
    CloseHandle(parent);
}

rustblock-non-Microsoft-DLLs mitigation

// Cargo: windows-sys = "0.59"
// Launch a helper process with the Microsoft-signed-DLLs-only mitigation —
// blocks EDR userland DLLs from being injected into the child.
use windows_sys::Win32::System::Threading::*;
use windows_sys::core::PCWSTR;

const PROC_THREAD_ATTRIBUTE_MITIGATION_POLICY: usize = 0x00020007;
const PROCESS_CREATION_MITIGATION_POLICY2_LOADER_INTEGRITY_CONTINUITY_ALWAYS_ON: u64
    = 0x0000_0001_0000_0000;

pub unsafe fn launch_locked_down(image: PCWSTR) {
    let mut attr_size = 0usize;
    InitializeProcThreadAttributeList(core::ptr::null_mut(), 1, 0, &mut attr_size);
    let attr = std::alloc::alloc(
        std::alloc::Layout::from_size_align(attr_size, 8).unwrap()) as *mut _;
    InitializeProcThreadAttributeList(attr, 1, 0, &mut attr_size);

    let mut policy: u64 =
        PROCESS_CREATION_MITIGATION_POLICY2_LOADER_INTEGRITY_CONTINUITY_ALWAYS_ON;
    UpdateProcThreadAttribute(attr, 0,
        PROC_THREAD_ATTRIBUTE_MITIGATION_POLICY,
        &mut policy as *mut _ as _, 8,
        core::ptr::null_mut(), core::ptr::null_mut());

    let mut si: STARTUPINFOEXW = core::mem::zeroed();
    si.StartupInfo.cb = core::mem::size_of_val(&si) as u32;
    si.lpAttributeList = attr;
    let mut pi: PROCESS_INFORMATION = core::mem::zeroed();

    CreateProcessW(image, core::ptr::null_mut(), core::ptr::null(),
                   core::ptr::null(), 0, EXTENDED_STARTUPINFO_PRESENT,
                   core::ptr::null(), core::ptr::null(),
                   &si as *const _ as _, &mut pi);
}

MITRE ATT&CK-Mappings

Last verified: 2026-05-20