Geoff Chappell, Software Analyst
The CSR_THREAD structure is what CSRSRV.DLL and the various server DLLs in the CSRSS.EXE server process use for representing a client thread.
The CSR_THREAD structure is not documented. Neither is Microsoft known to have disclosed a C-language definition in any header from any publicly available kit for any sort of software development.
Type information for the CSR_THREAD is in public symbol files for CSRSS.EXE starting with Windows Vista. Earlier type information is known in a statically linked library, named GDISRVL.LIB, which Microsoft published with the Device Driver Kit (DDK) for Windows NT 3.51.
Members, but not types, are also listed by the !dso command as implemented in the USEREXTS and USERKDX debugger extensions from the DDK for Windows 2000.
Considering how little of anything to do with CSRSS is documented, the CSR_THREAD is surprisingly stable. Members are rearranged in the early versions and then a substantial withdrawal of thread-level functionality from CSRSS in and after version 4.0 saw the CSR_THREAD shrink, but the only change since has been one member’s removal. The following changes of size are known:
Version | Size (x86) | Size (x64) |
---|---|---|
3.10 | 0xA0 | |
3.51 | 0x70 | |
4.0 | 0x48 | |
5.0 to 6.0 | 0x38 | 0x60 |
6.1 to 10.0 | 0x38 | 0x58 |
These sizes and the names and types in the table that follows are from type information in public symbol files (or such as would ordinarily be in public symbol files) for version 3.51 as an isolated case and for version 6.0 and higher. What’s known of Microsoft’s names and types for other versions is something of a guess, being inferred from what use CSRSRV is seen to make of the structure. 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.
Offset (x86) | Offset (x64) | Definition | Versions | Remarks |
---|---|---|---|---|
0x00 (3.10) | unaccounted four bytes | 3.10 only | ||
0x00 | 0x00 |
LARGE_INTEGER CreateTime; |
3.51 and higher | previously at 0x30 |
0x04 (3.10); 0x08 |
0x08 |
LIST_ENTRY Link; |
all | |
0x10 | 0x18 |
LIST_ENTRY HashLinks; |
3.51 and higher | previously at 0x28 |
0x18 | 0x28 |
CLIENT_ID ClientId; |
3.51 and higher | previously at 0x14 |
0x0C (3.10); 0x20 |
0x38 |
CSR_PROCESS *Process; |
3.10 and higher | |
0x10 (3.10); 0x24 (3.51 to 6.0) |
0x40 (before 6.1) |
CSR_WAIT_BLOCK *WaitBlock; |
3.10 to 6.0 | |
0x14 (3.10) |
CLIENT_ID ClientId; |
3.10 only | next at 0x18 | |
0x1C (3.10); 0x28 (3.51 to 6.0); 0x24 |
0x48 (before 6.1); 0x40 |
HANDLE ThreadHandle; |
3.10 to 6.1 | |
0x20 (3.10); 0x2C (3.51 to 6.0); 0x28 |
0x50 (before 6.1); 0x48 |
ULONG Flags; |
all | |
0x24 (3.10); 0x30 (3.51 to 6.0); 0x2C |
0x54 (before 6.1); 0x4C |
ULONG ReferenceCount; |
all | |
0x28 (3.10) |
LIST_ENTRY HashLinks; |
3.10 only | next at 0x10 | |
0x30 (3.10) |
LARGE_INTEGER CreateTime; |
3.10 only | next at 0x00 | |
0x38 (3.10); 0x34 |
NTSTATUS ShutDownStatus; |
3.51 | ||
0x3C (3.10) | unaccounted four bytes | 3.10 only | ||
0x40 (3.10); 0x38 |
PVOID ServerId; |
3.51 | ||
0x3C |
PVOID ServerThread; |
3.51 | ||
0x44 (3.10) | unaccounted eight bytes | 3.10 only | ||
0x4C (3.10) |
ULONG ImpersonateCount; |
3.10 only | next at 0x60 | |
0x50 (3.10) | unaccounted 0x24 bytes | 3.10 only | ||
0x74 (3.10) |
BOOLEAN ThreadConnected; |
3.10 only | next at 0x64 | |
0x78 (3.10); 0x40 (3.51) |
HANDLE ClientEventPairHandle; |
3.10 to 3.51 | ||
0x7C (3.10); 0x44 (3.51) |
HANDLE ClientSectionHandle; |
3.10 to 3.51 | ||
0x80 (3.10); 0x48 (3.51) |
CHAR *ClientSharedMemoryBase; |
3.10 to 3.51 | ||
0x84 (3.10); 0x4C (3.51) |
HANDLE ServerEventPairHandle; |
3.10 to 3.51 | ||
0x88 (3.10); 0x50 (3.51) |
HANDLE ServerSectionHandle; |
3.10 to 3.51 | ||
0x8C (3.10); 0x54 (3.51) |
HANDLE ServerThreadHandle; |
3.10 to 3.51 | ||
0x90 (3.10); 0x58 (3.51) |
CHAR *ServerSharedMemoryBase; |
3.10 to 3.51 | ||
0x94 (3.10); 0x5C (3.51) |
ULONG SharedMemorySize; |
3.10 to 3.51 | ||
0x60 (3.51); 0x34 (4.0 to 6.0); 0x30 |
0x58 (before 6.1); 0x50 |
ULONG ImpersonateCount; |
3.51 to 6.1 | previously at 0x4C |
0x64 (3.51) |
BOOLEAN ThreadConnected; |
3.51 only | previously at 0x74 | |
0x65 (3.51) |
BOOLEAN Dying; |
3.51 only | ||
0x38 (4.0) | unaccounted eight bytes | 4.0 only | ||
0x9C (3.10); 0x68 (3.51); 0x40 (4.0) |
PVOID ServerDllPerThreadData [1]; |
3.10 to 4.0 |
No use is known of the Dying member even in the version for which type information shows it as defined.
Up to and including version 4.0, the CSR_THREAD is built in a memory block that continues with:
A server DLL requests per-thread space for all future processes by setting the wanted amount into the PerThreadDataLength member of the CSR_SERVER_DLL during initialisation. Each server DLL’s allowance is aligned up to 4 bytes in version 3.10 but 8 bytes in later versions. Each ServerDllPerThreadData element points to the allowance for the corresponding server DLL (or is NULL if the server DLL has no per-thread space).