Csrss进程剖析
這幾天想了解下神秘的進程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:
?????????????????????????????
??????????????????????????????圖4
從圖4中我們首先能猜想到的就是ServerDll=winsrv:UserServerDllInitialization,3?的意思是winsev.dll這個核心服務dll里面存在導出函數UserServerDllInitialization。那么我們就先從這個函數里面找找看有什么有用的線索沒。
從UserServerDllInitialization代碼片段中我們發現了兩張表,如圖5
????????????????????????????????????????????
??????我們在IDA中看看這兩張表(UserServerApiDispatchTable?圖6):
?????????????????????????????
???????????????????????????????????????????圖6
??UserServerApiDispatchTable?這張表保存了很多函數。而UserServerApiServerValidTable這張表保存的是UserServerApiDispatchTable?表里面相對應函數是否有效的標志。
??同樣的道理我們看看ConServerDllInitialization這個函數,我們也發現了類似的表。
??如下圖7:
?????
????????????????????
??所以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?????????????????????????????????????);
???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:
?????????????????????????????
??????????????????????????????圖4
從圖4中我們首先能猜想到的就是ServerDll=winsrv:UserServerDllInitialization,3?的意思是winsev.dll這個核心服務dll里面存在導出函數UserServerDllInitialization。那么我們就先從這個函數里面找找看有什么有用的線索沒。
從UserServerDllInitialization代碼片段中我們發現了兩張表,如圖5
????????????????????????????????????????????
??????我們在IDA中看看這兩張表(UserServerApiDispatchTable?圖6):
?????????????????????????????
???????????????????????????????????????????圖6
??UserServerApiDispatchTable?這張表保存了很多函數。而UserServerApiServerValidTable這張表保存的是UserServerApiDispatchTable?表里面相對應函數是否有效的標志。
??同樣的道理我們看看ConServerDllInitialization這個函數,我們也發現了類似的表。
??如下圖7:
?????
????????????????????
??所以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?????????????????????????????????????);
總結
- 上一篇: docker - 常用命令详解
- 下一篇: 网页设计公众号相关资源网站