KPROCESS

The KPROCESS structure (formally _KPROCESS) is the Kernel’s portion of the Executive’s EPROCESS structure. The latter is the process object as exposed through the Object Manager. The KPROCESS is the start of it.

Availability

The process is a fundamental object in Windows. The KPROCESS exists in all versions, i.e., 3.10 and higher.

Documentation Status

For being fundamental, the KPROCESS has never been secret as something that exists. It is, however, deeply internal. It is not formally documented. Even among C-language headers in the Device Driver Kit (DDK) or Windows Driver Kit (WDK), the KPROCESS is only ever declared as an opaque type: its contents are never defined.

Though Microsoft is not known ever to have published a C-language definition of the KPROCESS, the practical equivalent is disclosed as type information in public symbol files for the kernel starting with Windows 2000 SP3. One earlier disclosure of type information is known from a statically linked library, named craShlib.Lib (sic), which Microsoft distributed with the Win32 SDK in 1996. Though it is supplied to help with building the user-mode Dr. Watson sample, it has type information that matches the kernel-mode KPROCESS for version 4.0.

Access

Presumably because the KPROCESS is only as much of the process’s representation as needed by the core of the kernel, it has very little exposure independently of its nesting in the EPROCESS as the latter’s Pcb member. Where code outside the kernel refers to a process by address, what will almost always be wanted is the larger EPROCESS. Notable exceptions are the KTHREAD and KAPC_STATE: being other creatures of the kernel’s core, these each have a member named Process that points to a KPROCESS.

Layout

The KPROCESS structure is plainly internal to the kernel and its layout changes greatly between Windows versions and even between builds. Throughout this article, early and late builds within a version have the following cut-offs:

Though the KPROCESS is highly variable, it has grown mostly by appending. This article attempts to lay out the structure’s members as one sequence for all versions. The following changes of size are known:

Version Size (x86) Size (x64)
3.10 0x70  
3.50 to 4.0 0x68  
5.0 to early 5.2 0x6C  
late 5.2 0x78 0xB8
6.0 0x80 0xC0
6.1 0x98 0x0160
6.2 to 6.3 0xA0 0x02C8
10.0 to 1607 0xA8 0x02D8
1703 to 1809 0xB0 0x02D8
1903 0xB0 0x02E0
2004 0xE0 0x0438

These sizes, and the offsets, types and names in the tables that follow, are from Microsoft’s public symbol files for the kernel starting with Windows 2000 SP3. Since symbol files for earlier versions do not contain type information for the KPROCESS, what’s known for earlier versions is instead inferred from what use the kernel is seen to make of the KPROCESS. Sizes are relatively straightforward, even without symbol files, but Microsoft’s names and types are something of a guess. Where use of a member corresponds closely with that of a version for which Microsoft’s symbols are available, it seems reasonable to suppose continuity. Some use, however, has no correspondence, the code having changed too much. Even where the use hasn’t changed, tracking it down exhaustively would be difficult, if not impossible, even with source code.

Layout

For the detailed layout in the tables that follow, it helps with some processor-dependent definitions if a macro, say MAX_PROC_GROUPS, is presumed for the maximum number of processor groups:

Note that the intention here is not to say that these limits on processor groups are permanent, let alone that they should be depended on when programming, just that they’re what are built in to various members of the KPROCESS in the presently observed Windows versions.

Original

It is well known even to user-mode programmers that a process can be waited on until it gets signalled, as happens when the process ends its execution. In version 3.50 and higher, this is effected by having the KPROCESS start with a DISPATCHER_HEADER so that it can be waited on by passing its address to such functions as KeWaitForSingleObject. In this header, the Type is ProcessObject (3) from the KOBJECTS enumeration.

It was not always so, however. In all versions, the EPROCESS can be waited on by passing a handle to NtWaitForSingleObject, but what’s actually waited on in version 3.10 is a KEVENT at offset 0x70 in the EPROCESS. The KPROCESS originally has no role in this. It does not begin with a DISPATCHER_HEADER, but like the other kernel objects that do not have this header, it does begin with a Type and Size. In version 3.10, this Type was surely named ProcessObject, as for later versions, but its numerical value is 0x0E.

Offset (x86) Offset (x64) Definition Versions Remarks
0x00 (3.10)  
USHORT Type;
3.10 only next in Header at 0x00
0x02 (3.10)  
USHORT Size;
3.10 only next in Header at 0x00
0x04 (3.10)  
ULONG StackCount;
3.10 only next as USHORT at 0x60
0x00 0x00
DISPATCHER_HEADER Header;
3.50 and higher  
0x08 (3.10);
0x10
0x18
LIST_ENTRY ProfileListHead;
all  

Whether the header is the full DISPATCHER_HEADER or just something a little like one, it has somehow always been followed by the list head for process-specific KPROFILE objects. Pretty much everything else that’s original to the KPROCESS was rearranged even as soon as versions 3.50 and 3.51.

Offset (x86) Offset (x64) Definition Versions Remarks
0x10 (3.10);
0x18 (3.50)
 
LIST_ENTRY ReadyListHead;
3.10 to 3.50 next at 0x40
0x18 (3.10);
0x20 (3.50)
 
LIST_ENTRY SwapListEntry;
3.10 to 3.50 next at 0x48
0x20 (3.10);
0x28 (3.50)
 
LIST_ENTRY ThreadListHead;
3.10 to 3.50 next at 0x50
0x28 (3.10);
0x30 (3.50)
 
LARGE_INTEGER KernelTime;
3.10 only  
ULONG KernelTime;
3.50 only next at 0x38
0x30 (3.10);
0x34 (3.50)
 
LARGE_INTEGER UserTime;
3.10 only  
ULONG UserTime;
3.50 only next at 0x3C
0x38 (3.10 to 3.50);
0x18
0x28
ULONG_PTR DirectoryTableBase [2];
3.10 to 5.2  
ULONG_PTR DirectoryTableBase;
6.0 and higher  
0x1C (6.0) 0x30 (6.0)
ULONG_PTR Unused0;
6.0 only  
0x40 (3.10)   unknown KSPIN_LOCK 3.10 only  
0x44 (3.10)  
ULONG Iopl;
3.10 only next as UCHAR at 0x5E
0x48 (3.10);
0x3C (3.50)
  unaccounted eight bytes 3.10 to 3.50  
0x50 (3.10)  
LONG ThreadQuantum;
3.10 only next as CHAR at 0x65
0x54 (3.10);
0x44 (3.50)
 
KAFFINITY ActiveProcessors;
3.10 to 3.50 next at 0x34
0x58 (3.10);
0x48 (3.50)
 
KAFFINITY Affinity;
3.10 to 3.50 next at 0x5C
0x5C (3.10);
0x4C (3.50);
0x20 (3.51 to 6.0);
0x1C
 
KGDTENTRY LdtDescriptor;
all  
0x54 (3.50);
0x28 (3.51 to 6.0);
0x24
 
KIDTENTRY Int21Descriptor;
3.50 and higher  
0x64 (3.10);
0x5C (3.50);
0x30 (3.51 to 6.0)
0x38 (late 5.2 to 6.0)
USHORT IopmOffset;
3.10 to 6.0 next at 0x6E (x86)
0x5E (3.50);
0x32 (3.51 to 6.0)
 
UCHAR Iopl;
3.50 to early 6.0 previously ULONG at 0x44
UCHAR Unused1;
late 6.0 only  
0x66 (3.10);
0x5F (3.50);
0x33 (3.51 to 6.0)
 
UCHAR VdmFlag;
3.10 to 5.0  
UCHAR Unused;
5.1 to early 6.0  
UCHAR Unused2;
late 6.0 only  
0x34 (3.51 to 6.0) 0x40 (late 5.2 to 6.0)
KAFFINITY ActiveProcessors;
3.51 to 5.1 previously 0x44
KAFFINITY volatile ActiveProcessors;
5.2 to 6.0 next as KAFFINITY_EX volatile at 0x50 and 0x88
0x38 (3.51 to 6.0) 0x48 (5.0 to 6.0)
ULONG KernelTime;
3.51 to 6.0 previously 0x30;
next at 0x88 and 0xF8
0x3C (3.51 to 6.0) 0x4C (5.0 to 6.0)
ULONG UserTime;
3.51 to 6.0 previously 0x34;
next at 0x8C and 0xFC
0x2C 0x30
LIST_ENTRY ThreadListHead;
6.1 and higher previously 0x50 and 0x70
0x34 0x40
ULONG_PTR ProcessLock;
6.1 only previously 0x58 and 0x80
ULONG ProcessLock;
6.2 and higher  
  0x44
ULONG Spare0;
6.2 to 1607  
ULONG ProcessTimerDelay;
1703 and higher at 0xAC for x86
0x38 0x48
ULONGLONG DeepFreezeStartTime;
10.0 and higher  
0x38 (6.1 to 6.3);
0x40
0x48 (6.1 to 6.3);
0x50
KAFFINITY_EX Affinity;
6.1 and higher previously KAFFINITY at 0x5C and 0x88
  0xF8
ULONGLONG AffinityPadding [0x0C];
2004 and higher  
0x40 (3.51 to 6.0);
0x44 (6.1 to 6.3);
0x4C
0x50 (late 5.2 to 6.0);
0x70 (6.1);
0xF0 (6.2 to 6.3);
0xF8 (10.0 to 1903);
0x0158
LIST_ENTRY ReadyListHead;
3.51 and higher previously 0x18
0x48 (3.51 to 6.0);
0x4C (6.1 to 6.3);
0x54
 
LIST_ENTRY SwapListEntry;
3.51 to 5.0 previously 0x20
0x60 (late 5.2 to 6.0);
0x80 (6.1);
0x0100 (6.2 to 6.3);
0x0108 (10.0 to 1903);
0x0168
SINGLE_LIST_ENTRY SwapListEntry;
5.1 and higher  
0x50 (6.1 to 6.3);
0x58
0x88 (6.1);
0x0108 (6.2 to 6.3);
0x0110 (10.0 to 1903);
0x0170
KAFFINITY_EX volatile ActiveProcessors;
6.1 and higher previously KAFFINITY volatile at 0x34 and 0x40
  0x0218
ULONGLONG ActiveProcessorsPadding [0x0C];
2004 and higher  
0x4C (5.1 to 6.0)  
PVOID VdmTrapcHandler;
5.1 to 6.0 next at 0x90
  0x68 (late 5.2 to 6.0)
PVOID Reserved1;
late 5.2 only  
PVOID InstrumentationCallback;
6.0 only next at 0x0100
0x50 (3.51 to 6.0) 0x70 (late 5.2 to 6.0)
LIST_ENTRY ThreadListHead;
3.51 to 6.0 previously 0x28;
next at 0x2C and 0x30
0x58 (3.51 to 6.0) 0x80 (late 5.2 to 6.0)
KSPIN_LOCK ProcessLock;
3.51 to 6.0 next at 0x34 and 0x40
0x5C (3.51 to 6.0) 0x88 (late 5.2 to 6.0)
KAFFINITY Affinity;
3.51 to 6.0 previously at 0x48;
next as KAFFINITY_EX at 0x40 and 0x50
0x60 (3.50 to early 5.2)  
USHORT StackCount;
3.50 to early 5.2 previously as ULONG at 0x04;
next as ULONG_PTR at 0x6C and 0xA0
0x60 (late 5.2 to 6.0);
0x5C (6.1 to 6.3);
0x64
0x90 (late 5.2 to 6.0);
0xB0 (6.1);
0x01B0 (6.2 to 6.3);
0x01B8 (10.0 to 1903);
0x0278
union {
    struct {
        /*  bit fields, follow link  */
    };
    LONG ProcessFlags;
};
late 5.2 only  
union {
    struct {
        /*  bit fields, follow link  */
    };
    LONG volatile ProcessFlags;
};
6.0 and higher  
0x67 (3.10);
0x62 (3.50)
 
BOOLEAN AutoAlignment;
3.10 to 3.50 next at 0x64
  0x01BC (1903);
0x027C
ULONG ActiveGroupsMask;
1903 and higher previously in ProcessFlags
0x68 (3.10);
0x63 (3.50);
0x62 (3.51 to early 5.2);
0x64 (late 5.2 to 6.0);
0x60 (6.1 to 6.3);
0x68
0x94 (late 5.2 to 6.0);
0xB4 (6.1);
0x01B4 (6.2 to 6.3);
0x01BC (10.0 to 1809);
0x01C0 (1903);
0x0280
CHAR BasePriority;
all  
0x69 (3.10);
0x64 (3.50)
 
UCHAR State;
3.10 to 3.50 next at 0x65;
last member in 3.10
0x65 (3.50);
0x63 (3.51 to early 5.2);
0x65 (late 5.2 to 6.0);
0x61 (6.1 to 6.3);
0x69
0x95 (late 5.2 to 6.0);
0xB5 (6.1);
0x01B5 (6.2 to 6.3);
0x01BD (10.0 to 1809);
0x01C1  (1903);
0x0281
CHAR ThreadQuantum;
3.50 to early 5.2 previously LONG at 0x50;
last member in 3.50
CHAR QuantumReset;
late 5.2 and higher  
0x64 (3.51 to early 5.2)  
BOOLEAN AutoAlignment;
3.51 to early 5.2 previously 0x62;
next in ProcessFlags
0x65 (3.51 to early 5.2);
0x66 (late 5.2 to 6.0)
0x96 (late 5.2 to 6.0)
UCHAR State;
3.51 to 6.0 previously 0x64;
next in StackCount;
last member in 3.51

Whatever may have motivated the reordering of byte-size members at the end in versions 3.10 to 3.51, all these versions end the structure with unused space because of alignment: six bytes in 3.10 because of the structure’s 8-byte alignment (from using LARGE_INTEGER for KernelTime and UserTime); two bytes in versions 3.50 and 3.51.

Appended for Windows NT 4.0

Version 4.0 adds just two bytes which anyway fit into the earlier versions’ alignment padding. Neither stays put.

Offset (x86) Offset (x64) Definition Versions Remarks
0x66 (4.0 to early 5.2);
0x67 (late 5.2 to 6.0)
0x97 (late 5.2 to 6.0)
UCHAR ThreadSeed;
4.0 to 6.0 next as ULONG array at 0x64 and 0xB8
0x67 (4.0 to early 5.2)  
BOOLEAN DisableBoost;
4.0 to early 5.2 next in ProcessFlags;
last member in 4.0

The ThreadSeed helps to spread the process’s threads over the available processors. It is initialised pseudo-randomly (from the low byte of KeTickCount) when the process is created. As each thread is initialised, the process’s ThreadSeeed (modulo the number of processors) becomes that thread’s IdealProcessor and is then incremented in anticipation of the next thread. When Windows 7 greatly increased the potential number of processors, the single-byte processor number widened to the four-byte processor index and the ThreadSeed was reworked elsewhere in the structure.

Appended for Windows 2000

Offset (x86) Offset (x64) Definition Versions Remarks
0x68 (5.0 to 6.0) 0x98 (late 5.2 to 6.0)
UCHAR PowerState;
5.0 to 6.0  
0x69 (5.0 to early 5.2)  
BOOLEAN DisableQuantum;
5.0 to early 5.2 next in ProcessFlags
0x6A (5.0)
 
UCHAR Spare [2];
5.0 only last member in 5.0

Appended for Windows XP

Additions for version 5.1 begin with the bytes that version 5.0 left explicitly Spare at its end.

Offset (x86) Offset (x64) Definition Versions Remarks
0x6A (5.1 to early 5.2);
0x69 (late 5.2 to 6.0)
0x99 (late 5.2 to 6.0)
UCHAR IdealNode;
5.1 to 6.0 next as USHORT array at 0x68 and 0xC8
0x6A (late 5.2 to 6.0);
0x62 (6.1 to 6.3);
0x6A
0x9A (late 5.2 to 6.0);
0xB6 (6.1);
0x01B6 (6.2 to 6.3);
0x01BE (10.0 to 1809);
0x01C2  (1903);
0x0282
BOOLEAN Visited;
late 5.2 and higher  
0x6B (5.1 to 6.0);
0x63 (6.1 to 6.3);
0x6B
 
UCHAR Spare;
early 5.1;
early 5.2
last member in early 5.1;
last member in early 5.2
0x9B (late 5.2 to 6.0);
0xB7 (6.1);
0x01B7 (6.2 to 6.3);
0x01BF (10.0 to 1809);
0x01C3 (1903);
0x0283
union {
    KEXECUTE_OPTIONS Flags;
    UCHAR ExecuteOptions;
};
late 5.1;
late 5.2 to 6.0
next without union at 0x6C and 0xD2;
last member in late 5.1
UCHAR Spare3;
6.1 only  
KEXECUTE_OPTIONS Flags;
6.2 and higher previously at 0x6C and 0xD2

Inserted for Windows 7

Offset (x86) Offset (x64) Definition Versions Remarks
0x64 (6.1 to 6.3);
0x6C
0xB8 (6.1);
0x01B8 (6.2 to 6.3);
0x01C0 (10.0 to 1809);
0x01C4 (1903);
0x0284
ULONG ThreadSeed [MAX_PROC_GROUPS];
6.1 to 1809 previously UCHAR at 0x67 and 0x97
USHORT ThreadSeed [MAX_PROC_GROUPS];
1903 and higher  
  0x02AC
USHORT ThreadSeedPadding [0x0C];
2004 and higher  
0x6E 0x01EC (1903);
0x02C4
USHORT IdealProcessor [MAX_PROC_GROUPS];
1903 and higher  
  0x02EC
USHORT IdealProcessorPadding [0x0C];
2004 and higher  
0x68 (6.1 to 6.3);
0x70
0xC8 (6.1);
0x0208 (6.2 to 6.3);
0x0210 (10.0 to 1809);
0x0214 (1903);
0x0304
USHORT IdealNode [MAX_PROC_GROUPS];
6.1 and higher previously UCHAR at 0x69 and 0x99
  0x032C
USHORT IdealNodePadding [0x0C];
2004 and higher  
0x6A (6.1 to 6.3);
0x72
0xD0 (6.1);
0x0230 (6.2 to 6.3);
0x0238 (10.0 to 1809);
0x023C (1903);
0x0344
USHORT IdealGlobalNode;
6.1 and higher  
0x6C (6.1 to 6.3);
0x74
0xD2 (6.1);
0x0232 (6.2 to 6.3);
0x023A (10.0 to 1809);
0x023E (1903);
0x0346
KEXECUTE_OPTIONS Flags;
6.1 only previously in union at 0x6B and 0x9B;
next at 0x63 and 0x01B7
USHORT Spare1;
6.2 and higher  
0x6D (6.1) 0xD3 (6.1)
UCHAR Unused1;
6.1 only  
0x6E (6.1 to 6.3);
0x76
 
USHORT IopmOffset;
6.1 and higher previously at 0x30
  0xD4 (6.1)
ULONG Unused2;
6.1 only  
0x70 (6.1 to 6.3);
0x78
0xD8 (6.1)
ULONG Unused4;
6.1 only  
 
KSCHEDULING_GROUP *SchedulingGroup;
6.2 and higher x64 at 0x0258

Appended for Windows Server 2003 SP1

While the first version with x64 builds found a few opportunities to save space by converting the AutoAlignment, DisableBoost and DisableQuantum booleans to bit fields in what were then the new ProcessFlags, it widened the StackCount and moved it to the end. Version 6.1 merged the ancient State into the StackCount as a bit field.

Offset (x86) Offset (x64) Definition Versions Remarks
0x6C (late 5.2 to 6.0);
0x74 (6.1 to 6.3);
0x7C
0xA0 (late 5.2 to 6.0);
0xDC (6.1);
0x0234 (6.2 to 6.3);
0x023C (10.0 to 1809);
0x0240 (1903);
0x0348
ULONG_PTR StackCount;
late 5.2 to 6.0 previously USHORT at 0x60
KSTACK_COUNT StackCount;
6.1 only  
KSTACK_COUNT volatile StackCount;
6.2 and higher  
0x70 (late 5.2 to 6.0);
0x78 (6.1 to 6.3);
0x80
0xA8 (late 5.2 to 6.0);
0xE0 (6.1);
0x0238 (6.2 to 6.3);
0x0240 (10.0 to 1809);
0x0248 (1903);
0x0350
LIST_ENTRY ProcessListEntry;
late 5.2 and higher last member in late 5.2

On x64 builds only, the ProcessListEntry links the KPROCESS into a global list whose head is an internal kernel variable that symbol files name KiProcessListHead. The only known use is for Kernel Patch Protection (perhaps more commonly known as PatchGuard). The list entry is defined all the while for the x86 builds, but not even initialised.

Appended For Windows Vista

Offset (x86) Offset (x64) Definition Versions Remarks
0x78 (6.0);
0x80 (6.1 to 6.3);
0x88
0xB8 (late 5.2 to 6.0);
0xF0 (6.1);
0x0248 (6.2 to 6.3);
0x0250 (10.0 to 1809);
0x0258 (1903);
0x0360
ULONGLONG volatile CycleTime;
6.0 to 6.1 last member in 6.0
ULONGLONG CycleTime;
6.2 and higher  

Inserted For Windows 8

Offset (x86) Offset (x64) Definition Versions Remarks
0x88 (6.2 to 6.3);
0x90
0x0250 (6.2 to 6.3);
0x0258 (10.0 to 1809);
0x0260 (1903);
0x0368
ULONGLONG ContextSwitches;
6.2 and higher  
  0x0258 (6.2 to 6.3);
0x0260 (10.0 to 1809);
0x0268 (1903);
0x0370
KSCHEDULING_GROUP *SchedulingGroup;
6.2 and higher x86 at 0x70
0x90 (6.2 to 6.3);
0x98
0x0260 (6.2 to 6.3);
0x0268 (10.0 to 1809);
0x0270 (1903);
0x0378
ULONG FreezeCount;
6.2 and higher  

Appended For Windows 7

Version 6.1 did not so much append to the structure as move some old, even ancient, members to the end.

Offset (x86) Offset (x64) Definition Versions Remarks
0x88 (6.1);
0x94 (6.2 to 6.3);
0x9C
0xF8 (6.1);
0x0264 (6.2 to 6.3);
0x026C (10.0 to 1809);
0x0274 (1903);
0x037C
ULONG KernelTime;
6.1 and higher previously 0x38 and 0x48
0x8C (6.1);
0x98 (6.2 to 6.3);
0xA0
0xFC (6.1);
0x0268 (6.2 to 6.3);
0x0270 (10.0 to 1809);
0x0278 (1903);
0x0380
ULONG UserTime;
6.1 and higher previously 0x3C and 0x4C
0xA4 0x0274 (1703 to 1809);
0x027C (1903);
0x0384
ULONG ReadyTime;
1703 and higher  
0x90 (6.1);
0x9C (6.2 to 6.3);
0xA4 (10.0 to 1607);
0xA8
 
PVOID VdmTrapcHandler;
6.1 and higher previously 0x4C;
last member in 6.1 to 1607 (x86)
0xAC  
ULONG ProcessTimerDelay;
1703 and higher at 0x44 for x64;
last member in 1703 to 1903 (x86)

Appended for 64-Bit Windows 7

The only truly new members that Windows 7 added are for 64-bit Windows only. Even these relatively few additions are not pretty, since shifts in preceding members allowed version 6.2 to get tighter packing just from rearranging what version 6.1 added.

Offset (x64) Definition Versions Remarks
0x0100 (6.1)
PVOID InstrumentationCallback;
6.1 only previously 0x68;
next at 0x02C0
0x0108 (6.1)
KDGENTRY64 LdtSystemDescriptor;
6.1 only next at 0x0270
0x0118 (6.1)
PVOID LdtBaseAddress;
6.1 only next at 0x0280
0x0120 (6.1)
KGUARDED_MUTEX LdtProcessLock;
6.1 only next as FAST_MUTEX at 0x0288
0x0158 (6.1);
0x026C (6.2 to 6.3);
0x0274 (10.0 to 1607)
USHORT LdtFreeSelectorHint;
6.1 to 1607  
0x015A (6.1);
0x026E (6.2 to 6.3);
0x0276 (10.0 to 1607)
USHORT LdtTableLength;
6.1 to 1607 last member in 6.1 (x64)
0x0270 (6.2 to 6.3);
0x0278 (10.0 to 1607)
KGDTENTRY64 LdtSystemDescriptor;
6.2 to 1607 previously 0x0108
0x0280 (6.2 to 6.3);
0x0288 (10.0 to 1607)
PVOID LdtBaseAddress;
6.2 to 1607 previously 0x0118
0x0288 (6.2 to 6.3);
0x0290 (10.0 to 1607)
FAST_MUTEX LdtProcessLock;
6.2 to 1607 previously KGUARDED_MUTEX at 0x0120
0x0278 (1803 to 1809);
0x0280 (1903);
0x0388
ULONGLONG UserDirectoryTableBase;
1803 and higher  
0x0280 (1803 to 1809);
0x0288 (1903);
0x0390
UCHAR AddressPolicy;
1803 and higher  
0x0278 (1703 to 1709);
0x0281 (1803 to 1809);
0x0289 (1903);
0x0391
UCHAR Spare2 [0x50];
1703 to 1709  
UCHAR Spare2 [0x47];
1803 and higher  
0x02C0 (6.2 to 6.3);
0x02C8 (10.0 to 1809);
0x02D0 (1903);
0x03D8
PVOID InstrumentationCallback;
6.2 and higher previously 0x0100;
last member in 6.2 to 6.3 (x64)
0x02D0 (10.0 to 1809);
0x02D8 (1903);
0x03E0
ULONGLONG SecurePid;
10.0 to 1703 last member in 10.0 to 1703 (x64)
union {
    ULONGLONG SecureHandle;
    struct {
        ULONGLONG SecureProcess : 1;
        ULONGLONG Unused : 1;
    } Flags;
} SecureState;
1709 and higher last member in 1709 to 1903 (x64)

Appended for Windows 10 Version 2004

Offset (x86) Offset (x64) Definition Versions Remarks
0xB0 0x03E8
ULONGLONG KernelWaitTime;
2004 and higher  
0xB8 0x03F0
ULONGLONG UserWaitTime;
2004 and higher  
0xC0 0x03F8
ULONG_PTR EndPadding [8];
2004 and higher last member in 2004