PS_CREATE_INFO

The PS_CREATE_INFO structure is exchanged between user and kernel modes for the NtCreateUserProcess function, which was new for Windows Vista.

Documentation Status

The PS_CREATE_INFO structure is not documented. Microsoft is known to have disclosed its existence only in two ways: type information in public symbol files for Windows 8 and higher; an unreferenced type in a C-language header that appears to have been published by mistake in a Windows Driver Kit (WDK) for Windows 10.

Curiously, though the PS_CREATE_INFO is prepared by KERNEL32.DLL or KERNELBASE.DLL, depending on the Windows version, and is passed through NTDLL.DLL to kernel mode, and is then interpreted by the kernel, public symbol files for none of these modules have type information for the PS_CREATE_INFO in any known Windows version. Where this type information turns up instead is in public symbol files for a handful of higher-level user-mode modules that ought never to see the structure. Especially prominent as examples are OLE32.DLL and URLMON.DLL. The latter is conspicuous as a key component of Internet Explorer. Government-appointed reviewers of Microsoft’s settlement compliance seem to have missed the irony that Internet Explorer is built with more detailed knowledge of Windows internals than Microsoft publishes even for kernel-mode programmers.

A pointer to a PS_CREATE_INFO is passed to the NtCreateUserProcess function as its second-last argument. Microsoft published a C-language prototype of this function, as its alias ZwCreateUserProcess, in a ZWAPI.H with the Enterprise edition of the Windows 10 WDK for the 1511 release. No other header in the same WDK even declares the pointer’s type.

Layout

The PS_CREATE_INFO structure is 0x48 or 0x58 bytes in 32-bit and 64-bit Windows, respectively, in version 6.0 and higher.

Offset (x86) Offset (x64) Definition
0x00 0x00
ULONG_PTR Size;
0x04 0x08
PS_CREATE_STATE State;
0x08 0x10
union {
    struct {
        /* see below */
    } InitState;
    struct {
        HANDLE FileHandle;
    } FailSection;
    struct {
        USHORT DllCharacteristics;
    } ExeFormat;
    struct {
        HANDLE IFEOKey;
    } ExeName;
    struct {
        /* see below */
    } SuccessState;
};

The point to the State member is to indicate which branch to select from the unnamed union that follows. While the PS_CREATE_STATE enumeration is not known to be used elsewhere, it is as well given here. The defined values are:

Input

The PsCreateInitialState is required for input and selects the InitState branch.

Init State

Offset (x86) Offset (x64) Definition
0x08 0x10
union {
    ULONG InitFlags;
    struct {
        /* changing bit fields, see below */
    };
};
0x0C 0x14
ACCESS_MASK AdditionalFileAccess;

The bit fields in union with the 32-bit InitFlags have a mixture of types. The modern identification of the second byte as being wholly spare but separate from spare bits in the first byte looks like a legacy from a reworking for Windows 8:

Offset Mask Definition Versions
0x08 0x01
UCHAR WriteOutputOnExit : 1;
6.0 and higher
0x02
UCHAR DetectManifest : 1;
6.0 and higher
0x04
UCHAR IFEOSkipDebugger : 1;
6.2 and higher
0x08
UCHAR IFEODoNotPropagateKeyState : 1;
6.2 and higher
 
UCHAR SpareBits1 : 6;
6.0 to 6.1
 
UCHAR SpareBits1 : 4;
6.2 and higher
0x09 0x03 unknown two bits 6.0 to 6.1
 
UCHAR SpareBits2 : 6;
6.0 to 6.1
 
UCHAR SpareBits2 : 8;
6.2 and higher
0x0A 0xFFFF
USHORT ProhibitedImageCharacteristics : 16;
6.2 and higher

Microsoft’s name for the second byte’s 2-bit field in the original layout is not known. The value 3 is explicitly invalid. The cases 0, 1 and 2 were later separated into combinations of single bits of the first byte:

Unknown IFEOSkipDebugger IFEODoNotPropagateKeyState
0 clear clear
1 set clear
2 set set

As late as the original Windows 10, these remain the only combinations that have known use. KERNELBASE sets both bits when the created process is to start as a debugged process, i.e., because DEBUG_PROCESS or DEBUG_ONLY_THIS_PROCESS is set among the process creation flags.

Output

Three cases of failure involve the return of information that may help the user-mode caller present the problem or recover from it.

FailSection

Offset (x86) Offset (x64) Definition
0x08 0x10
HANDLE FileHandle;

Exe Format

Offset (x86) Offset (x64) Definition
0x08 0x10
USHORT DllCharacteristics;

Exe Name

Failure as PsCreateFailExeName indicates that however usable may be the executable as a file its execution is prevented by something about its name, specifically as its name appears as a subkey of Image File Execution Options. The caller is not explicitly told what prevents execution but is returned a handle to the subkey.

There may be multiple causes as a point of design but only one is implemented. The executable’s Image File Execution Options subkey has a Debugger value. The kernel in effect interprets this value’s presence as meaning that a process with this name cannot ordinarily be created. (The kernel’s error code is STATUS_OBJECT_PATH_INVALID.) The one exception to “ordinarily” is if the IFEOSkipDebugger bit is set on input.

Offset (x86) Offset (x64) Definition
0x08 0x10
HANDLE IFEOKey;

Success State

The greatest output is produced on success.

Offset (x86) Offset (x64) Definition
0x08 0x10
union {
    ULONG OutputFlags;
    struct {
        /* changing bit fields, see below */
    };
};
0x0C 0x18
HANDLE FileHandle;
0x10 0x20
HANDLE SectionHandle;
0x18 0x28
ULONGLONG UserProcessParametersNative;
0x20 0x30
ULONG UserProcessParametersWow64;
0x24 0x34
ULONG CurrentParameterFlags;
0x28 0x38
ULONGLONG PebAddressNative;
0x30 0x40
ULONG PebAddressWow64;
0x38 0x48
ULONGLONG ManifestAddress;
0x40 0x50
ULONG ManifestSize;

The bit fields in union with the 32-bit OutputFlags have the same mixture of types as for the InitFlags but no use of the second byte or the high word is known in any version.

Offset Mask Definition Versions
0x08 0x01
UCHAR ProtectedProcess : 1;
6.0 and higher
0x02
UCHAR AddressSpaceOverride : 1;
6.0 and higher
0x04
UCHAR DevOverrideEnabled : 1;
6.0 and higher
0x08
UCHAR ManifestDetected : 1;
6.0 and higher
0x10
UCHAR ProtectedProcessLight : 1;
6.3 and higher
 
UCHAR SpareBits1 : 4;
6.0 to 6.2
 
UCHAR SpareBits1 : 3;
6.3 and higher
0x09  
UCHAR SpareBits2 : 8;
6.0 and higher
0x0A  
USHORT SpareBits3 : 16;
6.0 and higher