PS_CREATE_INFO

The PS_CREATE_INFO structure is exchanged between user and kernel modes for the NtCreateUserProcess and ZwCreateUserProcess functions, which were new for Windows Vista.

Documentation Status

The PS_CREATE_INFO structure is not documented. Even for an undocumented structure that is exposed through undocumented interfaces, PS_CREATE_INFO must count as obscure. Though the structure 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.

Type Information

Where this type information turns up instead is in symbol files for a handful of higher-level user-mode modules that ought never to see the structure. That these modules are built with knowledge of the PS_CREATE_INFO is revealed because for some of them in some versions (starting with Windows 8) the symbol files that Microsoft has included in downloadable packages of public symbols are in fact private symbols. Why these modules are built with knowledge of the PS_CREATE_INFO or of anything else that’s defined in the same unpublished header (ntpsapi.h) is not revealed. Especially prominent among them is URLMON.DLL for being a key component of Internet Explorer and thus of having some bearing on the success of an anti-trust suit among whose allegations was that Microsoft abused its Windows monpoly to help establish Internet Explorer anti-competitively. Official reviewers of Microsoft’s settlement compliance apparently either did not notice or did not care that Internet Explorer is built with more detailed knowledge of Windows internals than Microsoft publishes even for kernel-mode programmers.

Type information for the PS_CREATE_INFO also turns up in a statically linked library, named CLFSMGMT.LIB, which Microsoft publishes with the Software Development Kit (SDK). The 32-bit builds have the type information starting with Windows Vista, the 64-bit not until Windows 8. For both, the disclosure stops after the 1903 release of Windows 10.

C-Language Reference

The only other disclosure yet known is in the Windows Driver KIt (WDK) for the original and 1511 releases of Windows 10. These have a header named ZWAPI.H which presents a prototype for ZwCreateUserProcess. From inspection of binaries, everyone who cares can have known all along that the function’s second argument is a pointer to an undocumented structure. The disclosed prototype declares this argument’s type as a PPS_CREATE_INFO. In Microsoft’s long established convention for naming pointer types, this type is consistent with PS_CREATE_INFO being Micorosft’s name for the structure that the argument points to. No other header in the same WDK even references either type, not even to define the structure as opaque. That ZWAPI.H as supplied with the WDK does not compile without prior inclusion of otherwise unpublished headers is a strong suggestion that its own publication was an oversight.

Layout

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

Offset (x86) Offset (x64) Definition
0x00 0x00
ULONG_PTR Size;
0x04 0x08
PS_CREATE_STATE State;
0x08 0x10
union {
    /*  changing members, see below  */
};

While the PS_CREATE_STATE enumeration is not known to be used elsewhere, it is as well given here. The defined values are:

The immediate point to the State member is to indicate whether the structure is input to or output from the NtCreateUserProcess function (or its Zw alias). As input, it defines an initial state for the created process. Output tells of the creation’s success or failure. In some cases, the State is itself enough output. In most, both for input and output, there is more data to follow in the anonymous union, and the State then selects from this union’s members:

Definition Versions
struct {
    /* see below */
} InitState;
6.0 and higher
 struct {
    HANDLE FileHandle;
} FailSection;
6.0 and higher
 struct {
    USHORT DllCharacteristics;
} ExeFormat;
6.2 and higher
 struct {
    HANDLE IFEOKey;
} ExeName;
6.0 and higher
 struct {
    /* see below */
} SuccessState;
6.0 and higher

Input

The PsCreateInitialState value is required in State for input, i.e., when passing a PS_CREATE_INFO to NtCreateUserProcess. It selects the InitState branch.

Init State

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

Output

Six values of State in the PS_CREATE_INFO on output tell something of why NtCreateUserProcess failed. One tells of success.

For failure, the State may still be PsCreateInitialState. This means the process creation didn’t get past parameter validation—notably not even to fail at opening the file. For three of the failure states, the corresponding branch of the anonymous union has information that may help the user-mode caller not just report the problem but even to try recovering from it.

Fail Section

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 about its configuration 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:

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

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.

MORE TO WRITE ABOUT THIS!

Success State

The greatest output in the anonymous union is produced when State is PsCreateSuccess to indicate that the process has indeed been created. The caller is given information that it likely will want for completing the user-mode configuration of the process and would otherwise have to obtain through multiple queries:

Offset (x86) Offset (x64) Definition
0x08 0x10
union {
    ULONG OutputFlags;
    struct {
        /* changing bit fields, follow link */
    };
};
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;