Page 1 of 2 12 LastLast
Results 1 to 15 of 18

Thread: Windows CSRSS cross-version API Table

  1. #1

    Windows CSRSS cross-version API Table

    Hello!

    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 exemplary code snippet follows:

    Code:
    .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 @ http://j00ru.vexillium.org/csrss_list/api_list.html.
    2. A cross-version compatibility table, for the same system version set can be found @ http://j00ru.vexillium.org/csrss_list/api_table.html.

    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


    http://j00ru.vexillium.org/?p=349&lang=en

  2. #2
    j00ru
    Hardkod (job table as f(Version) a bad way). It should look for an alternative to searching for a dynamic, otherwise in future versions of the system or in the package code may not be working.
    Regarding the service subsystem - make better use of parsing api, this parsing code using a disassembler lengths and retrieval of SIGN/ID, or more complex, but versatile and desirable to use an analysis of the graph (and its construction means a third party engine).

  3. #3
    Teach, Not Flame Kayaker's Avatar
    Join Date
    Oct 2000
    Posts
    4,087
    Blog Entries
    5
    Nice work on another definitive reference j00ru. Yes, the CsrApi ID's would complete the tables and could be used as the key to intercepting the higher level API's (for hack/undocumented purposes). For example, through CsrClientCallServer and the LPC message system hooking as I discussed a bit in this thread, showing one possible way of intercepting both process and thread creation at a very early stage. Unfortunately I only parsed out a small subset of api numbers from kernel32.dll, but I'd be willing to dig around a bit more.

    http://www.woodmann.com/forum/showthread.php?12679-Thread-Based-Code-behavior-Profiler

  4. #4
    Teach, Not Flame Kayaker's Avatar
    Join Date
    Oct 2000
    Posts
    4,087
    Blog Entries
    5
    Following up on this a bit, the following defines from the Windows Research Kernel should simplify calculating the relevant CsrApi ID's from the individual CSRSS libraries.

    Code:
    #define CSRSRV_SERVERDLL_INDEX          0
    
    #define BASESRV_SERVERDLL_INDEX         1
    
    #define CONSRV_SERVERDLL_INDEX          2
    
    #define USERSRV_SERVERDLL_INDEX         3
    
    #define CSR_MAKE_API_NUMBER( DllIndex, ApiIndex ) \
        (CSR_API_NUMBER)(((DllIndex) << 16) | (ApiIndex))

    Using the example of BaseSrvExitProcess from basesrv.dll, CSR_API_NUMBER = 0x10003

    Code:
    .data:75B5D080 _BaseServerApiDispatchTable
    .data:75B5D080  dd offset _BaseSrvCreateProcess@8
    .data:75B5D084  dd offset _BaseSrvCreateThread@8
    .data:75B5D088  dd offset _BaseSrvGetTempFile@8
    .data:75B5D08C  dd offset _BaseSrvExitProcess@8
    ...
    Which is confirmed from kernel32.dll:

    Code:
    :7C81CA6C __ExitProcess@4 proc near
    ...
    :7C81CAB4  push    4
    :7C81CAB6  push    10003h
    :7C81CABB  push    ebx
    :7C81CABC  lea     eax, [ebp+var_DC]
    :7C81CAC2  push    eax
    :7C81CAC3  call    ds:__imp__CsrClientCallServer@16

    As Indy alludes to, a dynamic, version independant method of finding the unexported *ServerApiDispatchTable in each of the libraries would be nice. In XP the dispatch table is at offset 24h of a structure passed as arg0 of the exported DllInitialization functions for each of the cases. I haven't found a structure definition yet, but it appears to be a CsrHeap allocation.

    Code:
    ServerDllInitialization (basesrv.dll)
    :75B5338C  mov     dword ptr [edi+24h], offset _BaseServerApiDispatchTable
    
    ConServerDllInitialization (winsrv.dll)
    :75B688EE  mov     dword ptr [eax+24h], offset _ConsoleServerApiDispatchTable
    
    UserServerDllInitialization (winsrv.dll)
    :75B68536  mov     dword ptr [eax+24h], offset _UserServerApiDispatchTable
    
    CsrServerDllInitialization (csrsrv.dll)
    :75B41EF1  mov     dword ptr [eax+24h], offset _CsrServerApiDispatchTable

    EDIT: The structure might be similar to this from ReactOS /subsys/csr/server.h. Note the pointer to the Dispatch Table at the correct offset as well as other matches of structure use from ServerDllInitialization and CsrLoadServerDll (csrsrv.dll).

    Code:
    typedef struct _CSR_SERVER_DLL
    {
        ULONG Length;
        HANDLE Event;
        ANSI_STRING Name;
        HANDLE ServerHandle;
        ULONG ServerId;
        ULONG Unknown;
        ULONG ApiBase;
        ULONG HighestApiSupported;
        PCSR_API_ROUTINE *DispatchTable;
        PBOOLEAN ValidTable;
        PCHAR *NameTable;
        ULONG SizeOfProcessData;
        PCSR_CONNECT_CALLBACK ConnectCallback;
        PCSR_DISCONNECT_CALLBACK DisconnectCallback;
        PCSR_HARDERROR_CALLBACK HardErrorCallback;
        PVOID SharedSection;
        PCSR_NEWPROCESS_CALLBACK NewProcessCallback;
        PCSR_SHUTDOWNPROCESS_CALLBACK ShutdownProcessCallback;
        ULONG Unknown2[3];
    } CSR_SERVER_DLL, *PCSR_SERVER_DLL;

  5. #5
    Kayaker
    Using the example of BaseSrvExitProcess from basesrv.dll, CSR_API_NUMBER = 0x10003
    If you use ldasm, there will be a small problem with the disclosure of procedural branches(ExitProcess() -> _ExitProcess()). When searching for parsing graph(control flow) no such problems. A signature will be defined as:
    - Nesting Level = 1 or 2.
    - (Push 4)__(push ID)__(Line code, not specified)__(call [CsrClientCallServer]).
    Because procedural branch is a simple reference raises the level of nesting, it can lay the entire problem on engine. The function is defined as a hash on its name.
    There is a semiprivate and opensource engine for creating and parsing of the graph - GCBE. It performs the disassembly(basic) and the construction/tracing of the graph is open(extensions, such as the optimizer, builder, etc. private. Public parts enough to parse the code and extract the necessary signatures).

  6. #6
    @Indy, Kayaker: I certainly agree with you that the table should also contain CsrAPI opcode numbers, which in turn would be detected dynamically.

    Let me write a few words on each of the two methods suggested.

    1. Because of the fact that the only system libraries communicating with CSRSS are kernel32.dll and user32.dll, one could try to detect all the CsrClientCallServer (or CsrClientConnectToServer in case of Windows 7) calls and assign the contant numbers pushed on the stack to exported function names.

    Let's consider, for example, kernel32.CreateProcessA. After a program calls this API, the execution goes through
    • CreateProcessA
    • CreateProcessInternalA
    • CreateProcessInternalW
    • CsrClientCallServer(0x10000)

    In order to give the the 0x10000 value a particular name, the call path should be rebuilt, and eventually the number would become known as something like "SrvCreateProcessA".

    Even though it seems to be doable, I don't find this method really convenient. And more importantly, based on such analysis, we still wouldn't retrieve the original CSR-api names, but its equivalent from the Windows API instead.

    2. These numbers could also be extracted directly from the CSRSS-related binaries, most likely at run-time. The definitions and code snippets presented by Kayaker would be indeed helpful; however, there are a few additional factors that should be taken into consideration.

    2.1 As the operating systems are evolving, so is the security / functionality design. Some examples of this are:
    • the console management code has been moved from CSRSS (winsrv.dll) running on SYSTEM privileges to a dedicated conhost.exe process, running with the local user's rights. More information can be found here: http://blogs.technet.com/askperf/archive/2009/10/05/windows-7-windows-server-2008-r2-console-host.aspx
      -
    • the number of the server dispatch table is not guaranteed to remain the same thorough respective OS versions. For instance, an additional sxssrv.dll file is loaded by CSRSS since Windows 7. In general, information regarding the libraries containing dispatch tables could be gathered from the CSRSS.exe command line, which usually takes the following form:
      Code:
      %SystemRoot%\system32\csrss.exe ObjectDirectory=\Windows SharedSection=1024,20480,768 Windows=On ServerDll=basesrv,1 ServerDll=winsrv:UserServerDllInitialization,3 ServerDll=winsrv:ConServerDllInitialization,2 ServerDll=sxssrv,4 ProfileC
      This means that the contant values / macros from WRK are deprecated even now, not to mention the future.

    2.2 Calculating the relevant CsrApi ID's is slightly more complicated than you presented. More specifically, a simple pseudocode of the code responsible for calling the corresponding handlers looks similar to the following:

    Code:
    CsrApiID = WaitForRequest();
    
    if((CsrApiID>>16) > NUMBER_OF_DISPATCH_TABLES)
      continue;
    
    ServerTable = CsrLoadedServerDll[(CsrApiID>>16)];
    if(ServerTable)
    {
      if((CsrApiID - ServerTable->ApiBase) < (ServerTable->HighestApiSupported - ServerTable->ApiBase))
      {
        ServerTable->DispatchTable[CsrApiID - ServerTable->ApiBase];
      }
    }
    which means that three fields of the _CSR_SERVER_DLL are in fact required to rebuild the CsrApi numbers.


    To sum everything up - IMHO the best method of achieving a version-independent table dumper would:
    1. Find the CSRSS process associated with the current user, and detect the loaded server libraries
    2. Heuristically parse the server initialization function in search of the three values (ApiBase, HighestApiSupported and DispatchTable). OR
    3. Heuristically find the CsrLoadedServerDll table inside csrsrv.dll, and parse each _CSR_SERVER_DLL structure separately
    4. Obtain the symbols for function pointers present in the tables, and associate names with the contants.


    Any suggestions regarding the above? It is likely that I'll take up this project and let you test some generic piece of code

    Cheers

  7. #7
    Registered User
    Join Date
    Aug 2005
    Location
    Italy
    Posts
    133
    Blog Entries
    31
    Nice work, thanks!

    http://evilcry.netsons.org (Repository)
    http://evilcodecave.blogspot.com
    http://evilcodecave.wordpress.com

  8. #8
    Even though it seems to be doable, I don't find this method really convenient. And more importantly, based on such analysis, we still wouldn't retrieve the original CSR-api names, but its equivalent from the Windows API instead.
    You are wrong. For such tasks, more so for problems that are of concern, such as search LdrpDllNotificationList or LdrpInitializeTls.. analysis of the graph is the only normal solution. Graph can renounce the binary code, considering the functional in general.
    The nesting level of procedures, such as CreateProcessA -> CreateProcessInternalA.. etc. in the analysis of the graph is irrelevant. He wondered if the construction of the graph, to truncate the extra code.
    This is the only normal solution.

  9. #9
    Hey Indy,
    I don't see your point Indeed, execution graph analysis is some solution, but why calling it the only reasonable one (as far as I understand) ?

    Here are my doubts:

    1. Even if we're able to find & analyze all the x-refs to CsrClientCallServer, present in kernel32.dll and user32.dll, where do we take the corresponding, internal CsrApi names from? I've mentioned this issue before (you've even quoted it).
    2. The purpose of such project would be to gather information about all the existing functions. What is your guarantee that every supported CsrApi function is called from somewhere within the WinAPI implementation libraries? I don't have one.


    By the way, could you please clarify what a normal solution means here? I thought we're looking for something rather effective (even if out-of-the-box) than normal in any terms

    Cheers

  10. #10
    j00ru
    1. Of course the internal names are not needed. Necessary identification. They are linked with the name of the exported API functions. For example ExitProcess -> BasepExitProcess.
    2. Prove otherwise
    Of course not all services are used. But they are not needed. In addition, most of the opensource(w2k, w2000 etc.).
    Normal decision means universal, stable and independent of the version.
    Definition of table ID I regard as extremely bad decision. This is my imho, I can not hardly be mistaken in this
    As proof, I can build a sample

  11. #11
    Quote Originally Posted by Indy View Post
    j00ru
    1. Of course the internal names are not needed. Necessary identification. They are linked with the name of the exported API functions. For example ExitProcess -> BasepExitProcess.
    Name identification is one thing. The information about where a specific CsrApi is implemented is the second one.

    2. Prove otherwise
    Of course not all services are used. But they are not needed. In addition, most of the opensource(w2k, w2000 etc.).
    Normal decision means universal, stable and independent of the version.
    Definition of table ID I regard as extremely bad decision. This is my imho, I can not hardly be mistaken in this
    As proof, I can build a sample
    Documenting CSRSS only through the Windows API libraries sounds like trying to create a complete system-call table (e.g. graphical calls) based on static user32.dll analysis.
    Looking at the above quote, I'm under the impression that we've got a different point of view, on what exactly we would like to create in the first place. Well, maybe just let it be this way

    Cheers

  12. #12
    j00ru
    An example of a well reflecting the essence. Example is not full(dasm cut that not can disclose the import, so not everywhere will work on XP will)
    Attached Files Attached Files
    Last edited by Indy; May 5th, 2010 at 02:34.

  13. #13
    Teach, Not Flame Kayaker's Avatar
    Join Date
    Oct 2000
    Posts
    4,087
    Blog Entries
    5
    I wanted to try extracting out the CSR_SERVER_DLL structure from memory for each of the CSRSS subsystems, to get the address of the corresponding DispatchTable and other interesting bits dynamically.

    If you trace back from the CsrServerApiDispatchTable entry in csrsrv.dll you find that the parent CSR_SERVER_DLL structure is initially allocated on the heap in CsrLoadServerDll. Some of the structure elements are defined here, others later in CsrServerDllInitialization (csrsrv), ServerDllInitialization (basesrv), or ConServerDllInitialization & UserServerDllInitialization (winsrv).

    I'm not sure how all the modules tie together - who loads who and in what order or how the individual heap blocks comprising each of the CSR_SERVER_DLL structures are allocated, but it doesn't matter for the discussion.

    Code:
    int __stdcall CsrLoadServerDll
    
    :75B4338C  movzx   ebx, [ebp+DestinationString.MaximumLength]
    :75B43390  add     ebx, 4Ch
    :75B43393  push    ebx
    :75B43394  mov     eax, _CsrBaseTag ; 0 in memory
    :75B43399  add     eax, 40000h
    :75B4339E  push    eax
    :75B4339F  push    _CsrHeap        ; 0x160000 in memory
    :75B433A5  call    ds:__imp__RtlAllocateHeap@12
    
    RtlAllocateHeap(
      IN PVOID                HeapHandle,
      IN ULONG                Flags,
      IN ULONG                Size );
    Note that the HeapHandle (_CsrHeap) is actually the address of the Default Process Heap (for csrss.exe).


    I started with TopToBottomNt and viewed the memory of csrss.exe, searching for the *ServerApiDispatchTable addresses obtained from disassembly of each of the CSR modules. I found them all in the Default Process Heap beginning at 0x160000.

    At this point a better tool was called for so I used HeapMemView from NirSoft. Perfect! All of the individual heap allocations for csrss.exe can be examined. After a little bit of digging I found each of the CSR_SERVER_DLL structures with pointers to the Data Address and Header Address for each block (they are all of block size 88, 0x58).



    Next I created a structure definition in WinDbg for CSR_SERVER_DLL for use with the dt (Display Type) command. I had a problem though with attaching (non-invasively) to csrss.exe in usermode - it would lock up. Instead I used LiveKD in local kernel mode.

    To create the custom structure type so it was available in kernel mode in any context, I used the trick of Blabberer to ADD the struct definition to the already existing win32k.pdb, whose symbols are loaded by default in all contexts. You can use .reload /u win32k.sys to unload the pdb, modify your custom defs and recompile, then reload the new symbol with .reload win32k.sys.

    http://www.woodmann.com/forum/showthread.php?10295-Mysteries-of-win32k-amp-GDI&p=72632&viewfull=1#post72632


    Here is the structure definition I created which was added to the win32k.pdb list of symbols. Note that the last field, ULONG Unknown2[3]; given in the ReactOS version in an earlier post I redefined as UCHAR NameString[12], since that's what the ANSI_STRING Buffer field points to.

    Code:
    typedef unsigned long ULONG;
    typedef unsigned short USHORT;
    typedef unsigned char UCHAR;
    typedef unsigned long HANDLE;
    typedef unsigned long PBOOLEAN;
    typedef unsigned long PCHAR;
    typedef unsigned long PVOID;
    typedef unsigned long PCSR_API_ROUTINE;
    typedef unsigned long PCSR_CONNECT_CALLBACK;
    typedef unsigned long PCSR_DISCONNECT_CALLBACK;
    typedef unsigned long PCSR_HARDERROR_CALLBACK;
    typedef unsigned long PCSR_NEWPROCESS_CALLBACK;
    typedef unsigned long PCSR_SHUTDOWNPROCESS_CALLBACK;
    
    typedef struct _STRING {
      USHORT  Length;
      USHORT  MaximumLength;
      PCHAR  Buffer;
    } ANSI_STRING, *PANSI_STRING;
    
    typedef struct _CSR_SERVER_DLL
    {
        ULONG Length;
        HANDLE Event;
        ANSI_STRING Name;
        HANDLE ServerHandle;
        ULONG ServerId;
        ULONG Unknown;
        ULONG ApiBase;
        ULONG HighestApiSupported;
        PCSR_API_ROUTINE *DispatchTable;
        PBOOLEAN ValidTable;
        PCHAR *NameTable;
        ULONG SizeOfProcessData;
        PCSR_CONNECT_CALLBACK ConnectCallback;
        PCSR_DISCONNECT_CALLBACK DisconnectCallback;
        PCSR_HARDERROR_CALLBACK HardErrorCallback;
        PVOID SharedSection;
        PCSR_NEWPROCESS_CALLBACK NewProcessCallback;
        PCSR_SHUTDOWNPROCESS_CALLBACK ShutdownProcessCallback;
        UCHAR NameString[12];
    } CSR_SERVER_DLL, *PCSR_SERVER_DLL;


    OK, let's get to the results already...


    So we start with finding the csrss.exe process

    kd> !process 0 0

    PROCESS 831c7020 Image: csrss.exe

    and switch context to csrss

    kd> .process 831c7020
    Implicit process is now 831c7020


    Using the Data Address from HeapMemView for the relevant heap allocations, apply the custom CSR_SERVER_DLL structure definition.

    Code:
    kd> dt win32k!_CSR_SERVER_DLL -v -b 162b58
    struct _CSR_SERVER_DLL, 19 elements, 0x58 bytes
       +0x000 Length           : 0x52
       +0x004 Event            : 0x14
       +0x008 Name             : struct _STRING, 3 elements, 0x8 bytes
     "CSRSS"
          +0x000 Length           : 5
          +0x002 MaximumLength    : 6
          +0x004 Buffer           : 0x162ba4 (points to NameString below)
       +0x010 ServerHandle     : 0
       +0x014 ServerId         : 0
       +0x018 Unknown          : 0
       +0x01c ApiBase          : 0
       +0x020 HighestApiSupported : 5
       +0x024 DispatchTable    : 0x75b48004 
       +0x028 ValidTable       : 0x75b48018
       +0x02c NameTable        : (null) 
       +0x030 SizeOfProcessData : 0
       +0x034 ConnectCallback  : 0
       +0x038 DisconnectCallback : 0
       +0x03c HardErrorCallback : 0
       +0x040 SharedSection    : 0x7f6f0000
       +0x044 NewProcessCallback : 0
       +0x048 ShutdownProcessCallback : 0
       +0x04c NameString       : (12 elements)   "CSRSS"
        [00] 0x43 'C'
        [01] 0x53 'S'
        [02] 0x52 'R'
        [03] 0x53 'S'
        [04] 0x53 'S'
        [05] 0 ''
        [06] 0 ''
        [07] 0 ''
        [08] 0 ''
        [09] 0 ''
        [10] 0 ''
        [11] 0 ''

    Code:
    kd> dt win32k!_CSR_SERVER_DLL -v -b 162bb8
    struct _CSR_SERVER_DLL, 19 elements, 0x58 bytes
       +0x000 Length           : 0x54
       +0x004 Event            : 0x14
       +0x008 Name             : struct _STRING, 3 elements, 0x8 bytes
     "basesrv"
          +0x000 Length           : 7
          +0x002 MaximumLength    : 8
          +0x004 Buffer           : 0x162c04
       +0x010 ServerHandle     : 0x75b50000
       +0x014 ServerId         : 1
       +0x018 Unknown          : 0
       +0x01c ApiBase          : 0
       +0x020 HighestApiSupported : 0x20
       +0x024 DispatchTable    : 0x75b5d080 
       +0x028 ValidTable       : 0x75b5d104
       +0x02c NameTable        : (null) 
       +0x030 SizeOfProcessData : 0
       +0x034 ConnectCallback  : 0x75b52a89
       +0x038 DisconnectCallback : 0x75b52ab2
       +0x03c HardErrorCallback : 0
       +0x040 SharedSection    : 0x7f6f06a0
       +0x044 NewProcessCallback : 0
       +0x048 ShutdownProcessCallback : 0
       +0x04c NameString       : (12 elements)   "basesrv"
        [00] 0x62 'b'
        [01] 0x61 'a'
        [02] 0x73 's'
        [03] 0x65 'e'
        [04] 0x73 's'
        [05] 0x72 'r'
        [06] 0x76 'v'
        [07] 0 ''
        [08] 0 ''
        [09] 0 ''
        [10] 0 ''
        [11] 0 ''
    UserServerDllInitialization

    Code:
    kd> dt win32k!_CSR_SERVER_DLL -v -b 163a80
    struct _CSR_SERVER_DLL, 19 elements, 0x58 bytes
       +0x000 Length           : 0x53
       +0x004 Event            : 0x14
       +0x008 Name             : struct _STRING, 3 elements, 0x8 bytes
     "winsrv"
          +0x000 Length           : 6
          +0x002 MaximumLength    : 7
          +0x004 Buffer           : 0x163acc
       +0x010 ServerHandle     : 0x75b60000
       +0x014 ServerId         : 3
       +0x018 Unknown          : 0
       +0x01c ApiBase          : 0x400
       +0x020 HighestApiSupported : 0x40b
       +0x024 DispatchTable    : 0x75b9d560 
       +0x028 ValidTable       : 0x75b9d458
       +0x02c NameTable        : (null) 
       +0x030 SizeOfProcessData : 0
       +0x034 ConnectCallback  : 0x75b61c5d
       +0x038 DisconnectCallback : 0
       +0x03c HardErrorCallback : 0x75b7b3b9
       +0x040 SharedSection    : 0x7f6f0000
       +0x044 NewProcessCallback : 0
       +0x048 ShutdownProcessCallback : 0x75b78f84
       +0x04c NameString       : (12 elements)   "winsrv"
        [00] 0x77 'w'
        [01] 0x69 'i'
        [02] 0x6e 'n'
        [03] 0x73 's'
        [04] 0x72 'r'
        [05] 0x76 'v'
        [06] 0 ''
        [07] 0xff ''
        [08] 0xff ''
        [09] 0xff ''
        [10] 0xff ''
        [11] 0xff ''
    ConServerDllInitialization

    Code:
    kd> dt win32k!_CSR_SERVER_DLL -v -b 163be0
    struct _CSR_SERVER_DLL, 19 elements, 0x58 bytes
       +0x000 Length           : 0x53
       +0x004 Event            : 0x14
       +0x008 Name             : struct _STRING, 3 elements, 0x8 bytes
     "winsrv"
          +0x000 Length           : 6
          +0x002 MaximumLength    : 7
          +0x004 Buffer           : 0x163c2c
       +0x010 ServerHandle     : 0x75b60000
       +0x014 ServerId         : 2
       +0x018 Unknown          : 0
       +0x01c ApiBase          : 0x200
       +0x020 HighestApiSupported : 0x255
       +0x024 DispatchTable    : 0x75b689f0 
       +0x028 ValidTable       : 0x75b68b48
       +0x02c NameTable        : (null) 
       +0x030 SizeOfProcessData : 0x58
       +0x034 ConnectCallback  : 0x75b61a5a
       +0x038 DisconnectCallback : 0x75b618de
       +0x03c HardErrorCallback : 0
       +0x040 SharedSection    : 0x7f6f0000
       +0x044 NewProcessCallback : 0x75b61963
       +0x048 ShutdownProcessCallback : 0x75b7d5c7
       +0x04c NameString       : (12 elements)   "winsrv"
        [00] 0x77 'w'
        [01] 0x69 'i'
        [02] 0x6e 'n'
        [03] 0x73 's'
        [04] 0x72 'r'
        [05] 0x76 'v'
        [06] 0 ''
        [07] 0xff ''
        [08] 0xff ''
        [09] 0xff ''
        [10] 0xff ''
        [11] 0xff ''


    So what good is all this? While it might not be directly applicable to finding the CsrAPI Id's or their definitions, if we can find a reliable way to "walk" the Default Process Heap of csrss.exe and recognize the _CSR_SERVER_DLL allocations, it's a simple matter to get absolute addresses of PCSR_API_ROUTINE *DispatchTable and other elements for each of the subsystems. Assuming the whole house of cards doesn't fall in Vista or Windows 7...

    The heap allocations are preceded by an 8 byte Header, recognized by HeapMemView as a unique Header Address immediately before the Data Address. This unknown "HEAP_HEADER" might be similar to a POOL_HEADER, though when I applied that definition to the structure it didn't parse like a normal Pool Header (that I recognized anyway).

    Hopefully someone has some knowledge of how to parse/walk a process heap and might be able to clarify things.

    Kayaker

  14. #14
    Kayaker
    I'm not sure how all the modules tie together - who loads who and in what order or how the individual heap blocks comprising each of the CSR_SERVER_DLL structures are allocated, but it doesn't matter for the discussion.
    http://virustech.org/f/viewtopic.php?id=25
    http://files.virustech.org/release/autorundoc/autorun_doc_03.01.2010.rar
    The only question for what it is you need

  15. #15
    @Kayaker: Really nice work!
    Assuming the whole house of cards doesn't fall in Vista or Windows 7...
    As far as my observations go, the situation is generally the same on both Windows Vista and 7 (obviously the CSR_DLL_SERVER structures differ from version to version).

    The only thing in the presented approach that bothers me is the non-deterministic method of finding the aforementioned structures on the default CSRSS.exe heap. I am not a win32-heap specialist, but w/e method is used, we end up "scanning" the heap blocks in search of known signs of CSR_DLL_SERVER presence - there is still no certainty that we will find every and only desired structures (or maybe I've just missed your point?).

    One way or another, I myself have came up with a few new ideas of how to obtain the three critical values (ApiBase, HighestApiSupported, DispatchTable) in a stable manner.

    1. The first concept is about making direct use of the server initialization routines, exported by particular server libraries (such as winsrv.ConServerDllInitialization, winsrv.UserServerDllInitialization or basesrv.ServerDllInitialization). In fact, I can see a couple of possibilities how to take advantage of these functions:

    - Load these DLLs in current process context. Call the server initialization routines, supplying a pointer to the buffer controlled by us - and pray that none of the functions crash. If the above succeeds, our buffer would contain the desired values + dispatch table pointer (still in local process' memory).
    If no memory address randomization is involved, most likely we've just figured out the DispatchTable address inside CSRSS.exe.

    - Try to perform an analogue trick, but inside CSRSS itself rather than our process. More precisely - create a remote thread and respectively call the init routines, supplying a controlled buffer as the output parameter. However, a bit of a prayer is still necessary here, due to the fact that the system never initializes server libraries twice under normal circumstances - such a technique could result in unknown behavior (i.e. disabling all the console windows already present on the system [this one I've encouraged on my own skin during tests] and other unpredictable consequences).

    - As I've mentioned earlier, the actual list of server dlls, which CSRSS is supposed to load, is passed to the process through command line! To be more exact, the command line path, used by SMSS to spawn the csrss process can be found in a registry value:

    Code:
    HKLM\System\CurrentControlSet\Control\Session Manager\SubSystems\CSRSS\Windows
    containing something like:
    Code:
    %SystemRoot%\system32\csrss.exe ObjectDirectory=\Windows SharedSection=1024,12288,512 Windows=On SubSystemType=Windows ServerDll=basesrv,1 ServerDll=winsrv:UserServerDllInitialization,3 ServerDll=winsrv:ConServerDllInitialization,2 ProfileControl=Off MaxRequestThreads=16
    This, in turn, means that the the OS admin can easily control the names of server files and initialization functions by simply modifying the above reg value. My idea is to create a wrapper library for each of the srv DLLs. A majority of the exported functions would be simply forwarded to the original images; only the execution of most interesting routines would be intercepted, e.g. in the following way:

    Code:
    DWORD STDCALL ConServerDllInitialization(CSR_SERVER_DLL* ConServer)
    {
      DWORD dwReturn = orgConServerDllInitialization(ConServer);
    
      LogToFile("ConServer->ApiBase              = 0x%.8x\n"
                     "ConServer->HighestApiSupported  = 0x%.8x\n"
                     "ConServer->DispatchTable        = 0x%.8x\n",
                      ConServer->ApiBase,ConServer->HighestApiSupported,ConServer->DispatchTable);
    
      return dwReturn;
    }
    This would let us to parse the CSR_SERVER_DLL structure right after it is filled by the appropriate routine, and during legitimate system behavior - the wrappers would be called by CSRSS itself!

    The only problem is that we can't apply this technique in relation to csrsrv.dll - that's because the library is not a basic server dll - it is highly connected with the csrss.exe image, and thus the CsrServer initialization takes place locally, without any exported function involvement.

    I might create a some PoC code to prove that the above works in practice
    Concurrently, I would like to hear your opinion regarding the presented ideas ;p

    Cheers

Similar Threads

  1. 0-day Windows XP SP3 Denial of Service (CSRSS Crash #1)
    By j00ru vx tech blog in forum Blogs Forum
    Replies: 0
    Last Post: August 3rd, 2011, 17:18
  2. Replies: 0
    Last Post: July 15th, 2011, 03:27
  3. Windows CSRSS Write Up: Inter-process Communication (part 2/3)
    By j00ru vx tech blog in forum Blogs Forum
    Replies: 0
    Last Post: July 27th, 2010, 17:52
  4. Windows CSRSS Write Up: Inter-process Communication (part 1/3)
    By j00ru vx tech blog in forum Blogs Forum
    Replies: 2
    Last Post: July 17th, 2010, 12:18
  5. Windows CSRSS Write Up: the basics (part 1/1)
    By j00ru vx tech blog in forum Blogs Forum
    Replies: 2
    Last Post: July 9th, 2010, 15:59

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •