Windows CSRSS cross-version API Table

It seems like half a year has passed since I published the Win32k.SYS system call table list on the net. During this time (well, it didn’t take so long ;)) I managed to gather enough information to release yet another API list – this time, concerning an user-mode application – CSRSS (Client/Server Runtime SubSystem). As a relatively common research subject, I think a table of this kind can make things easier for lots of people.

Before presenting the table itself, I would like to gently introduce the mechanism in consideration to the reader. As the name itself states, CSRSS is a part of the Windows Environment Subsystem, running in user-mode. It is a single process (having the highest possible – SYSTEM – privileges), which mostly takes advantage of three dynamic libraries – basesrv.dll, csrsrv.dll and winsrv.dll. These files provide support for certain parts of the subsystem functionality, such as:

  • Updating the list of processes / threads running on the system
  • Handling the Console Window (i.e. special text-mode window) events
  • Implementing parts of the Virtual DOS Machine support
  • Supplying miscellaneous functions, such as ExitWindowsEx

Every Windows process running on the system does (or, at least, should) have an open connection with CSRSS, through the LPC / ALPC mechanism (depending on the system version) – which in turn stands for (Advanced) Local Procedure Calls. The ntdll.dll module provides multiple functions dedicated to the data exchange between user processes and CSRSS. Some of the examplary, exported names include, but are not limited to:

  • CsrClientConnectToServer
  • CsrGetProcessId
  • CsrClientCallServer
  • CsrAllocateMessageBuffer

Out of all the Csr~ wrapper functions, CsrClientCallServer is the most commonly used. One can find it’s references in kernel32.CreateProcess, kernel32.AllocConsole, kernel32.FreeConsole, user32.EndTask and tens of other documented API functions. At a closer look, it is easy to notice that each time a call is made to CsrClientCallServer, an unique number is pushed on the stack, differing from routine to routine. An example code snippet follows:

.text:77E96D55           push    4
.text:77E96D57           push    20225h <---------- HERE
.text:77E96D5C           mov     [ebp+var_7C], eax
.text:77E96D5F           push    0
.text:77E96D61           lea     eax, [ebp+var_A4]
.text:77E96D67           push    eax
.text:77E96D68           call    ds:__imp__CsrClientCallServer@16 ; CsrClientCallServer(x,x,x,x)

As it turns out, these numbers are in fact indexes into special function pointer tables defined by the aforementioned libraries used by CSRSS. More specifically, a special routine – internally called CsrApiRequestThread – running in the context of a separate csrss.exe thread, is responsible for receiving user requests (that is – the CsrApi ID value together with the input buffer), handling it through  appropriate dispatch tables, and returning the results. This scheme is slightly different on Windows 7, but the general idea remains the same.

In order to give the reader a better view of how many and what functions are supported on a specific OS version, as well as make cross-version comparisons easier, I’ve created two versions of the CsrAPI table:

  1. A complete list of the functions present in the dispatch tables for most likely every NT-series system can be found @
  2. A cross-version compatibility table, for the same system version set can be found @

I have done my best to make sure that the presented materials are correct and up-to-date. If, however, a mistake of any kinds is noticed, please let me know about this fact asap ;) It is possible that I will manage to fill the red-green table with corresponding api-numbers soon – I cannot guarantee this, though.

From this point, I would like to thank all people who showed their interest and helped my with this tiny project – thank You! Also, please drop me a line on whether you like the idea or not ;-)


11 thoughts on “Windows CSRSS cross-version API Table”

  1. @Ivanlef0u: wow, that’s an interesting subject..

    Now the question is, whether LPC is translated into “Local Procedure Calls” or “Local Inter-Process Communication”.

    When we assume the first option, than ALPC does stand for Advanced LPC, as stated in numerous sources: and

    If, however, the latter option is considered correct, other authors confirm the “Asynchronous” version:

    The thing is – am I the one confused here, or is the (A)LPC naming scheme a common problem out there?

  2. Haha no the name it’s not very important here. Actually i said it was “Asynchronous” because they were introduced in Vista to permit non-blocking send operation with LPC. Before when you sent a LPC message with NtReplyWaitReplyPort you have to wait the reaply. Now with NtAlpcSendWaitReceivePort you can use overlapped I/O.

  3. I had an old Win32 CD with some Windows NT 3.1 Preliminary Release build on it. According to many sources, the User and GDI were moved to the Kernel at one point. But what got moved, and how did it look like before? Once upon a time, there must have been some structure in the API, and I wanted to show you that by copying the dispatch tables from those NT 3.1 debug DLLs. Here it is:

    Note: The basesrv.dll names might not be correct! The DLL didn’t have debug symbols for some reason, so I guessed the names using your API table from NT 4. The other onces are the real names.

    In Windows NT 3.51, the winsrv.dll file has all the User routines and probably all the Gre, just like win32k.sys. But Windows NT 3.10 has usersrv.dll and gdisrv.dll.

    One question:
    Why are they (the DLLs) called server? Both client and server DLLs are in user-space, right? How is that security?

    Anyway, the old NT does have a nice structure.

  4. @LOst: Wow, you have done some impressive work!

    Yeah, I was aware of what you wrote – a majority of the graphical interface NTAPIs were moved to kernel-mode, in order to improve the performance – I haven’t ever had a chance to take a look at the actual user-mode dispatch tables from the old versions ;)

    The answer to your question is – they’re called “server DLLs” because of the Client/Server nature of CSRSS communication. In this scheme, *srv (basesrv,winsrv,csrsrv) libraries handle requests coming from the associated, client (user-application side) modules, such as kernel32.dll or user32.dll.

    As for the security – please keep in mind that the hardware-enforced security architecture (privilege rings) is not the only security mechanism utilized by the operating systems. The Windows kernel also implements his own security model – in this particular case, running the CSRSS executable with highest (SYSTEM) user privileges, so that users without certain security tokens (once again – managed by the system) cannot interfere with the Windows subsystem (most often, only Administrative-mode applications are able to do it).

    Thanks for your comment ;)

  5. Thanks j00ru!

    Yea, Windows NT just has so many security layers that I have never been able to put to use.

    I am glad you liked my work. I had to do it because I am such a fan of the old Windows design (you know (kernel, gdi, user) from the original Windows (on top of DOS), and seeing how it was translated to Windows NT in the newer versions didn’t really make much sense when it comes to THAT design (having all gdi and user in a big driver file win32k.sys). So looking at the oldest NT build that I could access, seeing something like kernel32->basesrv, gdi32->gdisrv, user32->usersrv looked much more structured.

    I have been knowing for a long time that CSRSS keeps my Windows alive. I sometimes kill it with my hacked taskmgr for fun (instead of terminating the computer the right way).
    I wanted to know more about it, and why it was considered more than just the Windows sub system (compared to OS/2 ss and Posix ss), and I found your guide. That brought my interest to look up the rest of the client-server API communication for the original NT design.

    I am pretty basic when it comes to hacking CSRSS myself. (On my Windows XP SP3 machine) I found the entry point for BaseSrvExitProcess, did the “at 9:38 /interactive cmd” in a console Window at time 9:37, so that it would spawn a console in the SYSTEM account. Then I opened up WinHex from that new console, and opened the RAM (memory mapped) of CSRSS, looked up the entrypoint inside basesrv.dll, and hacked it to return immediately. Then I opened alot of notepads and calcs on the desktop, and then logged out. It was so fun to find them all running when I logged in again. What a mess!

    You can use my list in your online API list. Just remember that the basesrv’s table is a direct copy of your Windows NT 4 list, because both versions had the same number of functions, and I was guessing none of them had changed. But that might not be true. My basesrv.dll didn’t have the debug symbols for some reason. The rest of the tables are real names, and gdisrv.dll and usersrv.dll’s dispatch tables were really named that way.

Comments are closed.