CURRENT WORK ITEM - PREVIEW ONLY

KPROCESS

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.

Layout

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.51 to 4.0 0x68  
5.0
early 5.1 (before Windows XP SP2)
late 5.1 (Windows XP SP2 and higher)
early 5.2 (before Windows Server 2003 SP1)
0x6C  
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.

Original

It is well known that the KPROCESS, being a dispatcher object, begins with a DISPATCHER_HEADER in which the Type is 3, i.e., ProcessObject in the KOBJECTS enumeration.

Offset (x86) Offset (x64) Definition Versions Remarks
0x00 0x00
DISPATCHER_HEADER Header;
3.51 and higher  
0x10 0x18
LIST_ENTRY ProfileListHead;
3.51 and higher  
0x18 0x28
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  
0x20 (3.51 to 6.0);
0x1C
 
KGDTENTRY LdtDescriptor;
3.51 and higher  
0x28 (3.51 to 6.0);
0x24
 
KIDTENTRY Int21Descriptor;
3.51 and higher  
0x30 (3.51 to 6.0) 0x38 (late 5.2 to 6.0)
USHORT IopmOffset;
3.51 to 6.0 moves back (x86)
0x32 (3.51 to 6.0)  
UCHAR Iopl;
3.51 to early 6.0  
UCHAR Unused1;
late 6.0 only  
0x33 (3.51 to 6.0)  
UCHAR VdmFlag;
3.51 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  
KAFFINITY volatile ActiveProcessors;
5.2 to 6.0 moves back (changes type)
0x38 (3.51 to 6.0) 0x48 (5.0 to 6.0)
ULONG KernelTime;
3.51 to 6.0 moves back
0x3C (3.51 to 6.0) 0x4C (5.0 to 6.0)
ULONG UserTime;
3.51 to 6.0 moves back
0x2C 0x30
LIST_ENTRY ThreadListHead;
6.1 and higher from behind
0x34 0x40
ULONG_PTR ProcessLock;
6.1 only from behind
ULONG ProcessLock;
6.2 and higher  
  0x44
ULONG Spare0;
6.2 and higher  
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 from behind (changed type)
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
LIST_ENTRY ReadyListHead;
3.51 and higher  
0x48 (3.51 to 6.0);
0x4C (6.1 to 6.3);
0x54
 
LIST_ENTRY SwapListEntry;
3.51 to 5.0  
0x60 (late 5.2 to 6.0);
0x80 (6.1);
0x0100 (6.2 to 6.3);
0x0108
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
KAFFINITY_EX volatile ActiveProcessors;
6.1 and higher from ahead (changed type) 
0x4C (5.1 to 6.0)  
PVOID VdmTrapcHandler;
5.1 to 6.0 moves back
  0x68 (late 5.2 to 6.0)
PVOID Reserved1;
late 5.2 only  
PVOID InstrumentationCallback;
6.0 only moves back
0x50 (3.51 to 6.0) 0x70 (late 5.2 to 6.0)
LIST_ENTRY ThreadListHead;
3.51 to 6.0 moves ahead
0x58 (3.51 to 6.0) 0x80 (late 5.2 to 6.0)
KSPIN_LOCK ProcessLock;
3.51 to 6.0 moves ahead
0x5C (3.51 to 6.0) 0x88 (late 5.2 to 6.0)
KAFFINITY Affinity;
3.51 to 6.0 moves ahead (changes type)
0x60 (3.51 to early 5.2)  
USHORT StackCount;
3.51 to early 5.2 moves back
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
union {
    struct {
        /*  bit fields, see below  */
    };
    LONG ProcessFlags;
};
late 5.2 only  
union {
    struct {
        /*  bit fields, see below  */
    };
    LONG volatile ProcessFlags;
};
6.0 and higher  
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
CHAR BasePriority;
3.51 and higher  
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
CHAR ThreadQuantum;
3.51 to early 5.2  
CHAR QuantumReset;
late 5.2 and higher  
0x64 (3.51 to early 5.2)  
BOOLEAN AutoAlignment;
3.51 to early 5.2 moves to ProcessFlags
0x65 (4.0 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 moves to StackCount;
last member in 3.51

Appended for Windows NT 4.0

Version 4.0 adds just two bytes which anyway fit into the undefined space left for alignment. 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 moves back (changes type)
0x67 (4.0 to early 5.2)  
BOOLEAN DisableBoost;
4.0 to early 5.2 moves to 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 early 5.2);
0x68 (late 5.2 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 moves to 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 Spare at the 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 moves back (changes type)
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
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 only 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
union {
    KEXECUTE_OPTIONS Flags;
    UCHAR ExecuteOptions;
};
late 5.1;
late 5.2 to 6.0
moves back (changes type);
last member in late 5.1
UCHAR Spare3;
6.1 and higher  
KEXECUTE_OPTIONS Flags;
6.2 and higher from behind

Insertions 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
ULONG ThreadSeed [MAX_PROC_GROUPS];
6.1 and higher from ahead (changed type)
0x68 (6.1 to 6.3);
0x70
0xC8 (6.1);
0x0208 (6.2 to 6.3);
0x0210
USHORT IdealNode [MAX_PROC_GROUPS];
6.1 and higher from ahead (changed type)
0x6A (6.1 to 6.3);
0x72
0xD0 (6.1);
0x0230 (6.2 to 6.3);
0x0238
USHORT IdealGlobalNode;
6.1 and higher  
0x6C (6.1 to 6.3);
0x74
0xD2 (6.1);
0x0232 (6.2 to 6.3);
0x023A
KEXECUTE_OPTIONS Flags;
6.1 only from ahead (changed type);
moves ahead
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 from ahead
  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  

Appended for Windows Server 2003 SP1

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
ULONG_PTR StackCount;
late 5.2 to 6.0 from ahead
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
LIST_ENTRY ProcessListEntry;
late 5.2 and higher last member in late 5.2

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
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
ULONGLONG ContextSwitches;
6.2 and higher  
  0x0258 (6.2 to 6.3);
0x0260
KSCHEDULING_GROUP *SchedulingGroup;
6.2 and higher  
0x90 (6.2 to 6.3);
0x98
0x0260 (6.2 to 6.3);
0x0268
ULONG FreezeCount;
6.2 and higher  

Appended For Windows 7

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
ULONG KernelTime;
6.1 and higher from ahead
0x8C (6.1);
0x98 (6.2 to 6.3);
0xA0
0xFC (6.1);
0x0268 (6.2 to 6.3);
0x0270
ULONG UserTime;
6.1 and higher from ahead
0x90 (6.1);
0x9C (6.2 to 6.3);
0xA4
 
PVOID VdmTrapcHandler;
6.1 and higher from ahead;
last member in 6.1 (x86);
last member in 6.2 (x86);
last member in 6.3 (x86);
last member in 10.0 (x86)

The only truly new members that Windows 7 adds at the end are for 64-bit Windows only.

Offset (x86) Offset (x64) Definition Versions Remarks
  0x0100 (6.1)
PVOID InstrumentationCallback;
6.1 only from ahead;
moves back
  0x0108 (6.1)
KDGENTRY64 LdtSystemDescriptor;
6.1 only moves back
  0x0118 (6.1)
PVOID LdtBaseAddress;
6.1 only moves back
  0x0120 (6.1)
KGUARDED_MUTEX LdtProcessLock;
6.1 only moves back
  0x0158 (6.1);
0x026C (6.2 to 6.3);
0x0274
USHORT LdtFreeSelectorHint;
6.1 and higher  
  0x015A (6.1);
0x026E (6.2 to 6.3);
0x0276
USHORT LdtTableLength;
6.1 and higher last member in 6.1 (x64)

Because of shifts in preceding members, version 6.2 gets tighter packing just from rearranging what version 6.1 added.

Offset (x86) Offset (x64) Definition Versions Remarks
  0x0270 (6.2 to 6.3);
0x0278
KGDTENTRY64 LdtSystemDescriptor;
6.2 and higher from ahead
  0x0280 (6.2 to 6.3);
0x0288
PVOID LdtBaseAddress;
6.2 and higher from ahead
  0x0288 (6.2 to 6.3);
0x0290
FAST_MUTEX LdtProcessLock;
6.2 and higher from ahead
  0x02C0 (6.2 to 6.3);
0x02C8
PVOID InstrumentationCallback;
6.2 and higher from ahead;
last member in 6.2 (x64);
last member in 6.3 (x64)

Appended for 64-Bit Windows 10

Offset (x86) Offset (x64) Definition Versions Remarks
  0x02D0
ULONGLONG SecurePid;
10.0 and higher last member in 10.0 (x64)

Process Flags

The 32-bit bit fields in union with the ProcessFlags member have a complicated history that seems better presented separately from the structure. Notably, new versions bring not just new fields but redefinitions and even changes of type. The original, for the version 5.2 from Windows Server 2003 SP1, was a straightforward tidying up that collected what had been three byte-sized booleans, but then someone got exercised about volatility and perhaps someone else later decided it didn’t matter:

Mask Definition Versions
0x00000001
LONG AutoAlignment : 1;
late 5.2 only
LONG volatile AutoAlignment : 1;
6.0 to 6.1
LONG AutoAlignment : 1;
6.2 and higher
0x00000002
LONG DisableBoost : 1;
late 5.2 only
LONG volatile DisableBoost : 1;
6.0 to 6.1
LONG DisableBoost : 1;
6.2 and higher
0x00000004
LONG DisableQuantum : 1;
late 5.2 only
LONG volatile DisableQuantum : 1;
6.0 to 6.1
LONG DisableQuantum : 1;
6.2 and higher

Additions are instead complicated by insertion and deletion. How version 6.2 added one bit as signed and two as unsigned may forever be anyone’s guess.

Mask Definition Versions
0x00000008 (6.2 to 6.3)
LONG AffinitySet : 1;
6.2 to 6.3
0x00000010 (6.2 to 6.3);
0x00000008
ULONG DeepFreeze : 1;
6.2 and higher
0x00000020 (6.2 to 6.3);
0x00000010
ULONG TimeVirtualization : 1;
6.2 and higher
0x00000040 (6.3);
0x00000020
ULONG CheckStackExtents : 1;
6.3 and higher
0x000000C0
ULONG SpareFlags0 : 2;
10.0 and higher

An ActiveGroupsMask is kept as the last of the defined fields, perhaps so that its processor-dependent width does not affect other fields. Windows 10 perhaps inserts the SpareFlags0 to align ActiveGroupMasks while leaving space both before for more bits and after for more processor groups. All versions have reserved bits at the end.

Mask (x86) Mask (x64) Definition Versions
0x00000008 (6.1);
0x00000040 (6.2);
0x00000080 (6.3);
0x00000100
0x00000078 (6.1);
0x03FFFFC0 (6.2);
0x07FFFF80 (6.3);
0x0FFFFF00
ULONG volatile ActiveGroupsMask : MAX_PROC_GROUPS;
6.1 only
ULONG ActiveGroupsMask : MAX_PROC_GROUPS;
6.2 and higher
   
LONG ReservedFlags : 29;
late 5.2 only
LONG volatile ReservedFlags : 29;
6.0 only
LONG volatile ReservedFlags : 29 - MAX_PROC_GROUPS;
6.1 only
LONG ReservedFlags : 26 - MAX_PROC_GROUPS;
6.2 only
LONG ReservedFlags : 25 - MAX_PROC_GROUPS;
6.3 only
LONG ReservedFlags : 24 - MAC_PROC_GROUPS;
10.0 and higher

KEXECUTE_OPTIONS

The KEXECUTE_OPTIONS were introduced simultaneously for version 5.1 in Windows XP SP2 and version 5.2 in Windows Server 2003 SP1. While they seem to have no purpose outside the KPROCESS, they may as well be listed here. They were originally presented as a simple structure of bit fields:

typedef struct _KEXECUTE_OPTIONS {      // late 5.2 to 6.0
    /*  bit fields, see below  */
} KEXECUTE_OPTIONS;

Then Windows 7 wrapped the structure into a union with an integral member for accessing all bits together:

typedef union _KEXECUTE_OPTIONS {       // 6.1 and higher
    struct {
        /*  bit fields, see below  */
    };
    UCHAR volatile ExecuteOptions;
    UCHAR ExceptionOptionsNV;           // 6.2 and higher
} KEXECUTE_OPTIONS;

Either way, the bit fields themselves remain the same except that one was added for Windows Vista SP1:

Mask Definition Versions
0x01
UCHAR ExecuteDisable : 1;
late 5.1;
late 5.2 and higher
0x02
UCHAR ExecuteEnable : 1;
late 5.1;
late 5.2 and higher
0x04
UCHAR DisableThunkEmulation : 1;
late 5.1;
late 5.2 and higher
0x08
UCHAR Permanent : 1;
late 5.1;
late 5.2 and higher
0x10
UCHAR ExecuteDispatchEnable : 1;
late 5.1;
late 5.2 and higher
0x20
UCHAR ImageDispatchEnable : 1;
late 5.1;
late 5.2 and higher
0x40
UCHAR DisableExceptionChainValidation : 1;
late 6.0 and higher
 
UCHAR Spare : 2;
late 5.1;
late 5.2 to early 6.0
UCHAR Spare : 1;
late 6.0 and higher

KSTACK_COUNT

The KSTACK_COUNT also seems to have no purpose outside the KPROCESS:

typedef union _KSTACK_COUNT {           // 6.1 only
    LONG volatile Value;
    struct {
        ULONG volatile State : 3;
        ULONG StackCount : 29;
    };
} KSTACK_COUNT;

It is not known what explains the mixtures of sign and volatility. Windows 8 shifts the volatility to where the structure appears in the KPROCESS as the StackCount member:

typedef union _KSTACK_COUNT {           // 6.2 and higher
    LONG Value;
    struct {
        ULONG State : 3;
        ULONG StackCount : 29;
    };
} KSTACK_COUNT;