Geoff Chappell, Software Analyst
The CSR_API_MSG structure is a container for input and output (mostly but not only) to the API routines of server DLLs in the CSRSS.EXE process. The ordinary means—indeed, in version 4.0 and higher, the only means—of communication is a Local Procedure Call (LPC) through a port. Parameters for the call are marshalled into messages. The CSR_API_MSG is what the server receives. It has a system-defined PORT_MESSAGE header and some allowance for message data whose interpretation is up to the API routine.
The CSR_API_MSG 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_API_MSG is in public symbol files for CSRSS.EXE in Windows Vista only. 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 debugger extension from the DDK for Windows 2000.
Being exchanged between multiple components, albeit all written by Microsoft, the CSR_API_MSG is better not to change much. Indeed, the only change in the whole history is a recurring increase in how large may be that part whose interpretation is specific to each API routine. The following changes of size therefore suggest more variability than there arguably is:
Version | Size (x86) | Size (x64) |
---|---|---|
3.10 to 4.0 | 0xA0 | |
5.0 | 0xA8 | |
5.1 to 5.2 | 0xC8 | 0x0178 |
6.0 to 10.0 | 0xE0 | 0x01B0 |
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 versions 3.51 and 6.0. 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 |
---|---|---|---|
0x00 | 0x00 |
PORT_MESSAGE h; |
all |
0x18 | 0x28 |
union { CSR_API_CONNECTINFO ConnectionRequest; struct { /* individual members, see below */ }; }; |
all |
The kernel’s support for ports requires that the message for connecting through a port is a system-defined PORT_MESSAGE followed immediately by port-specific data whose interpretation is up to the server. Before version 6.0, when CSRSRV changed from using NtCreatePort to NtAlpcCreatePort, the size to expect for this connection information is told to the kernel when the port is created. The ConnectionRequest is this data for connecting through the API port. The unnamed structure in union with the ConnectionRequest is similarly for interpretation by the server but for distributing to API routines that get called through the port once connected:
Offset (x86) | Offset (x64) | Definition | Versions |
---|---|---|---|
0x18 | 0x28 |
CSR_CAPTURE_HEADER *CaptureBuffer; |
all |
0x1C | 0x30 |
ULONG ApiNumber; |
all |
0x20 | 0x34 |
ULONG ReturnValue; |
all |
0x24 | 0x38 |
ULONG Reserved; |
all |
0x28 | 0x40 |
union { /* changing members, see below */ } u; |
all |
The ApiNumber must be meaningful on input. Its high word is the 0-based index of the server DLL. The low word selects from this server DLL’s API routines (which can be numbered from a base other than zero).
The union u has zero or more bytes of data whose interpretation is specific to the selected API routine:
Offset (x86) | Offset (x64) | Definition | Versions |
---|---|---|---|
0x28 | 0x40 |
CSR_NULLAPICALL_MSG NullApiCall; |
3.10 to 4.0 |
0x28 | 0x40 |
CSR_CLIENTCONNECT_MSG ClientConnect; |
all |
0x28 | 0x40 |
CSR_THREADCONNECT_MSG ThreadConnect; |
3.10 to 5.1 |
0x28 | 0x40 |
CSR_PROFILE_CONTROL_MSG ProfileControl; |
3.10 to 5.1 |
0x28 | 0x40 |
CSR_IDENTIFY_ALERTABLE_MSG IndentifyAlertable; |
3.10 to 5.1 |
0x28 | 0x40 |
CSR_SETPRIORITY_CLASS_MSG PriorityClass; |
3.10 to 5.1 |
0x28 | 0x40 |
ULONG ApiMessageData [0x1E]; |
3.10 to 4.0 |
ULONG ApiMessageData [0x20]; |
5.0 only | ||
ULONG_PTR ApiMessageData [0x27]; |
5.1 to 5.2 | ||
ULONG_PTR ApiMessageData [0x2E]; |
6.0 and higher |
The six special cases of this API message data are for the API routines in CSRSRV itself. They are arranged in increasing order of ApiNumber, starting with zero. CSRSRV trivially fails the messages for ThreadConnect and ProfileControl in version 4.0 and higher, and for ProfileControl and IndentifyAlertable in version 5.2 and higher. In contrast, version 5.0 removes all support for NullApiCall (and renumbers the API routines). By the way, the spelling of IndentifyAlertable is Microsoft’s.
The CSR_API_MSG in the x86 builds of versions 5.1 to 5.2 has enough space for the ApiMessageData to have 0x28 elements. It is here thought that the last of these is unlabelled padding created by the structure’s 8-byte alignment (picked up from the PORT_MESSAGE), with the merit of matching the x64 implementation which has space for only 0x27.