Geoff Chappell, Software Analyst
The CSR_SERVER_DLL structure is the main record that CSRSRV.DLL keeps of the various DLLs that are loaded in the CSRSS.EXE process to act as servers to other processes. CSRSRV is itself one of these server DLLs. Others are learnt from the ServerDLL arguments on the CSRSS command line.
Much as services can be packaged together in one executable file, so may the CSRSS server DLLs be in the one DLL file. Such server DLLs each have their own initialisation routine which the DLL file must export by name. The default name is ServerDllInitialization. Any other can be given in the ServerDLL argument. Microsoft is known to have the type definition
typedef NTSTATUS (*PCSR_SERVER_DLL_INIT_ROUTINE) (CSR_SERVER_DLL *);
for a pointer to a server DLL’s initialisation routine. Some of the CSR_SERVER_DLL is filled in before this call. Most is to be filled in by the server DLL. Thus is the CSR_SERVER_DLL not just an internal record for CSRSRV’s own use but is also the way that CSRSRV learns what a server DLL is capable of and how to call it.
Server DLLs are essential CSRSS functionality in all known versions of Windows, i.e., from as far back as version 3.10 up to and including the original release of Windows 10, which is the last that is yet inspected for this note.
Prominent examples of server DLLs through the whole history of Windows are BASESRV.DLL and the two or three that are packaged into WINSRV.DLL. Versions 3.10 to 4.0 allow as many as 16 server DLLs. Version 5.0 reduced the allowance to four, but new server DLLs for Windows 7 and (and perhaps anticipated for) Windows 8 saw the limit raised to five and then six.
The CSR_SERVER_DLL is not documented. Considering that the CSR_SERVER_DLL is shared between modules, rather than being internal to just one, Microsoft has been unusually careful about publishing the structure’s name, let alone any details about its members. Knowledge of the CSR_SERVER_DLL would be essential to any authorship of a CSRSS server DLL, and Microsoft presumably does not want that any third-party server DLLs should ever exist.
From this perspective, it is no surprise that Microsoft is not known to have disclosed a C-language definition of the CSR_SERVER_DLL in any header from any publicly available kit for any sort of software development. It is perhaps also no surprise that when type information for other CSRSS structures started appearing in public symbol files for CSRSS in Windows Vista, CSR_SERVER_DLL was omitted. Microsoft’s only known public release of type information for the CSR_SERVER_DLL structure is not in any symbol file but is instead in a statically linked library, named GDISRVL.LIB, that was published with the Device Driver Kit (DDK) for Windows NT 3.51. That type information surives in this library—especially since it has the detail of what would ordinarily be called private symbols—surely was an oversight, but published it is.
The CSR_SERVER_DLL has tended to shrink as functionality has been withdrawn from CSRSS and server DLLs have less to do (even if recent versions have found more reasons to do it). The following changes of size are known:
Version | Size (x86) | Size (x64) |
---|---|---|
3.10 | 0x60 | |
3.51 to 4.0 | 0x64 | |
5.0 to 5.1 | 0x4C | |
5.2 to 10.0 | 0x44 | 0x78 |
The sizes in the preceding table and the names and types in the table that follows are based on type information such as debuggers read from symbol files. As noted above, this means version 3.51 only. What’s known of Microsoft’s names and types for other versions is something of a guess, being inferred from inspecting different versions of CSRSRV for what use they make of the structure and assuming that continuity of use speaks strongly for continuity of names and types.
Offset (x86) | Offset (x64) | Definition | Versions | Remarks |
---|---|---|---|---|
0x00 (3.10 to 6.0) | 0x00 (before 6.1) |
ULONG Length; |
3.10 to 6.0 | input |
0x04 (3.10 to 5.1) |
HANDLE CsrInitializationEvent; |
3.10 to 5.1 | input | |
0x08 (3.10 to 5.1); 0x04 (5.2 to 6.0); 0x00 |
0x08 (before 6.1); 0x00 |
ANSI_STRING ModuleName; |
all | input |
0x10 (3.10 to 5.1); 0x0C (5.2 to 6.0); 0x08 |
0x18 (before 6.1); 0x10 |
HMODULE ModuleHandle; |
all | input |
0x14 (3.10 to 5.1); 0x10 (5.2 to 6.0); 0x0C |
0x20 (before 6.1); 0x18 |
ULONG ServerDllIndex; |
all | input |
0x18 (3.10 to 5.1); 0x14 (5.2 to 6.0); 0x10 |
0x24 (before 6.1); 0x1C |
ULONG ServerDllConnectInfoLength; |
all | |
0x1C (3.10 to 5.1); 0x18 (5.2 to 6.0); 0x14 |
0x28 (before 6.1); 0x20 |
ULONG ApiNumberBase; |
all | output |
0x20 (3.10 to 5.1); 0x1C (5.2 to 6.0); 0x18 |
0x2C (before 6.1); 0x24 |
ULONG MaxApiNumber; |
all | output |
0x24 (3.10 to 5.1); 0x20 (5.2 to 6.0); 0x1C |
0x30 (before 6.1); 0x28 |
PCSR_API_ROUTINE *ApiDispatchTable; |
3.10 only | output |
union { PCSR_API_ROUTINE *ApiDispatchTable; PCSR_1P_API_ROUTINE *QuickApiDispatchTable; }; |
3.51 only | |||
PCSR_API_ROUTINE *ApiDispatchTable; |
4.0 and higher | |||
0x28 (3.10 to 5.1); 0x24 (5.2 to 6.0); 0x20 |
0x38 (before 6.1); 0x30 |
BOOLEAN *ApiServerValidTable; |
all | output |
0x2C (3.10 to 5.1) |
PSTR *ApiNameTable; |
3.10 to 5.1 | ||
0x24 | 0x38 | unaccounted four or eight bytes | 6.1 and higher | |
0x30 (3.10 to 5.1); 0x28 |
0x40 |
ULONG PerProcessDataLength; |
all | output |
0x34 3.10 to 4.0) |
ULONG PerThreadDataLength; |
3.10 to 4.0 | output | |
0x38 (3.10 to 4.0); 0x34 (5.0 to 5.1); 0x2C |
0x48 |
LONG (*ConnectRoutine) ( CSR_PROCESS *, PVOID, ULONG *); |
all | output |
0x3C (3.10 to 4.0); 0x38 (5.0 to 5.1); 0x30 |
0x50 |
VOID (*DisconnectRoutine) (CSR_PROCESS *); |
all | output |
0x40 (3.10 to 4.0) |
LONG (*AddThreadRoutine) (CSR_THREAD *); |
3.10 to 4.0 | output | |
0x44 (3.10 to 4.0) |
LONG (*DeleteThreadRoutine) (CSR_THREAD *); |
3.10 to 4.0 | output | |
0x48 (3.10 to 4.0) |
LONG (*InitThreadRoutine) (VOID); |
3.10 to 4.0 | output | |
0x4C (3.10 to 4.0) |
VOID (*ExceptionRoutine) ( EXCEPTION_POINTERS *, BOOLEAN); |
3.10 to 4.0 | output | |
0x50 (3.10 to 4.0); 0x3C (5.0 to 5.1); 0x34 |
0x58 |
VOID (*HardErrorRoutine) ( CSR_THREAD *, HARDERROR_MSG *); |
all | output |
0x54 (3.10 to 4.0); 0x40 (5.0 to 5.1); 0x38 |
0x60 |
PVOID SharedStaticServerData; |
all | input output |
0x58 (3.10 to 4.0); 0x44 (5.0 to 5.1); 0x3C |
0x68 |
LONG (*AddProcessRoutine) ( CSR_PROCESS *, CSR_PROCESS *); |
all | output |
0x5C (3.10 to 4.0); 0x48 (5.0 to 5.1); 0x40 |
0x70 |
ULONG (*ShutdownProcessRoutine) ( CSR_PROCESS *, ULONG, UCHAR); |
all | output |
0x60 (3.51 to 4.0) |
ULONG (*ApiDispatchRoutine) ( CSR_API_MSG *, ULONG); |
3.51 to 4.0 | output |
To ease the reading of pointers to functions within other types, the preceding table uses the following type definitions from the known symbol file:
typedef ULONG (*PCSR_API_ROUTINE) (CSR_API_MSG *, CSR_REPLY_STATUS *); typedef ULONG (*PCSR_1P_API_ROUTINE) (CSR_API_MSG *);
The symbol file also has type definitions for the many other members that are function pointers: