> Windows Syscalls
ntoskrnl.exeT1055.012T1134.004T1106

NtCreateProcessEx

Erzeugt einen neuen Prozess aus einem Section-Handle ohne ntdll-Prozessinitialisierung — Baustein des Process Hollowing.

Prototyp

NTSTATUS NtCreateProcessEx(
  PHANDLE            ProcessHandle,
  ACCESS_MASK        DesiredAccess,
  POBJECT_ATTRIBUTES ObjectAttributes,
  HANDLE             ParentProcess,
  ULONG              Flags,
  HANDLE             SectionHandle,
  HANDLE             DebugPort,
  HANDLE             ExceptionPort,
  ULONG              JobMemberLevel
);

Argumente

NameTypeDirDescription
ProcessHandlePHANDLEoutErhält das Handle des neuen Prozesses bei Erfolg.
DesiredAccessACCESS_MASKinZugriffsrechte für das zurückgegebene Prozess-Handle, typischerweise PROCESS_ALL_ACCESS.
ObjectAttributesPOBJECT_ATTRIBUTESinOptionale Objektattribute (Name, Stammverzeichnis). Üblicherweise NULL.
ParentProcessHANDLEinHandle auf den Elternprozess (NtCurrentProcess() für sich selbst). Ermöglicht Parent-PID-Spoofing, wenn auf einen anderen Prozess gesetzt.
FlagsULONGinErzeugungs-Flags wie PROCESS_CREATE_FLAGS_INHERIT_HANDLES, PROCESS_CREATE_FLAGS_BREAKAWAY, PROCESS_CREATE_FLAGS_SUSPENDED.
SectionHandleHANDLEinHandle auf eine SEC_IMAGE-Section, die das Image des neuen Prozesses bereitstellt. NULL erbt das Image des Elternprozesses (genutzt in PPID-Spoof + Hollow-Kombinationen).
DebugPortHANDLEinOptionaler Debug-Port-Handle. Fast immer NULL.
ExceptionPortHANDLEinOptionaler Exception-Port-Handle (älterer LPC-Mechanismus). Fast immer NULL.
JobMemberLevelULONGinJob-Object-Verschachtelungstiefe, wenn der Elternprozess Teil einer Job-Hierarchie ist; 0, falls nicht relevant.

Syscall-IDs pro Windows-Version

Windows-VersionSyscall-IDBuild
Win10 15070x4Dwin10-1507
Win10 16070x4Dwin10-1607
Win10 17030x4Dwin10-1703
Win10 17090x4Dwin10-1709
Win10 18030x4Dwin10-1803
Win10 18090x4Dwin10-1809
Win10 19030x4Dwin10-1903
Win10 19090x4Dwin10-1909
Win10 20040x4Dwin10-2004
Win10 20H20x4Dwin10-20h2
Win10 21H10x4Dwin10-21h1
Win10 21H20x4Dwin10-21h2
Win10 22H20x4Dwin10-22h2
Win11 21H20x4Dwin11-21h2
Win11 22H20x4Dwin11-22h2
Win11 23H20x4Dwin11-23h2
Win11 24H20x4Dwin11-24h2
Server 20160x4Dwinserver-2016
Server 20190x4Dwinserver-2019
Server 20220x4Dwinserver-2022
Server 20250x4Dwinserver-2025

Kernel-Modul

ntoskrnl.exeNtCreateProcessEx

Verwandte APIs

CreateProcessWCreateProcessAsUserWNtCreateUserProcessNtCreateSectionNtCreateThreadExRtlCreateProcessParametersEx

Syscall-Stub

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

NtCreateProcessEx ist der hardwarenahe Einstiegspunkt zur Prozesserzeugung. Anders als NtCreateUserProcess (das CreateProcessW heute verwendet) verlangt NtCreateProcessEx, dass der Aufrufer zuvor eine SEC_IMAGE-Section aus dem Ziel-Executable via NtCreateSection(SEC_IMAGE) erzeugt und sie anhängt. Entscheidend: der resultierende Prozess hat keinen initialen Thread — der Aufrufer muss anschließend NtCreateThreadEx (oder NtCreateThread) aufrufen. Diese Trennung macht NtCreateProcessEx zum kanonischen Baustein des *Process Hollowing* und der *Early Bird APC*-Familie: einen Prozess erzeugen und Arbeit in ihn einreihen, bevor die erste Instruktion läuft. Die SSN `0x4D` ist über alle unterstützten Builds stabil.

Häufige Malware-Nutzung

Genutzt von Process-Hollowing-Ketten, die die CreateProcessW-Telemetrie umgehen wollen, von PPID-Spoofing-Tools (ParentProcess auf explorer.exe oder eine andere vertrauenswürdige PID setzen) und von Early-Bird-Varianten, die NtCreateProcessEx + NtCreateThreadEx(suspendiert) + NtQueueApcThreadEx kombinieren. Cobalt Strikes spawnto/spoof-parent-Features landen letztlich auf diesem Codepfad. Als alleinige Offensiv-Primitive heute seltener, weil NtCreateUserProcess reichhaltigere Attributkontrolle in einem einzigen Syscall bietet.

Erkennungs­möglichkeiten

ETW Microsoft-Windows-Kernel-Process emittiert ProcessStart-Events aus PspInsertProcess unabhängig vom Userland-Einstiegspunkt; der Kernel unterscheidet bei diesem Callback nicht zwischen NtCreateProcessEx und NtCreateUserProcess. Sysmon Event ID 1 feuert in beiden Fällen und legt die echte Parent-PID offen, auch wenn CreateProcessW gelogen hätte. Reine Userland-Hooks auf kernelbase!CreateProcessW verfehlen Direct-Syscall-Aufrufer; Hooks gehören auf ntdll!NtCreateUserProcess *und* ntdll!NtCreateProcessEx. Verdächtiger Indikator: eine SEC_IMAGE-Section über einer unsignierten PE, gefolgt innerhalb von Millisekunden von NtCreateProcessEx und NtCreateThreadEx im suspendierten Zustand.

Direkte Syscall-Beispiele

asmx64 direct stub

; Direct syscall stub for NtCreateProcessEx (SSN 0x4D, stable on Win10 1507+ through Win11 24H2)
NtCreateProcessEx PROC
    mov  r10, rcx          ; syscall convention
    mov  eax, 4Dh          ; SSN
    syscall
    ret
NtCreateProcessEx ENDP

cProcess-hollow style: SEC_IMAGE + NtCreateProcessEx

// Open the target PE and wrap it in a SEC_IMAGE section, then spawn a process backed by it.
HANDLE hFile = NULL;
IO_STATUS_BLOCK iosb = { 0 };
OBJECT_ATTRIBUTES oa = { 0 };
UNICODE_STRING path;
RtlInitUnicodeString(&path, L"\\??\\C:\\Windows\\System32\\notepad.exe");
InitializeObjectAttributes(&oa, &path, OBJ_CASE_INSENSITIVE, NULL, NULL);
NtOpenFile(&hFile, FILE_EXECUTE | SYNCHRONIZE, &oa, &iosb,
           FILE_SHARE_READ, FILE_SYNCHRONOUS_IO_NONALERT);

HANDLE hSection = NULL;
NtCreateSection(&hSection, SECTION_ALL_ACCESS, NULL, NULL,
                PAGE_READONLY, SEC_IMAGE, hFile);

HANDLE hProcess = NULL;
NtCreateProcessEx(&hProcess,
                  PROCESS_ALL_ACCESS,
                  NULL,
                  NtCurrentProcess(),     // ParentProcess — set elsewhere for PPID spoof
                  0,                       // Flags
                  hSection,                // SectionHandle
                  NULL,                    // DebugPort
                  NULL,                    // ExceptionPort
                  0);                      // JobMemberLevel
// New process has NO threads yet — caller must NtCreateThreadEx into it.

rustwindows-sys + naked syscall stub

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

#[unsafe(naked)]
unsafe extern "system" fn nt_create_process_ex_stub() {
    asm!(
        "mov r10, rcx",
        "mov eax, 0x4D",
        "syscall",
        "ret",
        options(noreturn),
    );
}

MITRE ATT&CK-Mappings

Last verified: 2026-05-20