ETHREAD

The ETHREAD structure is the kernel’s representation of a thread object. For instance, if the ObReferenceObjectByHandle function successfully resolves a handle though directed to do so only if the object type is PsThreadType, then the pointer that the function produces for the object is a pointer to an ETHREAD.

Many functions that are exported from the kernel, e.g., for use by drivers, provide for referring to a thread object through a pointer to an ETHREAD. However, the pointer is intended just as an identifier: the structure itself is plainly meant to be opaque outside the kernel.

Variability

Since the ETHREAD structure is internal to the kernel, it should not surprise that the layout changes greatly between Windows versions and even between builds. Some sense of the variability can be gained just from the structure’s changing size. In the following table, different builds of the same version are distinguished as early, late and even very late because they are known to vary the structure even if they don’t change the size. These descriptions are then used as a shorthand throughout this article and its companions.

Version Size (x86) Size (x64)
3.10 0x02E8  
3.50 to 4.0 0x0240  
5.0 0x0248  
5.1 0x0258  
early 5.2 (before Windows Server 2003 SP1) 0x0260  
late 5.2 (Windows Server 2003 SP1) 0x0250 0x0428
very late 5.2 (Windows Server 2003 SP2) 0x0250 0x0410
early 6.0 (before Windows Vista SP1);
late 6.0 (Windows Vista SP1 and higher)
0x0288 0x0450
6.1 0x02B8 0x0498
6.2 0x02C0 0x04C8
6.3 0x0418 0x0778
10.0 0x0458 0x07C0

Layout

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 ETHREAD, Microsoft’s names and types are something of a guess from inspection of how the kernel in those versions uses the ETHREAD. Where use of a member corresponds closely with that of a version for which type information is available in Microsoft’s symbol files, 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 so much, tracking down the correspondence exhaustively would be difficult, if not impossible, even with source code.

For all versions, it is well-known that the ETHREAD starts with a KTHREAD. The latter is the Kernel Core’s representation of the thread object. It is itself a dispatcher object, which has the useful effect that a handle to an ETHREAD can be waited on, for it to get signalled when the thread terminates.

Almost all the shifting of offsets of ETHREAD members between versions is explained by the KTHREAD being even more variable—indeed, much more variable—than the ETHREAD. The only known difference between Windows Server 2003 SP1 and SP2 for the 64-bit builds is that the KTHREAD shrank. To save space, “late 5.2” for the 32-bit builds stands for “v. late 5.2” also.

Offset (x86) Offset (x64) Definition Versions
0x00 0x00
KTHREAD Tcb;
all
0x01D8 (3.10);
0x01B0 (3.50 to 5.0);
0x01C0 (5.1);
0x01C8 (early 5.2);
0x01B8 (late 5.2);
0x01E0 (6.0);
0x0200 (6.1);
0x01E8 (6.2);
0x0338 (6.3);
0x0348
 
LARGE_INTEGER CreateTime;
3.10 to 4.0
 
union {
    LARGE_INTEGER CreateTime;
    struct { 
        UINT NestedFaultCount : 2;  // 0x00000003
        UINT ApcNeeded : 1;         // 0x00000004
    };
};
5.0 to early 5.2
0x0320 (late 5.2);
0x0308 (v. late 5.2);
0x0330 (6.0);
0x0360 (6.1);
0x0348 (6.2);
0x05D0 (6.3);
0x05D8
LARGE_INTEGER CreateTime;
late 5.2 and higher

In those builds that have CreateTime share space with bit fields, the CreateTime actually is in bits 3 to 63 as if it too is a bit field. It’s not that the low 3 bits are lost, but that the whole is shifted left by 3 bits.

Offset (x86) Offset (x64) Definition Versions Remarks
0x01E0 (3.10);
0x01B8 (3.50 to 5.0);
0x01C8 (5.1);
0x01D0 (early 5.2);
0x01C0 (late 5.2);
0x01E8 (6.0);
0x0208 (6.1);
0x01F0 (6.2);
0x0340 (6.3);
0x0350
 
union {
    LARGE_INTEGER ExitTime;
    LIST_ENTRY LpcReplyChain;
};
3.10 to 5.0  
0x0328 (late 5.2);
0x0310 (v. late 5.2);
0x0338 (6.0);
0x0368 (6.1);
0x0350 (6.2);
0x05D8 (6.3);
0x05E0
union {
    LARGE_INTEGER ExitTime;
    LIST_ENTRY LpcReplyChain;
    LIST_ENTRY KeyedWaitChain;
};
5.1 to 5.2  
union {
    LARGE_INTEGER ExitTime;
    LIST_ENTRY KeyedWaitChain;
};
6.0 and higher  
0x01E8 (3.10);
0x01C0 (3.50 to 5.0);
0x01D0 (5.1);
0x01D8 (early 5.2);
0x01C8 (late 5.2);
0x01F0 (6.0);
0x0210 (6.1)
0x0338 (late 5.2);
0x0320 (v. late 5.2);
0x0348 (6.0);
0x0378 (6.1)
union {
    LONG ExitStatus;
    PVOID OfsChain;
};
3.10 to 6.0  
LONG ExitStatus;
6.1 only next at 0x0280 and 0x0450
0x01F8 (6.2);
0x0348 (6.3);
0x0358
0x0360 (6.2);
0x05E8 (6.3);
0x05F0
PVOID ChargeOnlySession;
6.2 and higher  
0x01EC (3.10)   unknown dword 3.10 only  
0x01F0 (3.10)   unknown dword 3.10 only  
0x01C4 (3.50 to 5.0);
0x01D4 (5.1);
0x01DC (early 5.2);
0x01CC (late 5.2);
0x01F4 (6.0);
0x0214 (6.1);
0x01FC (6.2);
0x034C (6.3);
0x035C
0x0340 (late 5.2);
0x0328 (v. late 5.2);
0x0350 (6.0);
0x0380 (6.1);
0x0368 (6.2);
0x05F0 (6.3);
0x05F8
LIST_ENTRY PostBlockList;
3.50 to 5.2 previously at 0x02C4
union {
    LIST_ENTRY PostBlockList;
    struct {
        /*  packed members, see below  */
    };
};
6.0 and higher  

Take away the construction, and these are the members that are packed with PostBlockList:

Offset (x86) Offset (x64) Definition Versions Remarks
0x01F4 (6.0);
0x0214 (6.1);
0x01FC (6.2);
0x034C (6.3);
0x035C
0x0350 (6.0);
0x0380 (6.1);
0x0368 (6.2);
0x05F0 (6.3);
0x05F8
PVOID ForwardLinkShadow;
6.0 and higher  
0x01F8 (6.0);
0x0218 (6.1);
0x0200 (6.2);
0x0350 (6.3);
0x0360
0x0358 (6.0);
0x0388 (6.1);
0x0370 (6.2);
0x05F8 (6.3);
0x0600
PVOID StartAddress;
6.0 and higher previously at 0x021C and 0x03D8

Yes, there is a plan to write something here.

Offset (x86) Offset (x64) Definition Versions
0x01F4 (3.10);
0x01CC (3.50 to 5.0);
0x01DC (5.1);
0x01E4 (early 5.2);
0x01D4 (late 5.2);
0x01FC (6.0);
0x021C (6.1);
0x0204 (6.2);
0x0354 (6.3);
0x0364
 
LIST_ENTRY TerminationPortList;
3.10 to 5.0
0x0350 (late 5.2);
0x0338 (v. late 5.2);
0x0360 (6.0);
0x0390 (6.1);
0x0378 (6.2);
0x0600 (6.3);
0x0608
union {
    TERMINATION_PORT *TerminationPort;
    ETHREAD *ReaperLink;
    PVOID KeyedWaitValue;
};
5.1 to 5.2
union {
    TERMINATION_PORT *TerminationPort;
    ETHREAD *ReaperLink;
    PVOID KeyedWaitValue;
    PVOID Win32StartParameter;
};
6.0 only
union {
    TERMINATION_PORT *TerminationPort;
    ETHREAD *ReaperLink;
    PVOID KeyedWaitValue;
};
6.1 and higher
0x01FC (3.10);
0x01D4 (3.50 to 5.0);
0x01E0 (5.1);
0x01E8 (early 5.2);
0x01D8 (late 5.2);
0x0200 (6.0);
0x0220 (6.1);
0x0208 (6.2);
0x0358 (6.3);
0x0368
0x0358 (late 5.2);
0x0340 (v. late 5.2);
0x0368 (6.0);
0x0398 (6.1);
0x0380 (6.2);
0x0608 (6.3);
0x0610
KSPIN_LOCK ActiveTimerListLock;
all
0x0200 (3.10);
0x01D8 (3.50 to 5.0);
0x01E4 (5.1);
0x01EC (early 5.2);
0x01DC (late 5.2);
0x0204 (6.0);
0x0224 (6.1);
0x020C (6.2);
0x035C (6.3);
0x036C
0x0360 (late 5.2);
0x0348 (v. late 5.2);
0x0370 (6.0);
0x03A0 (6.1);
0x0388 (6.2);
0x0610 (6.3);
0x0618
LIST_ENTRY ActiveTimerListHead;
all
0x0208 (3.10);
0x01E0 (3.50 to 5.0);
0x01EC (5.1);
0x01F4 (early 5.2);
0x01E4 (late 5.2);
0x020C (6.0);
0x022C (6.1);
0x0214 (6.2);
0x0364 (6.3);
0x0374
0x0370 (late 5.2);
0x0358 (v. late 5.2);
0x0380 (6.0);
0x03B0 (6.1);
0x0398 (6.2);
0x0620 (6.3);
0x0628
CLIENT_ID Cid;
all

The Cid holds the process and thread IDs that represent the thread in user mode, notably for API functions that let user-mode clients open a handle to a thread. For some measure of how these IDs were at least originally intended solely for client-level identification, consider that the kernel did not originally export functions that allow kernel-mode software to gets these IDs even for the current thread. The PsGetCurrentProcessId and PsGetCurrentThreadId functions do nothing but extract the IDs from the Cid for the current thread, but they are not exported until version 4.0 (and were not immediately documented). The same straightforward extraction but for an arbitrary thread is done by the PsGetThreadProcessId and PsGetThreadId functions, but only in version 5.1 and higher (and apparently still without documentation).

Offset (x86) Offset (x64) Definition Versions Remarks
0x0210 (3.10);
0x01E8 (3.50 to 5.0);
0x01F4 (5.1);
0x01FC (early 5.2);
0x01EC (late 5.2);
0x0214 (6.0);
0x0234 (6.1);
0x021C (6.2);
0x036C (6.3);
0x037C
 
KSEMAPHORE LpcReplySemaphore;
3.10 to 5.0  
0x0380 (late 5.2);
0x0368 (v. late 5.2);
0x0390 (6.0);
0x03C0 (6.1);
0x03A8 (6.2);
0x0630 (6.3);
0x0638
union {
    KSEMAPHORE LpcReplySemaphore;
    KSEMAPHORE KeyedWaitSemaphore;
};
5.1 to 5.2  
union {
    KSEMAPHORE KeyedWaitSemaphore;
    KSEMAPHORE AlpcWaitSemaphore;
};
6.0 and higher  
0x0224 (3.10);
0x01FC (3.51 to 5.0);
0x0208 (5.1);
0x0210 (early 5.2);
0x0200 (late 5.2)
0x03A0 (late 5.2);
0x0388 (v. late 5.2)
union {
    PVOID LpcReplyMessage;
    PVOID LpcWaitingOnPort;
};
3.10 to 5.2  
0x0200 (3.51 to 5.0)  
ULONG LpcReplyMessageId;
3.51 to 5.0 next at 0x023C
0x0204 (3.51 to 5.0)  
ULONG PerformanceCountLow;
3.51 to 5.0  
0x0228 (3.10)   unknown KMUTEX 3.10 only  
0x0248 (3.10)   unknown TOKEN pointer 3.10 only  
0x024C (3.10)  
TOKEN Token;
3.10 only  
0x0250 (3.10)  
BOOLEAN CopyOnOpen;
3.10 only  
0x0251 (3.10)  
BOOLEAN EffectiveOnly;
3.10 only  
0x0252 (3.10)  
BOOLEAN LpcExitThreadCalled;
3.10 only next at 0x0238
0x0254 (3.10)  
SECURITY_IMPERSONATION_LEVEL ImpersonationLevel;
3.10 only  
0x0208 (3.50 to 5.0);
0x020C (5.1);
0x0214 (early 5.2);
0x0204 (late 5.2);
0x0228 (6.0);
0x0248 (6.1);
0x0230 (6.2);
0x0380 (6.3);
0x0390
0x03A8 (late 5.2);
0x0390 (v. late 5.2);
0x03B0 (6.0);
0x03E0 (6.1);
0x03C8 (6.2);
0x0650 (6.3);
0x0658
PS_IMPERSONATION_INFORMATION *ImpersonationInfo;
3.50 to 5.2  
PS_CLIENT_SECURITY_CONTEXT ClientSecurity;
6.0 and higher  

The names for the version 3.10 members Token, CopyOnOpen, EffectiveOnly and ImpersonationLevel are here duplicated from the structure that symbol files later name as a PS_IMPERSONATION_INFORMATION. In effect, version 3.10 has the whole of this structure where later versions have only a pointer to it. See, however, that version 3.10 doesn’t actually have the structure as a member, named or not, due to intrusion of the apparently unrelated LpcExitThreadCalled (which soon moves to nearly the end of the KTHREAD).

Offset (x86) Offset (x64) Definition Versions Remarks
0x0258 (3.10);
0x020C (3.50 to 5.0);
0x0210 (5.1);
0x0218 (early 5.2);
0x0208 (late 5.2);
0x022C (6.0);
0x024C (6.1);
0x0234 (6.2);
0x0384 (6.3);
0x0394
0x03B0 (late 5.2);
0x0398 (v. late 5.2);
0x03B8 (6.0);
0x03E8 (6.1);
0x03D0 (6.2);
0x0658 (6.3);
0x0660
LIST_ENTRY IrpList;
all  
0x0260 (3.10);
0x0214 (3.50 to 5.0);
0x0218 (5.1);
0x0220 (early 5.2);
0x0210 (late 5.2);
0x0234 (6.0);
0x0254 (6.1);
0x023C (6.2);
0x038C (6.3);
0x039C
0x03C0 (late 5.2);
0x03A8 (v. late 5.2);
0x03C8 (6.0);
0x03F8 (6.1);
0x03E0 (6.2);
0x0668 (6.3);
0x0670
ULONG_PTR TopLevelIrp;
all  
0x0264 (3.10);
0x0218 (3.50 to 5.0);
0x021C (5.1);
0x0224 (early 5.2);
0x0214 (late 5.2);
0x0238 (6.0);
0x0258 (6.1);
0x0240 (6.2);
0x0390 (6.3);
0x03A0
0x03C8 (late 5.2);
0x03B0 (v. late 5.2);
0x03D0 (6.0);
0x0400 (6.1);
0x03E8 (6.2);
0x0670 (6.3);
0x0678
DEVICE_OBJECT *DeviceToVerify;
all  
0x0268 (3.10)   unknown dword 3.10 only  
0x026C (3.10)   unknown array of two unknown (0x1C-byte) structures 3.10 only  
0x02A4 (3.10);
0x021C (3.50 to 5.0)
 
ULONG ReadClusterSize;
3.10 to 5.0 next at 0x0240
0x02A8 (3.10);
0x0220 (3.50 to 5.0)
 
BOOLEAN ForwardClusterOnly;
3.10 to 5.0 next at 0x0254
0x02A9 (3.10);
0x0221 (3.50 to 5.0)
 
BOOLEAN DisablePageFaultClustering;
3.10 to 5.0 next at 0x0255
0x02AA (3.10);
0x0222 (3.50 to 5.0)
 
BOOLEAN DeadThread;
3.10 to 5.0 next as bit in CrossThreadFlags
0x0223 (5.0)  
BOOLEAN HideFromDebugger;
5.0 only next as bit in CrossThreadFlags
0x02AB (3.10);
0x0223 (3.50 to 4.0);
0x0224 (5.0)
 
BOOLEAN HasTerminated;
3.10 to 4.0  
ULONG HasTerminated;
5.0 only next as bit in CrossThreadFlags
0x02AC (3.10);
0x0224 (3.50 to 4.0)
 
PVOID EventPair;
3.10 to 4.0  
0x02B0 (3.10)   unknown LARGE_INTEGER 3.10 only  

The EventPair is the address of an event-pair object for a user-mode client and server to synchronise their work through the NTDLL functions NtSetLowWaitHighThread and NtSetHighWaitLowThread. That Microsoft used the name EventPair for this member is known from the USERKDX.DLL debugger extension for Windows NT 4.0.

Offset (x86) Offset (x64) Definition Versions Remarks
0x02B8 (3.10);
0x0228 (3.50 to 5.0)
 
ULONG GrantedAccess;
3.10 to 5.0 next at 0x0244
0x02BC (3.10);
0x022C (3.50 to 5.0);
0x0220 (5.1);
0x0228 (early 5.2);
0x0218 (late 5.2)
0x03D0 (late 5.2);
0x03B8 (v. late 5.2)
KPROCESS *ThreadsProcess;
3.10 to 5.2  
0x02C0 (3.10);
0x0230 (3.50 to 5.0);
0x0224 (5.1);
0x022C (early 5.2);
0x021C (late 5.2)
0x03D8 (late 5.2);
0x03C0 (v. late 5.2)
PVOID StartAddress;
3.10 to 5.2 next at 0x01F8 and 0x0358
0x02C4 (3.10)  
LIST_ENTRY PostBlockList;
3.10 only next at 0x01C4
0x023C (6.0);
0x025C (6.1)
0x03D8 (6.0);
0x0408 (6.1)
PSP_RATE_APC *RateControlApc;
6.0 only  
PSP_CPU_QUOTA_APC *CpuQuotaApc;
6.1 only  
0x02CC (3.10);
0x0234 (3.50 to 5.0);
0x0228 (5.1);
0x0230 (early 5.2);
0x0220 (late 5.2);
0x0240 (6.0);
0x0260 (6.1);
0x0244 (6.2);
0x0394 (6.3);
0x03A4
0x03E0 (late 5.2);
0x03C8 (v. late 5.2);
0x03E0 (6.0);
0x0410 (6.1);
0x03F0 (6.2);
0x0678 (6.3);
0x0680
union {
    PVOID Win32StartAddress;
    ULONG LpcReceivedMessageId;
};
3.10 to 5.2  
PVOID Win32StartAddress;
6.0 and higher  
0x02D0 (3.10)   unknown pointer 3.10 only  
0x02D4 (3.10)   unaccounted 0x14 bytes 3.10 only last member in 3.10
0x0238 (3.50 to 5.0)  
BOOLEAN LpcExitThreadCalled;
3.50 to 5.0 previously at 0x0252;
next as bit in SameThreadApcFlags
0x0239 (3.50 to 5.0)  
BOOLEAN HardErrorsAreDisabled;
3.50 to 5.0 next as bit in CrossThreadFlags
0x023A (3.50 to 5.0)  
BOOLEAN LpcReceivedMsgIdValid;
3.50 to 5.0 next as bit in SameThreadApcFlags
0x023B (4.0 to 5.0)  
BOOLEAN ActiveImpersonationInfo;
4.0 to 5.0 next as bit in CrossThreadFlags
0x023C (3.50 to 5.0)  
LONG PerformanceCountHigh;
3.50 to 5.0 last member in 3.50;
last member in 3.51;
last member in 4.0
0x0244 (6.0);
0x0264 (6.1);
0x0248 (6.2);
0x0398 (6.3);
0x03A8
0x03E8 (6.0);
0x0418 (6.1);
0x03F8 (6.2);
0x0680 (6.3);
0x0688
PVOID SparePtr0;
6.0 only  
PVOID LegacyPowerObject;
6.1 and higher  
0x0240 (5.0);
0x022C (5.1);
0x0234 (early 5.2);
0x0224 (late 5.2);
0x0248 (6.0);
0x0268 (6.1);
0x024C (6.2);
0x039C (6.3);
0x03AC
0x03E8 (late 5.2);
0x03D0 (v. late 5.2);
0x03F0 (6.0);
0x0420 (6.1);
0x0400 (6.2);
0x0688 (6.3);
0x0690
LIST_ENTRY ThreadListEntry;
5.0 and higher last member in 5.0

Appended for Windows XP

Offset (x86) Offset (x64) Definition Versions Remarks
0x0234 (5.1);
0x023C (early 5.2);
0x022C (late 5.2);
0x0250 (6.0);
0x0270 (6.1);
0x0254 (6.2);
0x03A4 (6.3);
0x03B4
0x03F8 (late 5.2);
0x03E0 (v. late 5.2);
0x0400 (6.0);
0x0430 (6.1);
0x0410 (6.2);
0x0698 (6.3);
0x06A0
EX_RUNDOWN_REF RundownProtect;
5.1 and higher  
0x0238 (5.1);
0x0240 (early 5.2);
0x0230 (late 5.2);
0x0254 (6.0);
0x0274 (6.1);
0x0258 (6.2);
0x03A8 (6.3);
0x03B8
0x0400 (late 5.2);
0x03E8 (v. late 5.2);
0x0408 (6.0);
0x0438 (6.1);
0x0418 (6.2);
0x06A0 (6.3);
0x06A8
EX_PUSH_LOCK ThreadLock;
5.1 and higher  
0x023C (5.1);
0x0244 (early 5.2);
0x0234 (late 5.2)
0x0408 (late 5.2);
0x03F0 (v. late 5.2)
ULONG LpcReplyMessageId;
5.1 to 5.2 previously at 0x0200
0x0240 (5.1);
0x0248 (early 5.2);
0x0238 (late 5.2);
0x0258 (6.0);
0x0278 (6.1);
0x025C (6.2);
0x03AC (6.3);
0x03BC
0x040C (late 5.2);
0x03F4 (v. late 5.2);
0x0410 (6.0);
0x0440 (6.1);
0x0420 (6.2);
0x06A8 (6.3);
0x06B0
ULONG ReadClusterSize;
5.1 and higher previously at 0x021C
0x0244 (5.1);
0x024C (early 5.2);
0x023C (late 5.2)
0x0410 (late 5.2);
0x03F8 (v. late 5.2)
ULONG GrantedAccess;
5.1 to 5.2 previously at 0x0228
0x025C (6.0);
0x027C (6.1);
0x0260 (6.2);
0x03B0 (6.3);
0x03C0
0x0414 (6.0);
0x0444 (6.1);
0x0424 (6.2);
0x06AC (6.3);
0x06B4
LONG volatile MmLockOrdering;
6.0 and higher  
0x0264 (6.2);
0x03B4 (6.3);
0x03C4
0x0428 (6.2);
0x06B0 (6.3);
0x06B8
LONG volatile CmLockOrdering;
6.2 and higher  

Windows XP gathered seven booleans into bit fields in three sets, whose assignment of bits to functionality inevitably changes through successive versions:

Offset (x86) Offset (x64) Definition Versions
0x0248 (5.1);
0x0250 (early 5.2);
0x0240 (late 5.2);
0x0260 (6.0);
0x0280 (6.1);
0x0268 (6.2);
0x03B8 (6.3);
0x03C8
0x0414 (late 5.2);
0x03FC (v. late 5.2);
0x0418 (6.0);
0x0448 (6.1);
0x042C (6.2);
0x06B4 (6.3);
0x06BC
union {
    ULONG CrossThreadFlags;
    struct {
        /*  bit fields, follow link  */
    };
};
5.1 and higher
0x024C (5.1);
0x0254 (early 5.2);
0x0244 (late 5.2);
0x0264 (6.0);
0x0284 (6.1);
0x026C (6.2);
0x03BC (6.3);
0x03CC
0x0418 (late 5.2);
0x0400 (v. late 5.2);
0x041C (6.0);
0x044C (6.1);
0x0430 (6.2);
0x06B8 (6.3);
0x06C0
union {
    ULONG SameThreadPassiveFlags;
    struct {
        /*  bit fields, follow link  */
    };
};
5.1 and higher
0x0250 (5.1);
0x0258 (early 5.2);
0x0248 (late 5.2);
0x0268 (6.0);
0x0288 (6.1);
0x0270 (6.2);
0x03C0 (6.3);
0x03D0
0x041C (late 5.2);
0x0404 (v. late 5.2);
0x0420 (6.0);
0x0450 (6.1);
0x0434 (6.2);
0x06BC (6.3);
0x06C4
union {
    ULONG SameThreadApcFlags;
    struct {
        /*  bit fields, follow link  */
    };
};
5.1 and higher

For who knows what reason, two booleans weren’t changed to bit fields but were merely shifted to the structure’s end.

Offset (x86) Offset (x64) Definition Versions Remarks
0x0254 (5.1);
0x025C (early 5.2);
0x024C (late 5.2)
0x0420 (late 5.2);
0x0408 (v. late 5.2)
BOOLEAN ForwardClusterOnly;
5.1 to 5.2 previously at 0x0220
0x026C (6.0);
0x028C (6.1);
0x0274 (6.2);
0x03C4 (6.3);
0x03D4
0x0424 (6.0);
0x0454 (6.1);
0x0438 (6.2);
0x06C0 (6.3);
0x06C8
BOOLEAN CacheManagerActive;
6.0 and higher  
0x0255 (5.1);
0x0x25D (early 5.2);
0x024D (late 5.2);
0x026D (6.0);
0x028D (6.1);
0x0275 (6.2);
0x03C5 (6.3);
0x03D5
0x0421 (late 5.2);
0x0409 (v. late 5.2);
0x0425 (6.0);
0x0455 (6.1);
0x0439 (6.2);
0x06C1 (6.3);
0x06C9
BOOLEAN DisablePageFaultClustering;
5.1 and higher previously at 0x0221;
last member in 5.1;
last member in early 5.2

Appended for Windows Server 2003 SP1

For all that the build of version 5.2 for Windows Server 2003 SP1 rearranged the KTHREAD, it added just one byte beyond in the ETHREAD, and it anyway fits into alignment space. Indeed, the ETHREAD is very stable through versions 5.1 and 5.2: that members shift and that structure changes size is only because of the KTHREAD.

Even after this addition for Windows Server 2003 SP1, one byte of alignment space remained until Windows 7 found a use for it.

Offset (x86) Offset (x64) Definition Versions Remarks
0x024E (late 5.2);
0x026E (6.0);
0x028E (6.1);
0x0276 (6.2);
0x03C6 (6.3);
0x03D6
0x0422 (late 5.2);
0x040A (v. late 5.2);
0x0426 (6.0);
0x0456 (6.1);
0x043A (6.2);
0x06C2 (6.3);
0x06CA
UCHAR ActiveFaultCount;
late 5.2 and higher last member in late 5.2;
last member in v. late 5.2
0x028F (6.1);
0x0277 (6.2);
0x03C7 (6.3);
0x03D7
0x0457 (6.1);
0x043B (6.2);
0x06C3 (6.3);
0x06CB
UCHAR LockOrderState;
6.1 and higher  

Appended for Windows Vista

Offset (x86) Offset (x64) Definition Versions Remarks
0x0270 (6.0);
0x0290 (6.1);
0x0278 (6.2);
0x03C8 (6.3);
0x03D8
0x0428 (6.0);
0x0458 (6.1);
0x0440 (6.2);
0x06C8 (6.3);
0x06D0
ULONG_PTR AlpcMessageId;
6.0 and higher  
0x0274 (6.0);
0x0294 (6.1);
0x027C (6.2);
0x03CC (6.3);
0x03DC
0x0430 (6.0);
0x0460 (6.1);
0x0448 (6.2);
0x06D0 (6.3);
0x06D8
union {
    PVOID AlpcMessage;
    ULONG AlpcReceiveAttributeSet;
};
6.0 and higher  
0x0280 (6.2);
0x03D0 (6.3);
0x03E0
0x0450 (6.2);
0x06D8 (6.3);
0x06E0
LONG ExitStatus;
6.2 and higher previously at 0x0210 and 0x0378
0x0278 (6.0);
0x0298 (6.1);
0x0284 (6.2);
0x03D4 (6.3);
0x03E4
0x0438 (6.0);
0x0468 (6.1);
0x0458 (6.2);
0x06E0 (6.3);
0x06E8
LIST_ENTRY AlpcWaitListEntry;
6.0 and higher  
0x0280 (6.0);
0x02A0 (6.1);
0x028C (6.2);
0x03DC (6.3);
0x03EC
0x0448 (6.0);
0x0478 (6.1);
0x0468 (6.2);
0x06F0 (6.3);
0x06F8
ULONG CacheManagerCount;
6.0 and higher last member in 6.0

Appended for Windows 7

Offset (x86) Offset (x64) Definition Versions Remarks
0x02A4 (6.1);
0x0290 (6.2);
0x03E0 (6.3);
0x03F0
0x047C (6.1);
0x046C (6.2);
0x06F4 (6.3);
0x06FC
ULONG IoBoostCount;
6.1 and higher  
0x0294 (6.2);
0x03E4 (6.3);
0x03F4
0x0470 (6.2);
0x06F8 (6.3);
0x0708
LIST_ENTRY BoostList;
6.2 and higher  
0x029C (6.2);
0x03EC (6.3);
0x03FC
0x0480 (6.2);
0x0708 (6.3);
0x0710
LIST_ENTRY DeboostList;
6.2 and higher  
0x02A4 (6.2);
0x03F4 (6.3);
0x0404
0x0490 (6.2);
0x0718 (6.3);
0x0720
KSPIN_LOCK BoostListLock;
6.2 and higher  
0x02A8 (6.1 to 6.2);
0x03F8 (6.3);
0x0408
0x0480 (6.1);
0x0498 (6.2);
0x0720 (6.3);
0x0728
KSPIN_LOCK IrpListLock;
6.1 and higher  
0x02AC (6.1 to 6.2);
0x03FC (6.3);
0x040C
0x0488 (6.1);
0x04A0 (6.2);
0x0728 (6.3);
0x0730
PVOID ReservedForSynchTracking;
6.1 and higher  
0x02B0 (6.1 to 6.2);
0x0400 (6.3);
0x0410
0x0490 (6.1);
0x04A8 (6.2);
0x0730 (6.3);
0x0738
SINGLE_LIST_ENTRY CmCallbackListHead;
6.1 and higher last member in 6.1

Appended for Windows 8

Offset (x86) Offset (x64) Definition Versions Remarks
0x02B4 (6.2);
0x0404 (6.3);
0x0414
0x04B0 (6.2);
0x0738 (6.3);
0x0740
GUID const *ActivityId;
6.2 and higher  
0x02B8 (6.2) 0x04B8 (6.2)
PVOID WnfContext;
6.2 only  
0x0408 (6.3);
0x0418
0x0740 (6.3);
0x0748
SINGLE_LIST_ENTRY SeLearningModeListHead;
6.3 and higher  
0x040C (6.3);
0x041C
0x0748 (6.3);
0x0750
PVOID VerifierContext;
6.3 and higher  
0x02BC (6.2);
0x0410 (6.3);
0x0420
0x04C0 (6.2);
0x0750 (6.3);
0x0758
ULONG KernelStackReference;
6.2 and higher last member in 6.2

Appended for Windows 8.1

Offset (x86) Offset (x64) Definition Versions Remarks
0x0414 (6.3);
0x0424
0x0758 (6.3);
0x0760
PVOID AdjustedClientToken;
6.3 and higher last member in 6.3 (x86)
  0x0760 (6.3)
ULONG UserFsBase;
6.3 only;
x64 only
next at 0x043C and 0x0790
  0x0768 (6.3)
ULONGLONG UserGsBase;
6.3 only;
x64 only
next at 0x0440 and 0x0798
  0x0770 (6.3)
PVOID PicoContext;
6.3 only;
x64 only
next at 0x0438 and 0x0788
last member in 6.3 (x64)

Appended for Windows 10

Offset (x86) Offset (x64) Definition Versions Remarks
0x0428 0x0768
PVOID WorkingOnBehalfOfClient;
10.0 and higher  
0x042C 0x0770
PS_PROPERTY_SET PropertySet;
10.0 and higher  
0x0438 0x0788
PVOID PicoContext;
10.0 and higher previously x64-only at 0x0770
0x043C 0x0790
ULONG UserFsBase;
10.0 and higher previously x64-only at 0x0760
0x0440 0x0798
ULONG_PTR UserGsBase;
10.0 and higher previously x64-only at 0x0768
0x0444 0x07A0
THREAD_ENERGY_VALUES *EnergyValues;
10.0 and higher  
0x0448 0x07A8
ULONG volatile CmCellReferences;
10.0 and higher  
0x044C 0x07B0
union {
    ULONG_PTR SelectedCpuSets;
    ULONG_PTR *SelectedCpuSetsIndirect;
};
10.0 and higher  
0x0450 0x07B8
ESILO *Silo;
10.0 and higher last member in 10.0