Geoff Chappell, Software Analyst
The THREADINFO (formally tagTHREADINFO) is the most of what WIN32K.SYS keeps about a thread. A portion at its start is reproduced as a W32THREAD (formally _W32THREAD), apparently as an unnamed member. It is not clear what governs the separation.
No thread is born with a THREADINFO and many execute to their end without ever having one—and not just for being system threads that execute no user-mode code at all. To get a THREADINFO a thread must try to use at least some of the extensive but optional GUI functionality that Windows is known and loved for. When a thread calls a system service that is not yet defined for the thread, the kernel attempts to convert the thread to a GUI thread. This gets the thread connected with WIN32K.SYS in kernel mode and its support for USER32.DLL and GDI32.DLL, among others, in user mode—and gives the thread an additional service descriptor table so that those DLLs can communicate with WIN32K. Though the distribution of the work involved in this conversion varies between versions, the mechanism is essentially unchanged since version 3.51 prepared for the introduction of WIN32K in version 4.0.
Neither the W32THREAD nor the THREADINFO is documented, but structural details of the W32THREAD—more or less equivalent to having a C-language definition—are disclosed as type information in the public symbol files for WIN32K.SYS starting with Windows XP. The larger THREADINFO is apparently more secret. Though symbol files for Windows 8 and higher name the THREADINFO in the C++ decorations of internal routines, type information for the structure is present in symbol files for Windows 7 only—not before and not since.
For some versions before Windows XP, Microsoft’s names for some, and even all, members of both structures are known with varying confidence from the output of one or another debugger command as implemented in the USEREXTS.DLL or USERKDX.DLL debugger extensions which Microsoft published with one or another Device Driver Kit (DDK). Nobody would sensibly count this as documentation. It does show, however, that Microsoft understood for a while that knowledge of the THREADINFO may help programmers in the depths of debugging what they’re doing with Windows!
The THREADINFO has long been a kernel-mode structure allocated from per-session paged pool, but although it is not accessible from user mode its address is readily available to user-mode software, even with low integrity, even as late as Windows 10, through all sorts of techniques from all sorts of places.
Most direct and obvious is that in each TEB for a GUI thread, the Win32ThreadInfo member, reliably at offset 0x40 since version 3.51, is formally a pointer to void but what it actually holds is the kernel-mode address of the THREADINFO. Less direct but ubiquitous is that the table of handles to user objects is in shared memory such that any user-mode process that can find the SHAREDINFO structure and knows that the aheList member addresses an array of HANDLEENTRY structures can get THREADINFO addresses by the bucketload because in each HANDLEENTRY for a user object that can be owned by a thread (as can a window, for instance) the pOwner member is the address of the owning thread’s THREADINFO.
These kernel-mode addresses’ presence in user-mode memory—despite increasing effort by Microsoft to eliminate such leakage in general—is perhaps a relic from the earliest Windows versions. Before version 4.0, the THREADINFO was a user-mode structure. Much of the work that is since done in kernel mode by WIN32K.SYS was instead done in user mode by WINSRV.DLL in the CSRSS.EXE process. Especially notable in the present context is a continuous history of a routine named xxxCreateThreadInfo now in WIN32K but with the same name in WINSRV version 3.51 and with an even earlier existence in version 3.10 as plain CreateThreadInfo.
In kernel mode, each KTHREAD has a Win32Thread member whose value is returned by the exported function PsGetThreadWin32Thread in version 5.1 and higher. Starting with version 5.2 from Windows Server 2003 SP1, the kernel also exports a PsGetCurrentThreadWin32Thread which, of course, reads this member specifically from the current thread’s KTHREAD. The contemporaneous elaboration PsGetCurrentThreadWin32ThreadAndEnterCriticalRegion does the same but also puts the thread into a critical region (as if to have called KeEnterCriticalRegion) and indirectly returns the thread’s process ID. None of these functions are documented, but all three are declared in the NTOSP.H that was disclosed in some editions of the Windows Driver Kit (WDK) for Windows 10.
The Win32Thread in the KTHREAD also is formally a pointer to void. Historically, what it actually points to, if it points to anything, is the THREADINFO. In version 10.0, however, it points to a W32THREADNONPAGED that is in session-global non-paged pool and whose pW32Thread is in turn a pointer to the THREADINFO (which, remember, is in per-session paged pool).
Not only is the THREADINFO highly variable between versions but in the one version for which publicly available symbol files have type information not just for the W32THREAD but for the THREADINFO too, reconciling the information against the matching executable shows immediately that the THREADINFO as described in the symbol files is not the full story. The memory block the THREADINFO is created in is larger than is declared for the structure, yet the additional space is accessed as if for members of a larger structure. It could be that the THREADINFO is itself a reduction from an even more secret structure, but close inspection shows something more interesting: the THREADINFO as described by type information in the symbol file for WIN32K is not the THREADINFO that the matching WIN32K executable actually uses. Even the following table just of changing sizes is therefore not just more than usually complex but more than usually uncertain.
Version | W32THREAD | THREADINFO | Remarks | ||
---|---|---|---|---|---|
Size (x86) | Size (x64) | SIze (x86) | Size (x64) | ||
3.10 | 0x026C | ||||
3.51 | 0x01F8 | ||||
early 4.0 (before Windows NT 4.0 SP3) | 0x38 | 0x0148 | |||
late 4.0 (Windows NT 4.0 SP3 and higher) | 0x38 | 0x0150 | |||
5.0 | 0x1C | 0x013C | |||
5.1 | 0x28 | 0x014C | |||
5.2 | 0x28 | 0x60 | 0x0150 | 0x0278 | |
6.0 | 0x28 | 0x60 | 0x0164 | 0x0298 | |
6.1 | 0xB4 | 0x0150 | 0x0220 | 0x03D0 | symbol files have 0x0208 and 0x03A8 for THREADINFO size |
6.2 | 0xC0 | 0x0168 | 0x0278 | 0x0468 | |
6.3 | 0xC0 | 0x0168 | 0x0298 | 0x0490 | |
10.0 | 0xC4 | 0x0170 | 0x02D0 | 0x04E0 |
That the THREADINFO shrinks by nearly half before it starts the continuing growth that would ordinarily be expected is because three relatively large structures that are later built on the stack or in dynamically allocated memory started out in the THREADINFO itself.
For versions 5.1 and higher, offsets, types and Microsoft’s names for the first part of the THREADINFO are known from type information in public symbol files. For versions 4.0 and 5.0, offsets and Microsoft’s names are known with good confidence from the output of the debugger’s !dso command as supported by the USEREXTS.DLL and USERKDX.DLL debugger extensions for these versions.
Memory for the THREADINFO is allocated by the kernel in version 4.0, the required size having been communicated by WIN32K as an argument to the undocumented (and highly variable) PsEstablishWin32Callouts function. The first 0x20 bytes of the THREADINFO get copied from the kernel’s service descriptor table. The remainder is zero-initialised, to be completed by WIN32K. It is not known how service descriptor table entries are represented in Microsoft’s definitions. Version 5.0 redistributed the work, such that the THREADINFO is instead created by WIN32K and the service descriptor tables stay with the kernel.
Offset (x86) | Offset (x64) | Definition | Versions | Remarks |
---|---|---|---|---|
0x00 (4.0) |
<unknown-type> ServiceDescriptorTable [2]; |
4.0 only | ||
0x20 (4.0); 0x00 |
0x00 |
ETHREAD *Thread; |
4.0 only | |
ETHREAD *pEThread; |
5.0 and higher | |||
0x24 (4.0) |
CLIENT_ID RealClientId; |
4.0 only | ||
0x2C (4.0) |
PVOID GdiCachedProcessHandle; |
4.0 only | ||
0x04 | 0x08 |
ULONG RefCount; |
5.0 and higher | |
0x08 | 0x10 |
TL *ptlW32; |
5.0 and higher | |
0x30 (4.0); 0x0C |
0x18 |
PVOID pgdiDcattr; |
4.0 and higher | |
0x34 (4.0); 0x10 |
0x20 |
PVOID pgdiBrushAttr; |
4.0 and higher | last W32THREAD member in 4.0 |
0x14 | 0x28 |
PVOID pUMPDObjs; |
5.0 to 6.1 | |
LIST_ENTRY UMPDOBJList; |
10.0 | |||
0x18 (5.0 to 6.3); 0x1C |
0x30 (5.1 to 6.3); 0x38 |
PVOID pUMPDHeap; |
5.0 and higher | last W32THREAD member in 5.0 |
0x1C (5.1) |
ULONG dwEngAcquireCount; |
5.1 only | ||
0x20 (5.1) |
PVOID pSemTable; |
5.1 only | ||
0x1C (6.2 to 6.3) | 0x38 (6.2 to 6.3) |
PVOID DxThread; |
6.2 to 6.3 | next at 0x28 and 0x50 |
0x24 (5.1); 0x1C (5.2 to 6.1); 0x20 (6.2 to 6.3) |
0x38 (5.2 to 6.1); 0x40 (6.2 to 6.3) |
PVOID pUMPDObj; |
5.2 to 6.3 | last W32THREAD member in 5.1 |
0x24 (6.2 to 6.3); 0x20 |
0x40 (5.2 to 6.1); 0x48 (6.2 to 6.3); 0x40 |
PVOID pProxyPort; |
late 5.2 and higher (x64); 6.2 and higher (x86) |
|
0x28 (6.2 to 6.3); 0x24 |
0x48 (5.2 to 6.1); 0x50 (6.2 to 6.3); 0x48 |
PVOID pClientID; |
late 5.2 and higher (x64); 6.2 and higher (x86) |
|
0x28 | 0x50 |
PVOID DxThread; |
10.0 and higher | previously at 0x1C and 0x38 |
0x20 (5.2 to 6.1); 0x2C |
0x50 (5.2 to 6.1); 0x58 |
LIST_ENTRY GdiTmpAllocList; |
5.2 only | last W32THREAD member in 5.2 |
LIST_ENTRY GdiTmpTgoList; |
6.0 and higher | last W32THREAD member in 6.0 | ||
0x28 (6.1); 0x34 |
0x60 (6.1); 0x68 |
ULONG pRBRecursionCount; |
6.1 and higher | |
0x2C (6.1); 0x38 |
0x64 (6.1); 0x6C |
ULONG pNonRBRecursionCount; |
6.1 and higher | |
0x30 (6.1); 0x3C |
0x68 (6.1); 0x70 |
TLSPRITESTATE tlSpriteState; |
6.1 and higher | |
0x90 (6.1); 0x9C |
0x0110 (6.1); 0x0118 |
PVOID pSpriteState; |
6.1 and higher | |
0x94 (6.1); 0xA0 |
0x0118 (6.1); 0x0120 |
PVOID pDevHTInfo; |
6.1 and higher | |
0x98 (6.1); 0xA4 |
0x0120 (6.1); 0x0128 |
ULONG ulDevHTInfoUniqueness; |
6.1 and higher | |
0x9C (6.1); 0xA8 |
0x0128 (6.1); 0x0130 |
PVOID pdcoAA; |
6.1 and higher | |
0xA0 (6.1); 0xAC |
0x0130 (6.1); 0x0138 |
PVOID pdcoRender; |
6.1 and higher | |
0xA4 (6.1); 0xB0 |
0x0138 (6.1); 0x0140 |
PVOID pdcoSrc; |
6.1 and higher | |
0xA8 (6.1); 0xB4 |
0x0140 (6.1); 0x0148 |
BOOLEAN bEnableEngUpdateDeviceSurface; |
6.1 and higher | |
0xA9 (6.1); 0xB5 |
0x0141 (6.1); 0x0149 |
BOOLEAN bIncludeSprites; |
6.1 and higher | |
0xB6 | 0x014A |
BOOLEAN bEnableAppContainerRendering; |
6.3 and higher | |
0xAC (6.1); 0xB8 |
0x0144 (6.1); 0x014C |
ULONG ulWindowSystemRendering; |
6.1 and higher | |
0xB0 (6.1); 0xBC |
0x0148 (6.1); 0x0150 |
ULONG iVisRgnUniqueness; |
6.1 and higher | last W32THREAD member in 6.1; last W32THREAD member in 6.2 (x86); last W32THREAD member in 6.3 (x86) |
0x0158 |
ULONGLONG RefCountInc; |
6.2 and higher | ||
0x0160 |
ULONGLONG RefCountDec; |
6.2 and higher | last W32THREAD member in 6.2 (x64); last W32THREAD member in 6.3 (x64) |
|
0xC0 | 0x0168 |
PVOID pUmfdTls; |
10.0 and higher | last W32THREAD member in 10.0 |
For the rest of the THREADINFO, type information is known in public symbol files for version 6.1 only. Microsoft’s names for some members in versions 3.51 to 5.0 inclusive are known from the output of debugger commands. Most noticeable is the !dti command. More notable for versions 4.0 and 5.0 is the !dso command as supported by the USERKDX.DLL debugger extensions for these versions. Still, structural details of the THREADINFO are more than usually scarce among public sources. For almost all Windows versions, the tables from here are necessarily the result of deduction, inference and outright guesswork from inspection of executables. Near the end of the structure, this becomes true even of version 6.1 despite Microsoft’s disclosure of type information.
Offset (x86) | Offset (x64) | Definition | Versions | Remarks |
---|---|---|---|---|
0x00 (3.10 to 3.51) |
THROBJHEAD head; |
3.10 to 3.51 | ||
0x0C (3.10); 0x10 (3.51) |
unknown THREADINFO pointer | 3.10 to 3.51 | ||
0x38 (4.0) |
LIST_ENTRY PtiLink; |
4.0 only | next at 0xA4 | |
0x10 (3.10) | unknown heap handle | 3.10 only | ||
0x14 (3.10) | unknown event handle | 3.10 only | ||
0x14 (3.51); 0x40 (4.0); 0x1C (5.0); 0x28 (5.1 to 6.0); 0xB4 (6.1); 0xC0 (6.2 to 6.3); 0xC4 |
0x60 (5.2 to 6.0); 0x0150 (6.1); 0x0168 (6.2 to 6.3); 0x0170 |
TL *ptl; |
3.51 and higher | |
0x44 (4.0) |
TL *ptlOb; |
4.0 only | ||
0x48 (4.0) |
TL *ptlPool; |
4.0 only | ||
0x4C (4.0) |
INT cEnterCount; |
4.0 only | next at 0xC4 |
Version 3.10 has at offset 0x14 a handle to a per-thread event that may correspond in later versions to the per-process InputIdleEvent.
Offset (x86) | Offset (x64) | Definition | Versions | Remarks |
---|---|---|---|---|
0x18 (3.10 to 3.51); 0x50 (4.0); 0x20 (5.0); 0x2C (5.1 to 6.0); 0xB8 (6.1); 0xC4 (6.2 to 6.3); 0xC8 |
0x68 (5.2 to 6.0); 0x0158 (6.1); 0x0170 (6.2 to 6.3); 0x0178 |
PROCESSINFO *ppi; |
all | |
0x1C (3.10 to 3.51); 0x54 (4.0); 0x24 (5.0); 0x30 (5.1 to 6.0); 0xBC (6.1); 0xC8 (6.2 to 6.3); 0xCC |
0x70 (5.2 to 6.0); 0x0160 (6.1); 0x0178 (6.2 to 6.3); 0x0180 |
Q *pq; |
all | |
0x58 (4.0); 0x28 (5.0); 0x34 (5.1 to 6.0); 0xC0 (6.1); 0xCC (6.2 to 6.3); 0xD0 |
0x78 (5.2 to 6.0); 0x0168 (6.1); 0x0180 (6.2 to 6.3); 0x0188 |
KL *spklActive; |
4.0 and higher | |
0x20 (3.10 to 3.51); 0x5C (4.0) |
MLIST mlPost; |
3.10 to 4.0 | next at 0xC8 | |
0x68 (4.0) |
USHORT fsChangeBitsRemoved; |
4.0 only | previously as ULONG at 0x38; next at 0xD4 |
|
0x6A (4.0) |
USHORT cDeskClient; |
4.0 only | ||
0x6C (4.0); 0x2C (5.0); 0x38 (5.1 to 6.0); 0xC4 (6.1); 0xD0 (6.2 to 6.3); 0xD4 |
0x80 (5.2 to 6.0); 0x0170 (6.1); 0x0188 (6.2 to 6.3); 0x0190 |
CLIENTTHREADINFO *pcti; |
4.0 and higher | |
0x70 (4.0) |
CLIENTTHREADINFO cti; |
4.0 only | next at 0x012C | |
0x28 (3.10); 0x2C (3.51); 0x80 (4.0) |
HANDLE hEventQueueClient; |
3.51 to 4.0 | next at 0x9C | |
0x2C (3.10); 0x30 (3.51); 0x84 (4.0) |
HANDLE hEventQueueServer; |
3.10 to 3.51 | ||
KEVENT *pEventQueueServer; |
4.0 | next at 0xA0 | ||
0x30 (3.10); 0x34 (3.51) |
ULONG fsChangeBits; |
3.10 to 3.51 | next as USHORT in CLIENTTHREADINFO | |
0x38 (3.51) |
ULONG fsChangeBitsRemovd; |
3.51 only | next as USHORT at 0x68 | |
0x34 (3.10); 0x3C (3.51) |
ULONG fsWakeBits; |
3.10 to 3.51 | next as USHORT in CLIENTTHREADINFO | |
0x38 (3.10); 0x40 (3.51) |
ULONG fsWakeMask; |
3.10 to 3.51 | next as USHORT in CLIENTTHREADINFO |
The spelling fsChangeBitsRemovd is Microsoft’s, specifically from the USEREXTS debugger extension from the DDK for Windows NT 3.51. This is as good a moment as any to remind that the text for a debugger extension’s description of a member does not necessarily reproduce the member’s name from whatever header has the member’s source-code definition.
Offset (x86) | Offset (x64) | Definition | Versions | Remarks |
---|---|---|---|---|
0x88 (4.0) |
KEVENT **apEvent; |
4.0 only | next at 0xDC | |
0x3C (3.10); 0x44 (3.51); 0x8C (4.0); 0x30 (5.0); 0x3C (5.1 to 6.0); 0xC8 (6.1); 0xD4 (6.2 to 6.3); 0xD8 |
0x88 (5.2 to 6.0); 0x0178 (6.1); 0x0190 (6.2 to 6.3); 0x0198 |
DESKTOP *spdesk; |
3.10 to 3.51 | |
DESKTOP *rpdesk; |
4.0 and higher | |||
0x48 (3.51) |
DESKTOPINFO *pDeskInfo; |
3.51 only | next at 0x98 | |
0x40 (3.10); 0x4C (3.51); 0x90 (4.0) |
HDESK hdesk; |
3.10 to 4.0 | next at 0x60 | |
0x94 (4.0) |
ACCESS_MASK amdesk; |
4.0 only | next at 0xE0 | |
0x98 (4.0); 0x34 (5.0); 0x40 (5.1 to 6.0); 0xCC (6.1); 0xD8 (6.2 to 6.3); 0xDC |
0x90 (5.2 to 6.0); 0x0180 (6.1); 0x0198 (6.2 to 6.3); 0x01A0 |
DESKTOPINFO *pDeskInfo; |
4.0 and higher | previously at 0x48 |
0x44 (5.2 to 6.0); 0xD0 (6.1); 0xDC (6.2 to 6.3); 0xE0 |
0x98 (5.2 to 6.0); 0x0188 (6.1); 0x01A0 (6.2 to 6.3); 0x01A8 |
ULONG_PTR ulClientDelta; |
5.2 and higher | |
0x9C (4.0); 0x38 (5.0); 0x44 (5.1); 0x48 (5.2 to 6.0); 0xD4 (6.1); 0xE0 (6.2 to 6.3); 0xE4 |
0xA0 (5.2 to 6.0); 0x0190 (6.1); 0x01A8 (6.2 to 6.3); 0x01B0 |
CLIENTINFO *pClientInfo; |
4.0 and higher | |
0x44 (3.10); 0x50 (3.51); 0xA0 (4.0); 0x3C (5.0); 0x48 (5.1); 0x4C (5.2 to 6.0); 0xD8 (6.1); 0xE4 (6.2 to 6.3); 0xE8 |
0xA8 (5.2 to 6.0); 0x0198 (6.1); 0x01B0 (6.2 to 6.3); 0x01B8 |
ULONG TIF_flags; |
all | |
0x48 (3.10); 0x54 (3.51) |
DWORD idProcessClient; |
3.10 to 3.51 | ||
0x4C (3.10); 0x58 (3.51) |
DWORD idThreadClient; |
3.10 to 3.51 | ||
0x50 (3.10); 0x5C (3.51) |
DWORD idSequenceClient; |
3.10 to 3.51 | ||
0x54 (3.10); 0x60 (3.51) |
unknown thread ID | 3.10 to 3.51 | ||
0x58 (3.10); 0x64 (3.51); 0xA4 (4.0); 0x40 (5.0); 0x4C (5.1); 0x50 (5.2 to 6.0); 0xDC (6.1); 0xE8 (6.2 to 6.3); 0xEC |
0xB0 (5.2 to 6.0); 0x01A0 (6.1); 0x01B8 (6.2 to 6.3); 0x01C0 |
PWSTR pstrAppName; |
3.10 to 3.51 | |
UNICODE_STRING *pstrAppName; |
4.0 and higher | |||
0x5C (3.10); 0x68 (3.51) |
ULONG fsHooks; |
3.10 to 3.51 | next at 0x0104 | |
0x60 (3.10); 0x6C (3.51) |
HOOK *asphkStart [0x0D]; |
3.10 to 3.51 | next at 0x0108 | |
0x94 (3.10); 0xA0 (3.51) |
HOOK *sphkCurrent; |
3.10 to 3.51 | next at 0x0140 | |
0x98 (3.10); 0xA4 (3.51); 0xA8 (4.0); 0x44 (5.0); 0x50 (5.1); 0x54 (5.2 to 6.0); 0xE0 (6.1); 0xEC (6.2 to 6.3); 0xF0 |
0xB8 (5.2 to 6.0); 0x01A8 (6.1); 0x01C0 (6.2 to 6.3); 0x01C8 |
SMS *psmsSent; |
all | |
0x9C (3.10); 0xA8 (3.51); 0xAC (4.0); 0x48 (5.0); 0x54 (5.1); 0x58 (5.2 to 6.0); 0xE4 (6.1); 0xF0 (6.2 to 6.3); 0xF4 |
0xC0 (5.2 to 6.0); 0x01B0 (6.1); 0x01C8 (6.2 to 6.3); 0x01D0 |
SMS *psmsCurrent; |
all | |
0xA0 (3.10); 0xAC (3.51); 0xB0 (4.0); 0x4C (5.0); 0x58 (5.1); 0x5C (5.2 to 6.0); 0xE8 (6.1); 0xF4 (6.2 to 6.3); 0xF8 |
0xC8 (5.2 to 6.0); 0x01B8 (6.1); 0x01D0 (6.2 to 6.3); 0x01D8 |
SMS *psmsReceiveList; |
3.10 to 6.3 | |
unknown LIST_ENTRY | 10.0 and higher | |||
0x0100 | 0x01E8 | unknown dword | 10.0 and higher | |
0xA4 (3.10); 0xB0 (3.51) |
LONG_PTR ExtraInfo; |
3.10 to 3.51 | next in Q | |
0xA8 (3.10); 0xB4 (3.51 to 4.0); 0x50 (5.0); 0x5C (5.1); 0x60 (5.2 to 6.0); 0xEC (6.1); 0xF8 (6.2 to 6.3); 0x0104 |
0xD0 (5.2 to 6.0); 0x01C0 (6.1); 0x01D8 (6.2 to 6.3); 0x01EC |
LONG timeLast; |
all | |
0xAC (3.10); 0xB8 (3.51 to 4.0) |
POINT ptLast; |
3.10 to 4.0 | next at 0xB0 | |
0xB4 (3.10); 0xC0 (3.51 to 4.0); 0x54 (5.0); 0x60 (5.1); 0x64 (5.2 to 6.0); 0xF0 (6.1); 0xFC (6.2 to 6.3); 0x0108 |
0xD8 (5.2 to 6.0); 0x01C8 (6.1); 0x01E0 (6.2 to 6.3); 0x01F0 |
ULONG_PTR idLast; |
all | |
0xBC (3.10); 0xC8 (3.51); 0xC4 (4.0); 0x58 (5.0) |
INT cQuit; |
3.10 to 5.0 | next as 0x40000000 bit in TIF_flags | |
0xC0 (3.10); 0xCC (3.51); 0xC8 (4.0); 0x5C (5.0); 0x64 (5.1); 0x68 (5.2 to 6.0); 0xF4 (6.1); 0x0100 (6.2 to 6.3); 0x010C |
0xE0 (5.2 to 6.0); 0x01D0 (6.1); 0x01E8 (6.2 to 6.3); 0x01F8 |
INT exitCode; |
all | |
0x60 (5.0); 0x68 (5.1); 0x6C (5.2 to 6.0); 0xF8 (6.1); 0x0104 (6.2 to 6.3); 0x0110 |
0xE8 (5.2 to 6.0); 0x01D8 (6.1); 0x01F0 (6.2 to 6.3); 0x0200 |
HDESK hdesk; |
5.0 and higher | previously at 0x90 |
0xC4 (3.10); 0xD0 (3.51) |
unaccounted four bytes | 3.10 to 3.51 | ||
0xC8 (3.10); 0xD4 (3.51); 0xCC (4.0); 0x64 (5.0); 0x6C (5.1); 0x70 (5.2 to 6.0); 0xFC (6.1); 0x0108 (6.2 to 6.3); 0x0114 |
0xF0 (5.2 to 6.0); 0x01E0 (6.1); 0x01F8 (6.2 to 6.3); 0x0208 |
INT cPaintsReady; |
all | |
0xCC (3.10); 0xD8 (3.51); 0xD0 (4.0); 0x68 (5.0); 0x70 (5.1); 0x74 (5.2 to 6.0); 0x0100 (6.1); 0x010C (6.2 to 6.3); 0x0118 |
0xF4 (5.2 to 6.0); 0x01E4 (6.1); 0x01FC (6.2 to 6.3); 0x020C |
UINT cTimersReady; |
all | |
0xD0 (3.10); 0xDC (3.51); 0xD4 (4.0); 0x6C (5.0); 0x74 (5.1); 0x78 (5.2 to 6.0); 0x0104 (6.1); 0x0110 (6.2 to 6.3); 0x011C |
unknown MENUSTATE | 3.10 to 3.51 | ||
0xF8 (5.2 to 6.0); 0x01E8 (6.1); 0x0200 (6.2 to 6.3); 0x0210 |
MENUSTATE *pMenuState; |
4.0 and higher | ||
0x0108 (3.10); 0x0104 (3.51) |
<unknown-type> SBState; |
3.10 to 3.51 | ||
0x01B0 (3.10) | unknown MOVESIZEDATA | 3.10 only | ||
0x022C (3.10); 0x01B0 (3.51); 0xD8 (4.0); 0x70 (5.0); 0x78 (5.1) 0x7C (5.2 to 6.0); 0x0108 (6.1); 0x0114 (6.2 to 6.3); 0x0120 |
0x0100 (5.2 to 6.0); 0x01F0 (6.1); 0x0208 (6.2 to 6.3); 0x0218 |
union { TDB *ptdb; WINDOWSTATION *pwinsta; DESKTOP *pdeskClient; }; |
3.10 to 4.0 | |
union { TDB *ptdb; WINDOWSTATION *pwinsta; }; |
5.0 and higher | |||
0x0230 (3.10); 0x01B4 (3.51); 0xDC (4.0); 0x74 (5.0); 0x7C (5.1); 0x80 (5.2 to 6.0); 0x010C (6.1); 0x0118 (6.2 to 6.3); 0x0124 |
0x0108 (5.2 to 6.0); 0x01F8 (6.1); 0x0210 (6.2 to 6.3); 0x0220 |
SVR_INSTANCE_INFO *psiiList; |
all | |
0x0234 (3.10); 0x01B8 (3.51); 0xE0 (4.0); 0x78 (5.0); 0x80 (5.1); 0x84 (5.2 to 6.0); 0x0110 (6.1); 0x011C (6.2 to 6.3); 0x0128 |
0x0110 (5.2 to 6.0); 0x0200 (6.1); 0x0218 (6.2 to 6.3); 0x0228 |
DWORD dwExpWinVer; |
all | |
0x0120 (6.2 to 6.3); 0x012C |
0x021C (6.2 to 6.3); 0x022C |
DWORD dwManifestWinVer; |
6.2 and higher | |
0x0238 (3.10); 0x01BC (3.51); 0xE4 (4.0); 0x7C (5.0); 0x84 (5.1); 0x88 (5.2 to 6.0); 0x0114 (6.1); 0x0124 (6.2 to 6.3); 0x0130 |
0x0114 (5.2 to 6.0); 0x0204 (6.1); 0x0220 (6.2 to 6.3); 0x0230 |
union { DWORD dwCompatFlags; struct { /* bit fields, follow link */ }; }; |
all | |
0x023C (3.10) | unknown dword | 3.10 only | ||
0x80 (5.0); 0x88 (5.1); 0x8C (5.2 to 6.0); 0x0118 (6.1); 0x0128 (6.2 to 6.3); 0x0138 |
0x0118 (5.2 to 6.0); 0x0208 (6.1); 0x0228 (6.2 to 6.3); 0x0238 |
union { DWORD dwCompatFlags2; struct { /* bit fields, follow link */ }; }; |
5.0 to 6.0 | |
union { DWORD dwCompatFlags2; ULONGLONG qwCompatFlags2; struct { /* bit fields, follow link */ }; }; |
6.1 and higher | |||
0x01C0 (3.51); 0xE8 (4.0) |
UINT cWindows; |
3.51 to 4.0 | next at 0xE4 | |
0x0240 (3.10); 0x01C4 (3.51); 0xEC (4.0) |
UINT cVisWindows; |
3.10 to 4.0 | next at 0xE8 | |
0x0244 (3.10); 0x01C8 (3.51) |
ULONG hTaskWow; |
3.10 to 3.51 | next in TDB | |
0x0248 (3.10); 0x01CC (3.51) |
HANDLE hThreadClient; |
3.10 to 3.51 | ||
0x024C (3.10); 0x01D0 (3.51) |
HANDLE hThreadServer; |
3.10 to 3.51 | ||
0x0250 (3.10); 0x01D4 (3.51) |
<unknown-type> *pcsrt; |
3.10 to 3.51 | ||
0x0254 (3.10); 0x01D8 (3.51) |
TEB *pteb; |
3.10 to 3.51 | ||
0x0258 (3.10); 0x01DC (3.51); 0xF0 (4.0); 0x84 (5.0); 0x8C (5.1); 0x90 (5.2 to 6.0); 0x0120 (6.1); 0x0130 (6.2 to 6.3); 0x0140 |
0x0120 (5.2 to 6.0); 0x0210 (6.1); 0x0230 (6.2 to 6.3); 0x0240 |
Q *pqAttach; |
all | |
0x025C (3.10) | unknown dword | 3.10 only | ||
0x0260 (3.10); 0x01E0 (3.51); 0xF4 (4.0) |
INT iCursorLevel; |
3.10 to 4.0 | next at 0xAC | |
0x0264 (3.10); 0x01E4 (3.51) |
INT cSpins; |
3.10 to 3.51 | ||
0x0268 (3.10); 0x01E8 (3.51); 0xF8 (4.0) |
ULONG fsReserveKeys; |
4.0 only | next at 0xD8; last THREADINFO member in 3.10 |
|
0x01EC (3.51); 0xFC (4.0); 0x88 (5.0); 0x90 (5.1); 0x94 (5.2 to 6.0); 0x0124 (6.1); 0x0134 (6.2 to 6.3); 0x0144 |
0x0128 (5.2 to 6.0); 0x0218 (6.1); 0x0238 (6.2 to 6.3); 0x0248 |
THREADINFO *ptiSibling; |
3.51 and higher | |
0x01F0 (3.51); 0x0100 (4.0); 0x8C (5.0); 0x94 (5.1); 0x98 (5.2 to 6.0); 0x0128 (6.1); 0x0138 (6.2 to 6.3); 0x0148 |
0x0130 (5.2 to 6.0); 0x0220 (6.1); 0x0240 (6.2 to 6.3); 0x0250 |
MOVESIZEDATA *pmsd; |
3.51 and higher | |
0x01F4 (3.51) |
WOWTHREADINFO *pwti; |
3.51 only | next in TDB; last THREADINFO member in 3.51 |
|
0x0104 (4.0); 0x90 (5.0); 0x98 (5.1); 0x9C (5.2 to 6.0); 0x012C (6.1); 0x013C (6.2 to 6.3); 0x014C |
0x0138 (5.2 to 6.0); 0x0228 (6.1); 0x0248 (6.2 to 6.3); 0x0258 |
ULONG fsHooks; |
4.0 and higher | previously at 0x68 |
0x0108 (4.0) |
HOOK *asphkStart [0x0E]; |
early 4.0 only | previously at 0x6C | |
HOOK *asphkStart [0x10]; |
late 4.0 only | next at 0xEC | ||
0x0140 (early 4.0); 0x0148 (late 4.0); 0x94 (5.0); 0x9C (5.1); 0xA0 (5.2 to 6.0); 0x0130 (6.1); 0x0140 (6.2 to 6.3); 0x0150 |
0x0140 (5.2 to 6.0); 0x0230 (6.1); 0x0250 (6.2 to 6.3); 0x0260 |
HOOK *sphkCurrent; |
4.0 and higher | previoustly at 0xA0 |
0x0134 (6.1); 0x0144 (6.2 to 6.3); 0x0154 |
0x0238 (6.1); 0x0258 (6.2 to 6.3); 0x0268 |
LPARAM lParamHkCurrent; |
6.1 and higher | |
0x0138 (6.1); 0x0148 (6.2 to 6.3); 0x0158 |
0x0240 (6.1); 0x0260 (6.2 to 6.3); 0x0270 |
WPARAM wParamHkCurrent; |
6.1 and higher | |
0x0144 (early 4.0); 0x014C (late 4.0); 0x98 (5.0); 0xA0 (5.1); 0xA4 (5.2 to 6.0); 0x013C (6.1); 0x014C (6.2 to 6.3); 0x015C |
0x0148 (5.2 to 6.0); 0x0248 (6.1); 0x0268 (6.2 to 6.3); 0x0278 |
SBTRACK *pSBTrack; |
4.0 and higher | last THREADINFO member in 4.0 |
The unknown LIST_ENTRY elaborates psmsReceiveList from single-linked to double-linked. It seems likely that Microsoft changed the name, but to what is unknown. The unknown dword that follows counts the SMS structures in the list.
A thread has a ptdb or a pwinsta according to whether its TIF_16BIT (0x00000002) bit is set or clear in the TIF_flags.
The name dwManifestWinVer is proposed as a reasonable guess in the style of what it follows. The member is set by a routine that symbol files show to be named SetManifestWinVer.
There is, of course, one element in the aphkStart array for each possible hook, as set through the API function SetWindowsHookEx. The hooks are documented and it is well known that the numbering is not zero-based but instead starts at -1 (WH_MSGFILTER). Notwithstanding that a conditional block in Microsoft’s WINUSER.H would have it that WH_KEYBOARD_LL (0x0D) and WH_MOUSE_LL (0x0E) are defined for version 4.0 and higher, they are in fact rejected by the WIN32K.SYS from the original release of Windows NT 4.0. Indeed, look back through Microsoft’s documentation, even as recently as the Software Development Kit (SDK) for Windows 7, and it can be found that the low-level keyboard and mouse hooks require “version 4.0 SP3 or later.”
Most members that appear at the end of the THREADINFO in version 5.0 weren’t so much appended as just moved from earlier in the structure, in no particular order for no reason that I yet understand.
Offset (x86) | Offset (x64) | Definition | Versions | Remarks |
---|---|---|---|---|
0x9C (5.0); 0xA4 (5.1); 0xA8 (5.2 to 6.0); 0x0140 (6.1); 0x0150 (6.2 to 6.3); 0x0160 |
0x0150 (5.2 to 6.0); 0x0250 (6.1); 0x0270 (6.2 to 6.3); 0x0280 |
PVOID hEventQueueClient; |
5.0 and higher | previously at 0x80 |
0xA0 (5.0); 0xA8 (5.1); 0xAC (5.2 to 6.0); 0x0144 (6.1); 0x0154 (6.2 to 6.3); 0x0164 |
0x0158 (5.2 to 6.0); 0x0258 (6.1); 0x0278 (6.2 to 6.3); 0x0288 |
KEVENT *pEventQueueServer; |
5.0 and higher | previously at 0x84 |
0xA4 (5.0); 0xAC (5.1); 0xB0 (5.2 to 6.0); 0x0148 (6.1); 0x0158 (6.2 to 6.3); 0X0168 |
0x0160 (5.2 to 6.0); 0x0260 (6.1); 0x0280 (6.2 to 6.3); 0x0290 |
LIST_ENTRY PtiLink; |
5.0 and higher | previously at 0x38 |
0xAC (5.0); 0xB4 (5.1); 0xB8 (5.2 to 6.0); 0x0150 (6.1); 0x0160 (6.2 to 6.3); 0x0170 |
0x0170 (5.2 to 6.0); 0x0270 (6.1); 0x0290 (6.2 to 6.3); 0x02A0 |
INT iCursorLevel; |
5.0 and higher | previously at 0xF4 |
0xB0 (5.0); 0xB8 (5.1); 0xBC (5.2 to 6.0); 0x0154 (6.1); 0x0164 (6.2 to 6.3); 0x0174 |
0x0174 (5.2 to 6.0); 0x0274 (6.1); 0x0294 (6.2 to 6.3); 0x02A4 |
POINT ptLast; |
5.0 and higher | previously at 0xB8 |
0xC4 (6.0); 0x015C (6.1); 0x016C (6.2 to 6.3); 0x017C |
0x017C (6.0); 0x027C (6.1); 0x029C (6.2 to 6.3); 0x02AC |
POINT ptLastReal; |
6.0 and higher | |
0xB8 (5.0); 0xC0 (5.1); 0xC4 (5.2); 0xCC (6.0); 0x0164 (6.1); 0x0174 (6.2 to 6.3); 0x0184 |
0x0180 (5.2); 0x0188 (6.0); 0x0288 (6.1); 0x02A8 (6.2 to 6.3); 0x02B8 |
WND *spwndDefaultIme; |
5.0 and higher | |
0xBC (5.0); 0xC4 (5.1); 0xC8 (5.2); 0xD0 (6.0); 0x0168 (6.1); 0x0178 (6.2 to 6.3); 0x0188 |
0x0188 (5.2); 0x0190 (6.0); 0x0290 (6.1); 0x02B0 (6.2 to 6.3); 0x02C0 |
IMC *spDefaultImc; |
5.0 and higher | |
0xC0 (5.0); 0xC8 (5.1); 0xCC (5.2); 0xD4 (6.0); 0x016C (6.1); 0x017C (6.2 to 6.3); 0x018C |
0x0190 (5.2); 0x0198 (6.0); 0x0298 (6.1); 0x02B8 (6.2 to 6.3); 0x02C8 |
HKL hklPrev; |
5.0 and higher | |
0xC4 (5.0); 0xCC (5.1); 0xD0 (5.2); 0xD8 (6.0); 0x0170 (6.1); 0x0180 (6.2 to 6.3); 0x0190 |
0x0198 (5.2); 0x01A0 (6.0); 0x02A0 (6.1); 0x02C0 (6.2 to 6.3); 0x02D0 |
INT cEnterCount; |
5.0 and higher | previously at 0x4C |
0xC8 (5.0); 0xD0 (5.1); 0xD4 (5.2); 0xDC (6.0); 0x0174 (6.1); 0x0184 (6.2 to 6.3); 0x0194 |
0x01A0 (5.2); 0x01A8 (6.0); 0x02A8 (6.1); 0x02C8 (6.2 to 6.3); 0x02D8 |
MLIST mlPost; |
5.0 and higher | previously at 0x5C |
0xD4 (5.0); 0xDC (5.1); 0xE0 (5.2); 0xE8 (6.0); 0x0180 (6.1); 0x0194 (6.2 to 6.3); 0x01A4 |
0x01B8 (5.2); 0x01C0 (6.0); 0x02C0 (6.1); 0x02E0 (6.2 to 6.3); 0x02F0 |
USHORT fsChangeBitsRemoved; |
5.0 and higher | previously at 0x68 |
0xD6 (5.0); 0xDE (5.1); 0xE2 (5.2); 0xEA (6.0); 0x0182 (6.1); 0x0196 (6.2 to 6.3); 0x01A6 |
0x01BA (5.2); 0x01C2 (6.0); 0x02C2 (6.1); 0x02E2 (6.2 to 6.3); 0x02F2 |
WCHAR wchInjected; |
5.0 and higher | |
0xD8 (5.0); 0xE0 (5.1); 0xE4 (5.2); 0xEC (6.0); 0x0184 (6.1); 0x0198 (6.2 to 6.3); 0x01A8 |
0x01BC (5.2); 0x01C4 (6.0); 0x02C4 (6.1); 0x02E4 (6.2 to 6.3); 0x02F4 |
ULONG fsReserveKeys; |
5.0 and higher | previously at 0xF8 |
0xDC (5.0); 0xE4 (5.1); 0xE8 (5.2); 0xF0 (6.0); 0x0188 (6.1); 0x019C (6.2 to 6.3); 0x01AC |
0x01C0 (5.2); 0x01C8 (6.0); 0x02C8 (6.1); 0x02E8 (6.2 to 6.3); 0x02F8 |
KEVENT **apEvent; |
5.0 and higher | previously at 0x88 |
0xE0 (5.0); 0xE8 (5.1); 0xEC (5.2); 0xF4 (6.0); 0x018C (6.1); 0x01A0 (6.2 to 6.3); 0x01B0 |
0x01C8 (5.2); 0x01D0 (6.0); 0x02D0 (6.1); 0x02F0 (6.2 to 6.3); 0x0300 |
ACCESS_MASK amdesk; |
5.0 and higher | previously at 0x94 |
0xE4 (5.0); 0xEC (5.1); 0xF0 (5.2); 0xF8 (6.0); 0x0190 (6.1); 0x01A4 (6.2 to 6.3); 0x01B4 |
0x01CC (5.2); 0x01D4 (6.0); 0x02D4 (6.1); 0x02F4 (6.2 to 6.3); 0x0304 |
UINT cWindows; |
5.0 and higher | previously at 0xE8 |
0xE8 (5.0); 0xF0 (5.1); 0xF4 (5.2); 0xFC (6.0); 0x0194 (6.1); 0x01A8 (6.2 to 6.3); 0x01B8 |
0x01D0 (5.2); 0x01D8 (6.0); 0x02D8 (6.1); 0x02F8 (6.2 to 6.3); 0x0308 |
UINT cVisWindows; |
5.0 and higher | previously at 0xEC |
0xEC (5.0); 0xF4 (5.1); 0xF8 (5.2); 0x0100 (6.0); 0x0198 (6.1); 0x01AC (6.2 to 6.3); 0x01BC |
0x01D8 (5.2); 0x01E0 (6.0); 0x02E0 (6.1); 0x0300 (6.2 to 6.3); 0x0310 |
HOOK *aphkStart [0x10]; |
5.0 and higher | previously at 0x0108 |
0x012C (5.0); 0x0134 (5.1); 0x0138 (5.2); 0x0140 (6.0); 0x01D8 (6.1); 0x01EC (6.2 to 6.3); 0x01FC |
0x0258 (5.2); 0x0260 (6.0); 0x0360 (6.1); 0x0380 (6.2 to 6.3); 0x0390 |
CLIENTTHREADINFO cti; |
5.0 and higher | previously at 0x70; last THREADINFO member in 5.0 |
It is immediately after the cti member that offsets in type information from symbol files for Windows 7 start to go wrong. These symbol files have the CLIENTTHREADINFO as 0x10 bytes in both 32-bit and 64-bit Windows, but for the structure as actually used by WIN32K this size has not been correct since Windows XP added a dword. How the symbol files get built with only a partial CLIENTTHREADINFO is not known. The consequence for the next few THREADINFO members is that offsets that are read mechanically from the Windows 7 symbol files, e.g., for presentation on the Internet as supposedly worthwhile research, are off by four or eight bytes in 32-bit and 64-bit Windows respectively.
Offset (x86) | Offset (x64) | Definition | Versions | Remarks |
---|---|---|---|---|
0x0148 (5.1); 0x014C (5.2); 0x0154 (6.0); 0x01EC (6.1); 0x0200 (6.2 to 6.3); 0x0210 |
0x0270 (5.2); 0x0278 (6.0); 0x0378 (6.1); 0x0398 (6.2 to 6.3); 0x03A8 |
PVOID hPrevHidData; |
5.1 and higher | last THREADINFO member in 5.1; last THREADINFO member in 5.2; 0x01E8 and 0x0370 in 6.1 according to symbol files |
0x01F0 (6.1); 0x0204 (6.2 to 6.3); 0x0214 |
0x0380 (6.1); 0x03A0 (6.2 to 6.3); 0x03B0 |
HTOUCHINPUT hTouchInputCurrent; |
6.1 and higher | 0x01EC and 0x0378 in 6.1 according to symbol files |
0x01F4 (6.1); 0x0208 (6.2 to 6.3); 0x0218 |
0x0388 (6.1); 0x03A8 (6.2 to 6.3); 0x03B8 |
HGESTUREINFO hGestureInfoCurrent; |
6.1 and higher | 0x01F0 and 0x0380 in 6.1 according to symbol files |
0x01F8 (6.1) | 0x0390 (6.1) |
MSGPPINFO MsgPPInfo; |
6.1 only | 0x01F4 and 0x0388 in 6.1 according to symbol files; next at 0x024C and 0x0424 |
0x020C (6.2 to 6.3); 0x021C |
0x03B0 (6.2 to 6.3); 0x03C0 |
unknown THREADINPUTPOINTERLIST | 6.2 and higher | |
0x0158 (6.0); 0x0200 (6.1); 0x0224 (6.2 to 6.3); 0x0234 |
0x0280 (6.0); 0x0398 (6.1); 0x03D8 (6.2 to 6.3); 0x03E8 |
unknown INPUTHANGINFO | 6.0 and higher | not present in 6.1 according to symbol files; last THREADINFO member in 6.0 |
0x020C (6.1); 0x023C (6.2 to 6.3); 0x024C |
0x03B0 (6.1); 0x0408 (6.2 to 6.3); 0x0418 |
UINT cNestedStableVisRgn; |
6.1 and higher | 0x01F8 and 0x038C in 6.1 according to symbol files |
0x0210 (6.1); 0x0240 (6.2 to 6.3); 0x0250 |
0x03B8 (6.1); 0x0410 (6.2 to 6.3); 0x0420 |
LIST_ENTRY readyHead; |
6.1 and higher | 0x01FC and 0x0390 in 6.1 according to symbol files |
0x0218 (6.1); 0x0248 (6.2 to 6.3); 0x0258 |
0x03C8 (6.1); 0x0420 (6.2 to 6.3); 0x0430 |
union { struct { /* bit fields, follow link */ }; ULONG ulThreadFlags2; }; |
6.1 and higher | 0x0204 and 0x03A0 in 6.1 according to symbol files; last THREADINFO member in 6.1 |
Microsoft’s name THREADINPUTINFOLIST (formally tagTHREADINPUTINFOLIST) for the structure that first appears in version 6.2 at offsets 0x020C and 0x03B0 is known from symbol files, specifically from the names of routines that are written in C++ and take the structure’s address among their arguments. The structure begins with a LIST_ENTRY that links structures whose name is similarly known to be THREADPOINTERDATA (formally tagTHREADPOINTERDATA). Microsoft’s names for these structures’ members are not known.
The MsgPPInfo member is accessed as eight bytes in both 32-bit and 64-bit Windows, yet symbol files for Windows 7 have the MSGPPINFO structure as four bytes in both 32-bit and 64-bit Windows. It is here supposed that the symbol files must be wrong about the MSGPPINFO structure, the alternative being that they’re wrong even about the existence of a MsgPPInfo member (there being no other space for it).
The structure that first appears in version 6.0 at offsets 0x0158 and 0x0280 is operated on by routines that symbol files name as AddUpdateHangInfo, DestroyUpdateHangInfo, etc, and since symbol files for Windows 8.1 (but not Windows 8 or Windows 10) have C++ decorations for these routines Microsoft’s name for the structure is nowadays known to be INPUTHANGINFO (formally tagINPUTHANGINFO). The structure in the THREADINFO itself is the head of a list. The head is for the thread itself. Others are for the thread’s windows. This is where the timeout for hung applications is tested—and it is hard-coded to 5 seconds in version 6.0. Microsoft’s names for the THREADINFO member or for the INPUTHANGINFO members are not known. How the member gets missed in the type information from the symbol files for Windows 7 is not known. Note especially that it cannot be that the symbol files as published are somehow out of date: this INPUTHANGINFO was no last-minute addition during development of Windows 7 but has existed since Windows Vista.
Before version 6.1, timers for all threads go into one list. Version 6.1 has a global list too but improves on it by putting each timer into both the global list and the new per-thread list. The name readyHead from the suspect symbol files is consistent with the cTimersReady counter that is the whole per-thread tracking of timers in earlier versions.
Microsoft’s names for members that have been added to the THREADINFO since Windows 7 may never be known. On the plus side, if only for neatness of presentation, new members have mostly been added simply by appending.
Offset (x86) | Offset (x64) | Definition | Versions | Remarks |
---|---|---|---|---|
0x024C (6.2 to 6.3); 0x025C |
0x0424 (6.2 to 6.3); 0x0434 |
MSGPPINFO MsgPPInfo; |
6.2 and higher | previously at 0x01F8 and 0x0390 |
0x0254 (6.2 to 6.3); 0x0264 |
0x042C (6.2 to 6.3); 0x043C |
unknown byte | 6.2 and higher | |
0x0258 (6.2 to 6.3); 0x0268 |
0x0430 (6.2 to 6.3); 0x0440 |
unknown pointer | 6.2 and higher | |
0x025C (6.2 to 6.3); 0x026C |
0x0438 (6.2 to 6.3); 0x0448 |
unknown pointer | 6.2 and higher | |
0x0260 (6.2 to 6.3); 0x0270 |
0x0440 (6.2 to 6.3); 0x0450 |
unknown dword (counter) | 6.2 and higher | |
0x0264 (6.2 to 6.3); 0x0274 |
0x0448 (6.2 to 6.3); 0x0458 |
unknown pointer | 6.2 and higher | |
0x0268 (6.3); 0x0278 |
0x0450 (6.3); 0x0460 |
unknown dword | 6.3 and higher | |
0x0268 (6.2); 0x026C (6.3); 0x027C |
0x0450 (6.2); 0x0454 (6.3); 0x0464 |
unknown POINT | 6.2 and higher | |
0x0270 (6.2); 0x0274 (6.3); 0x0284 |
0x0458 (6.2); 0x0460 (6.3); 0x0470 |
unknown LIST_ENTRY | 6.2 and higher | last THREADINFO member in 6.2 |
The unknown LIST_ENTRY is presumed to remain defined for version 10.0 though its use seems to have been discontinued.
Offset (x86) | Offset (x64) | Definition | Versions | Remarks |
---|---|---|---|---|
0x027C (6.3); 0x028C |
0x0470 (6.3); 0x0480 |
unknown dword | 6.3 and higher | |
0x0280 (6.3); 0x0290 |
0x0474 (6.3); 0x0484 |
unknown dword | 6.3 and higher | |
0x0284 (6.3); 0x0294 |
0x0478 (6.3); 0x0488 |
unknown MSGPPINFO | 6.3 and higher | |
0x028C (6.3); 0x029C |
0x0480 (6.3); 0x0490 |
unknown pointer | 6.3 and higher | |
0x0290 (6.3); 0x02A0 |
0x0488 (6.3); 0x0498 |
unknown dword | 6.3 and higher | last THREADINFO member in 6.3 |
Offset (x86) | Offset (x64) | Definition | Versions | Remarks |
---|---|---|---|---|
0x02A4 | 0x04A0 | unaccounted | 10.0 and higher | |
0x02A8 | 0x04A8 | unknown eight bytes | 10.0 and higher | |
0x02B0 | 0x04B0 | unknown eight bytes | 10.0 and higher | |
0x02B8 | 0x04B8 | unknown pointer | 10.0 and higher | |
0x02BC | 0x04C0 | unknown KEVENT pointer | 10.0 and higher | |
0x02C0 | 0x04C8 | unknown WND pointer | 10.0 and higher | |
0x02C4 | 0x04D0 | unknown pointer | 10.0 and higher | |
0x02C8 | 0x04D8 | unknown dword | 10.0 and higher | |
0x02CC | 0x04DC | unknown dword | 10.0 and higher | last THREADINFO member in 10.0 |