CSR_SERVER_DLL

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.

Availability

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.

Documentation Status

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.

Variability

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

Layout

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: