(转) Csrss进程剖析

http://bbs.pediy.com/showthread.php?t=150284

这几天想了解下神秘的进程csrss,在学习和了解的过程中就写下了自己对csrss进程的理解。
  Csrss(客户端/服务器运行时子系统)是 Win32 子系统的用户模式部分,在桌面管理、终端登录、控制台管理、错误报告报告和DOS 虚拟机等方面起着重要作用,另外还监控着系统内所有Win32 子系统进程和线程的运行,进程的创建与退出,都需要通知Csrss。

图1是用内核工具xuetr观察Csrss进程加载的模块。(以下的分析环境为xp sp2 32位)

                               图1
  
  由图1中我们可以知道Csrss进程除了加载诸如Kernel32,ntdll等基础模块之外,basesrv.dll,csrsrv.dll ,winsrv.dll就是Csrss进程的核心模块,因此我们重点研究这几个模块,当然研究这几个模块就要那个这几个模块的pdb文件,我们利用windbg提供的工具SymChk 下载这几个模块的pdb文件,首先在cmd命令行中进入windbg目录,然后用如下命令:
Symchk /r  c:\windows\system32 /s SRV*c:\mysymbols\*http://msdl.microsoft.com/download/symbols

如图2.                                 
                                            图2
  

  这样我们就有了csrss进程核心模块的pdb文件,为下面我们用IDA分析这些模块提供了方便。
  

  csrsrv.dll 里面有一个未导出符号叫做 CsrRootProcess, 对 csrss 起着重要的作用。CsrRootProcess 指向一个 CSR_PROCESS 结构。
  
  CSR_PROCESS 结构 (Vista/2008, 对于 XP/2003 同样适用) 如下:

typedef struct _CSR_PROCESS
{
    CLIENT_ID ClientId;
    LIST_ENTRY ListLink;
    LIST_ENTRY ThreadList;
    struct _CSR_PROCESS *Parent;
    PCSR_NT_SESSION NtSession;
    ULONG ExpectedVersion;
    HANDLE ClientPort;
    ULONG_PTR ClientViewBase;
    ULONG_PTR ClientViewBounds;
    HANDLE ProcessHandle;
    ULONG SequenceNumber;
    BYTE Flags[4];
    ULONG DebugFlags;
    CLIENT_ID DebugCid;
    ULONG ReferenceCount;
    ULONG ProcessGroupId;
    ULONG ProcessGroupSequence;
    ULONG fVDM;
    ULONG ThreadCount;
    ULONG PriorityClass;
    ULONG Reserved;
    ULONG ShutdownLevel;
    ULONG ShutdownFlags;
    PVOID ServerData[ANYSIZE_ARRAY];
} CSR_PROCESS, *PCSR_PROCESS;

  每一个进程都对应着一个 CSR_PROCESS 结构体,所有进程的CSR_PROCESS 结构体

  通过成员struct _LIST_ENTRY ListLink 构成了一个链表,通过CsrRootProcess 可以遍历这个链表。当一个进程创建时,Csrss.exe 会新建一个CSR_PROCESS 结构体,加入到这个链表
中(从Csrss.dll中我们可以看到插入链表是通过未导出函数CsrInsertProcess实现的);当一个进程退出时,Csrss.exe 会将该进程对应的CSR_PROCESS 结构体从链表中删除(从Csrss.dll中我们可以看到插入链表是通过未导出函数CsrRemoveProcess实现的)。

  下面我们可以简单看下这连个函数的实现:

VOID NTAPI CsrInsertProcess(IN PCSR_PROCESS Parent OPTIONAL,
    IN PCSR_PROCESS CurrentProcess OPTIONAL,
    IN PCSR_PROCESS CsrProcess)
{
    PCSR_SERVER_DLL ServerDll;
    ULONG i;

    /* Set the parent */
    CsrProcess->Parent = Parent;

    /* Insert it into the Root List */
    InsertTailList(&CsrRootProcess->ListLink, &CsrProcess->ListLink);

    /* Notify the Server DLLs */
    for (i = 0; i < CSR_SERVER_DLL_MAX; i++)
    {
        /* Get the current Server DLL */
        ServerDll = CsrLoadedServerDll[i];

        /* Make sure it's valid and that it has callback */
        if (ServerDll && ServerDll->NewProcessCallback)
        {
            (*ServerDll->NewProcessCallback)(CurrentProcess, CsrProcess);  //进程创建的通知
        }
    }
}


VOID NTAPI CsrRemoveProcess(IN PCSR_PROCESS CsrProcess)
{
    PCSR_SERVER_DLL ServerDll;
    ULONG i;

    /* Remove us from the Process List */
    RemoveEntryList(&CsrProcess->ListLink);

    /* Release the lock */
    CsrReleaseProcessLock();

    /* Loop every Server DLL */
    for (i = 0; i < CSR_SERVER_DLL_MAX; i++)
    {
        /* Get the Server DLL */
        ServerDll = CsrLoadedServerDll[i];

        /* Check if it's valid and if it has a Disconnect Callback */
        if (ServerDll && ServerDll->DisconnectCallback)
        {
            /* Call it */
            (ServerDll->DisconnectCallback)(CsrProcess);   //进程关闭的通知
        }
    }
}

  Csrss 里面还存在着一个 关于线程的未导出符号叫做 CsrThreadHashTable。它是一个有 256 个元素的数组, 每一个元素都指向一个 CSR_THREAD 结构, 而 CSR_THREAD 结构同样包含一个 LIST_ENTRY。

typedef struct _CSR_THREAD
{ 
    // <size 0x38>   
    union _LARGE_INTEGER CreateTime;    
    struct _LIST_ENTRY Link;   
    struct _LIST_ENTRY HashLinks;   
    struct _CLIENT_ID ClientId;   
    struct _CSR_PROCESS* Process;   
    struct _CSR_WAIT_BLOCK* WaitBlock;   
    void* ThreadHandle;  
    unsigned long Flags;   
    unsigned long ReferenceCount;   
    unsigned long ImpersonateCount;
} CSR_THREAD, *PCSR_THREAD;

  相关操作函数CsrInsertThread,CsrRemoveThread。


  Win32 子系统进程与CSRSS 的通信
  我们首先从csrss是怎么启动的作为入口点,用进程查看工具procexp.exe查看相关信息。
  如下图3                                     
                              图3
  从图3中我们可以知道csrss进程的父进程是smss,我们同样利用procexp.exe工具查看csrss的启动参数是什么,如图4:
                             按圖片以查看大圖  名稱: arg.jpg 查看次數: 3 文件大小: 75.3 KB ID: 67102
                              图4
  从图4中我们首先能猜想到的就是ServerDll=winsrv:UserServerDllInitialization,3 的意思是winsev.dll这个核心服务dll里面存在导出函数UserServerDllInitialization。那么我们就先从这个函数里面找找看有什么有用的线索没。
从UserServerDllInitialization代码片段中我们发现了两张表,如图5
                                            
  我们在IDA中看看这两张表(UserServerApiDispatchTable 图6):
                             
                                           图6
  UserServerApiDispatchTable 这张表保存了很多函数。而UserServerApiServerValidTable这张表保存的是UserServerApiDispatchTable 表里面相对应函数是否有效的标志。
  同样的道理我们看看ConServerDllInitialization这个函数,我们也发现了类似的表。
  如下图7:

     
                    名稱:  table2.jpg 查看次數: 838 文件大小:  64.5 KB
  所以winsrv.dll里面有两个重要的保存函数的表:ConsoleServerApiDispatchTable(控制台管理),UserServerApiDispatchTable(终端登录之类)。
  
  
  最后我们发现basesrv.DLL也存在一张保存函数的表:BaseServerApiDispatchTable,
如下图8   
                                     
                                               图8
  
  Csrsrv.dll存在CsrServerApiDispatchTable这张表。(图9)
                             
                                图9
  
  四个分发表序号如下:
  CsrServerApiDispatchTable:0
  BaseServerApiDispatchTable:1
  ConsoleServerApiDispatchTable:2
  UserServerApiDispatchTable:3
  
  因此我们可以知道csrss.exe启动时候参数winsrv:UserServerDllInitialization,3 的意思了。
Win32 子系统进程与CSRSS 的通信是通过lpc port,在图3中我们可以看到个名为\Windows\ApiPort 的LPC 端口与名为\Windows\sbApiPort的LPC端口。那么在 Csrss 中,对ApiPort 端口所接收到的LPC 消息的处理,主要是由csrsrv.dll 中的
CsrApiRequestThread 函数完成。CsrApiRequestThread 函数调用NtReplyWaitReceivePort 接收
消息,根据消息的类型执行特定的操作。

CsrApiRequestThread函数里面有一while循环处理各种请求,ReceiveMsg参数的ReceiveMsg.h.u2.s2.Type字段保存了消息的类型,当请求为LPC_REQUEST:
  LPC参数中某一字段:高16 位指定是哪个分发表,低16 位为分发表中函数的索引值
,定义如下:
#define CSR_APINUMBER_TO_SERVERDLLINDEX( ApiNumber ) \
    ((ULONG)((ULONG)(ApiNumber) >> 16))    //高16 位指定是哪个分发表

#define CSR_APINUMBER_TO_APITABLEINDEX( ApiNumber ) \
  ((ULONG)((USHORT)(ApiNumber)))  //低16 位为分发表中函数的索引值
   这样就可以通过分发表调用函数。
  
  ApiNumber = ReceiveMsg.ApiNumber;ServerDllIndex = CSR_APINUMBER_TO_SERVERDLLINDEX( ApiNumber );LoadedServerDll = CsrLoadedServerDll[ ServerDllIndex ](*(LoadedServerDll->ApiDispatchTable[ ApiTableIndex ]))(                                     &ReceiveMsg,                                     &ReplyStatus                                     );

转载于:https://www.cnblogs.com/himessage/archive/2012/12/27/2835286.html

一:SSDT表的hook检测和恢复 ~!~~~ 二:IDT表的hook检测和恢复 ~~~~~~(idt多处理器的恢复没处理,自己机器是单核的,没得搞,不过多核的列举可以) 三:系统加载驱动模块的检测 通过使用一个全局hash表(以DRIVEROBJECT为对象)来使用以下的方法来存储得到的结果,最终显示出来 1.常规的ZwQuerySystemInformation来列举 2通过打开驱动对象目录来列举 3搜索内核空间匹配驱动的特征来列举(这个功能里面我自己的主机一运行就死机,别的机器都没事,手动设置热键来蓝屏都不行,没dump没法分析,哎,郁闷) 4从本驱动的Modulelist开始遍历来列举驱动 四:进程的列举和进程所加载的dll检测 采用以下方法来列举进程: 1ZwQuerySystemInformation参数SystemProcessesAndThreadsInformation来枚举 2进程EPROCESS 结构的Activelist遍历来枚举 3通过解析句柄表来枚举进程 4通过Handletablelisthead枚举进程 5进程创建时都会向csrss来注册,从这个进程里面句柄表来枚举进程 6通过自身进程的HANDLETABLE来枚举进程 7通过EPROCESS的SessionProcessLinks来枚举进程 8通过EPROCESS ---VM---WorkingSetExpansionLinks获取进程 9暴力搜索内存MmSystemRangeStart以上查找PROCESS对象 进程操作: 进程的唤醒和暂停通过获取PsSuspendProcess和PsResumeProcess来操作的 进程结束通过进程空间清0和插入apc。 采用以下方法查找DLL: 1遍历VAD来查找dll 2挂靠到对应的进程查找InLoadOrderLinks来枚举dll 3暴力搜索对应进程空间查找pe特征来枚举dll DLL的操作: Dll的卸载是通过MmUnmapViewOfSection和MmmapViewOfSection(从sdt表中相应函数搜索到的)来实现的(本来想直接清0 dll空间,有时行有时不行)(只要将这个进程的ntdll卸载了,进程就结束了,一个好的杀进程的办法撒,绿色环保无污染),注入dll使用的是插入apc实现的。(注入的dll必须是realse版的。Debug版会出现***错误,全局dll注入貌似也是)插入apc效果不是很好,要有线程有告警状态才执行。 五:线程信息的检测 遍历ThreadList来枚举线程 线程的暂停和唤醒都是通过反汇编获取PsResumeThread和PsSuspendThread直接从r3传来ETHREAD来操作的,通过插入APC来结束线程 六:shadow sdt表的hook检测与恢复 没有采用pdb来解决函数名问题,直接写入xp和03的shandow表函数名(主要是自己的网不稳定,连windbg有时都连不上微软) 七:系统所有的过滤驱动的检测 查看各device下是否挂接有驱动之类的,可直接卸载 八:系统常用回调历程的检测和清除 只检查了PsSetLoadImageNotifyRoutine PsSetCreateThreadNotifyRoutine PsSetCreateProcessNotifyRoutine CmRegisterCallback这几个,至于那个什么shutdown回调不知道是啥玩意,就没搞了,有知道的顺便告诉我下撒,谢谢 九:文件系统fat和ntfs的分发函数检测 直接反汇编fat和ntfs的DriverEntry得到对应的填充分发的偏移,然后和当前已经运行的文件系统的分发相比是否被hook,并附带恢复 十:文件查看功能 自己解析ntfs和fat的结构,来实现列举文件和直接写磁盘删除。附带有普通的删除和发生IRP来删除。不过这里面有点问题,ntfs删除有时把目录给搞坏了,大家凑合着吧, Ntfs网上删除这些操作的代码不多,就是sudami大大的利用ntfs-3g来实现的,看了下,太多了,充满了结构。然后自己对照着系统删除文件时目录的变化来自己实现的。只处理了$BITMAP对应的位清除,父目录的对应文件的索引项的覆盖,删除文件对应的filerecord清0. 另外偷懒时间都没处理,呵呵,y的,一个破时间都都搞好几个字节移来移去的。 十一:常用内核模块钩子的检测和恢复 这里只检测了主要的内核模块nkrnlpa**.exe的.win32k.sys,hal.dll,比对它们的原始文件从而查找eat inline hook,iat hook ,和inline hook。Inline是从TEXT段开始一段位置开始比较的。(有点慢貌似,等待显示扫描完成就好了) 十二:应用层进程所加载dll的钩子 应用层钩子检测和内核模块钩子检测原理一样,不过为了能读写别的进程的空间,并没有使用openprocess去打开进程,而是通过KiattachProcess挂靠到当前进程,然后通过在r0直接读写进程空间的。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值