The KPROCESS structure is the Kernel Core’s portion of the EPROCESS structure. The latter is the process object as exposed through the Object Manager. The KPROCESS is the core of it.


The KPROCESS structure is plainly internal to the kernel and its layout changes greatly between Windows versions and even between builds. In the following table of sizes, different builds of the same version are distinguished as early and late because they are known to vary the structure even if they don’t change the size. These descriptions, as early and late, are then used throughout the article as a shorthand.

Version Size (x86) Size (x64)
3.10 0x70  
3.50 to 4.0 0x68  
early 5.1 (before Windows XP SP2)
late 5.1 (Windows XP SP2 and higher)
early 5.2 (before Windows Server 2003 SP1)
late 5.2 (Windows Server 2003 SP1 and higher) 0x78 0xB8
early 6.0 (before Windows Vista SP1)
late 6.0 (Windows Vista SP1 and higher)
0x80 0xC0
6.1 0x98 0x0160
6.2 to 6.3 0xA0 0x02C8
10.0 0xA8 0x02D8

These sizes, and the offsets, types and names in the tables that follow, are from Microsoft’s 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 them 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.


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.


It is well known that the KPROCESS is a kernel object that can be waited on until it gets signalled, as happens when the process ends its execution. In the DISPATCHER_HEADER at the beginning of a KPROCESS, the Type is ProcessObject (3) in the KOBJECTS enumeration.

Well, the Type is 3 in all versions except 3.10, which has it as 0x0E. This different numbering is in sequence—alphabetically, even—with other kernel objects that are not waitable and which begin with a Type and Size but not with a DISPATCHER_HEADER. And indeed, it cannot be that the KPROCESS in version 3.10 has a DISPATCHER_HEADER. What would be the latter’s WaitListHead is plainly used differently in version 3.10, as the list head for process-specific KPROFILE objects. Can it really be that in version 3.10 processes are not waitable objects (or cannot be waited on by arbitrary threads)? There is non-trivial pre-history to sort out here!

Offset (x86) Offset (x64) Definition Versions Remarks
0x00 0x00
3.50 and higher  
0x00 (3.10)  
3.10 only  
0x02 (3.10)  
3.10 only  
0x04 (3.10)   unaccounted four bytes 3.10 only  
0x08 (3.10);
LIST_ENTRY ProfileListHead;
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)
3.10 only  
ULONG KernelTime;
3.50 only next at 0x38
0x30 (3.10);
0x34 (3.50)
3.10 only  
ULONG UserTime;
3.50 only next at 0x3C
0x38 (3.10 to 3.50);
ULONG_PTR DirectoryTableBase [2];
3.51 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)  
3.10 only next as UCHAR at 0x5E
0x48 (3.10);
0x3C (3.50)
  unknown 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)
3.10 to 3.50 next at 0x5C
0x5C (3.10);
0x4C (3.50);
0x20 (3.51 to 6.0);
KGDTENTRY LdtDescriptor;
0x54 (3.50);
0x28 (3.51 to 6.0);
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)
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  
ULONG Spare0;
6.2 and higher  
0x38 0x48
ULONGLONG DeepFreezeStartTime;
10.0 and higher  
0x38 (6.1 to 6.3);
0x48 (6.1 to 6.3);
6.1 and higher previously KAFFINITY at 0x5C and 0x88
0x40 (3.51 to 6.0);
0x44 (6.1 to 6.3);
0x50 (late 5.2 to 6.0);
0x70 (6.1);
0xF0 (6.2 to 6.3);
LIST_ENTRY ReadyListHead;
3.51 and higher previously 0x18
0x48 (3.51 to 6.0);
0x4C (6.1 to 6.3);
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);
5.1 and higher  
0x50 (6.1 to 6.3);
0x88 (6.1);
0x0108 (6.2 to 6.3);
KAFFINITY_EX volatile ActiveProcessors;
6.1 and higher previously KAFFINITY volatile at 0x34 and 0x40
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)
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 next as ULONG_PTR at 0x6C and 0xA0
0x60 (late 5.2 to 6.0);
0x5C (6.1 to 6.3);
0x90 (late 5.2 to 6.0);
0xB0 (6.1);
0x01B0 (6.2 to 6.3);
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
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);
0x94 (late 5.2 to 6.0);
0xB4 (6.1);
0x01B4 (6.2 to 6.3);
CHAR BasePriority;
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);
0x95 (late 5.2 to 6.0);
0xB5 (6.1);
0x01B5 (6.2 to 6.3);
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, 3.50 and 3.51, all these versions end the structure with unused space because of alignment: six in 3.10 because of the structure’s 8-byte alignment (from using LARGE_INTEGER for KernelTime and UserTime); two in the next versions.

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);
0x9A (late 5.2 to 6.0);
0xB6 (6.1);
0x01B6 (6.2 to 6.3);
BOOLEAN Visited;
late 5.2 and higher  
0x6B (5.1 to 6.0);
0x63 (6.1 to 6.3);
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);
union {
    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  
6.2 and higher previously at 0x6C and 0xD2

Insertions for Windows 7

Offset (x86) Offset (x64) Definition Versions Remarks
0x64 (6.1 to 6.3);
0xB8 (6.1);
0x01B8 (6.2 to 6.3);
6.1 and higher previously UCHAR at 0x67 and 0x97
0x68 (6.1 to 6.3);
0xC8 (6.1);
0x0208 (6.2 to 6.3);
6.1 and higher previously UCHAR at 0x69 and 0x99
0x6A (6.1 to 6.3);
0xD0 (6.1);
0x0230 (6.2 to 6.3);
USHORT IdealGlobalNode;
6.1 and higher  
0x6C (6.1 to 6.3);
0xD2 (6.1);
0x0232 (6.2 to 6.3);
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);
USHORT IopmOffset;
6.1 and higher previously at 0x30
  0xD4 (6.1)
ULONG Unused2;
6.1 only  
0x70 (6.1 to 6.3);
0xD8 (6.1)
ULONG Unused4;
6.1 only  
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);
0xA0 (late 5.2 to 6.0);
0xDC (6.1);
0x0234 (6.2 to 6.3);
ULONG_PTR StackCount;
late 5.2 to 6.0 previously USHORT at 0x60
6.1 only  
KSTACK_COUNT volatile StackCount;
6.2 and higher  
0x70 (late 5.2 to 6.0);
0x78 (6.1 to 6.3);
0xA8 (late 5.2 to 6.0);
0xE0 (6.1);
0x0238 (6.2 to 6.3);
LIST_ENTRY ProcessListEntry;
late 5.2 and higher last member in late 5.2

The ProcessListEntry may be worth studying. On x64 builds, it links processes into a global list whose head is an internal kernel variable that symbol files name KiProcessListHead. Yet I don’t see where they ever get removed from the list and I don’t know any use at all on x64 builds.

Appended For Windows Vista

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

Inserted For Windows 8

Offset (x86) Offset (x64) Definition Versions Remarks
0x88 (6.2 to 6.3);
0x0250 (6.2 to 6.3);
ULONGLONG ContextSwitches;
6.2 and higher  
  0x0258 (6.2 to 6.3);
6.2 and higher x86 at 0x70
0x90 (6.2 to 6.3);
0x0260 (6.2 to 6.3);
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);
0xF8 (6.1);
0x0264 (6.2 to 6.3);
ULONG KernelTime;
6.1 and higher previously 0x38 and 0x48
0x8C (6.1);
0x98 (6.2 to 6.3);
0xFC (6.1);
0x0268 (6.2 to 6.3);
ULONG UserTime;
6.1 and higher previously 0x3C and 0x4C
0x90 (6.1);
0x9C (6.2 to 6.3);
PVOID VdmTrapcHandler;
6.1 and higher previously 0x4C;
last member in 6.1 and higher (x86)

Appended for 64-Bit Windows

The only truly new members that Windows 7 added or that any later version has yet appended to the KPROCESS 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)
6.1 only next as FAST_MUTEX at 0x0288
0x0158 (6.1);
0x026C (6.2 to 6.3);
USHORT LdtFreeSelectorHint;
6.1 and higher  
0x015A (6.1);
0x026E (6.2 to 6.3);
USHORT LdtTableLength;
6.1 and higher last member in 6.1 (x64)
0x0270 (6.2 to 6.3);
KGDTENTRY64 LdtSystemDescriptor;
6.2 and higher previously 0x0108
0x0280 (6.2 to 6.3);
PVOID LdtBaseAddress;
6.2 and higher previously 0x0118
0x0288 (6.2 to 6.3);
FAST_MUTEX LdtProcessLock;
6.2 and higher previously KGUARDED_MUTEX at 0x0120
0x02C0 (6.2 to 6.3);
PVOID InstrumentationCallback;
6.2 and higher previously 0x0100;
last member in 6.2 to 6.3 (x64)
10.0 and higher last member in 10.0 (x64)