Csrss进程剖析
這幾天想了解下神秘的進程csrss,在學(xué)習和了解的過程中就寫下了自己對csrss進程的理解。
???Csrss(客戶端/服務(wù)器運行時子系統(tǒng))是?Win32?子系統(tǒng)的用戶模式部分,在桌面管理、終端登錄、控制臺管理、錯誤報告報告和DOS?虛擬機等方面起著重要作用,另外還監(jiān)控著系統(tǒng)內(nèi)所有Win32?子系統(tǒng)進程和線程的運行,進程的創(chuàng)建與退出,都需要通知Csrss。
??圖1是用內(nèi)核工具xuetr觀察Csrss進程加載的模塊。(以下的分析環(huán)境為xp?sp2?32位)
???????????????????????????
???????????????????????????????圖1
??
??由圖1中我們可以知道Csrss進程除了加載諸如Kernel32,ntdll等基礎(chǔ)模塊之外,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?里面有一個未導(dǎo)出符號叫做?CsrRootProcess,?對?csrss?起著重要的作用。CsrRootProcess?指向一個?CSR_PROCESS?結(jié)構(gòu)。
??
??CSR_PROCESS?結(jié)構(gòu)?(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;
??
??
??每一個進程都對應(yīng)著一個?CSR_PROCESS?結(jié)構(gòu)體,所有進程的CSR_PROCESS?結(jié)構(gòu)體
??通過成員struct?_LIST_ENTRY?ListLink?構(gòu)成了一個鏈表,通過CsrRootProcess?可以遍歷這個鏈表。當一個進程創(chuàng)建時,Csrss.exe?會新建一個CSR_PROCESS?結(jié)構(gòu)體,加入到這個鏈表
中(從Csrss.dll中我們可以看到插入鏈表是通過未導(dǎo)出函數(shù)CsrInsertProcess實現(xiàn)的);當一個進程退出時,Csrss.exe?會將該進程對應(yīng)的CSR_PROCESS?結(jié)構(gòu)體從鏈表中刪除(從Csrss.dll中我們可以看到插入鏈表是通過未導(dǎo)出函數(shù)CsrRemoveProcess實現(xiàn)的)。
下面我們可以簡單看下這連個函數(shù)的實現(xiàn):
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);??//進程創(chuàng)建的通知
????????}
????}
}
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);???//進程關(guān)閉的通知
????????}
????}
}
??
??
Csrss?里面還存在著一個?關(guān)于線程的未導(dǎo)出符號叫做?CsrThreadHashTable。它是一個有?256?個元素的數(shù)組,?每一個元素都指向一個?CSR_THREAD?結(jié)構(gòu),?而?CSR_THREAD?結(jié)構(gòu)同樣包含一個?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;
相關(guān)操作函數(shù)CsrInsertThread,CsrRemoveThread。
Win32?子系統(tǒng)進程與CSRSS?的通信
???我們首先從csrss是怎么啟動的作為入口點,用進程查看工具procexp.exe查看相關(guān)信息。
??如下圖3
???????????????????????????????????????????
??????????????????????????????圖3
??從圖3中我們可以知道csrss進程的父進程是smss,我們同樣利用procexp.exe工具查看csrss的啟動參數(shù)是什么,如圖4:
?????????????????????????????
??????????????????????????????圖4
從圖4中我們首先能猜想到的就是ServerDll=winsrv:UserServerDllInitialization,3?的意思是winsev.dll這個核心服務(wù)dll里面存在導(dǎo)出函數(shù)UserServerDllInitialization。那么我們就先從這個函數(shù)里面找找看有什么有用的線索沒。
從UserServerDllInitialization代碼片段中我們發(fā)現(xiàn)了兩張表,如圖5
????????????????????????????????????????????
??????我們在IDA中看看這兩張表(UserServerApiDispatchTable?圖6):
?????????????????????????????
???????????????????????????????????????????圖6
??UserServerApiDispatchTable?這張表保存了很多函數(shù)。而UserServerApiServerValidTable這張表保存的是UserServerApiDispatchTable?表里面相對應(yīng)函數(shù)是否有效的標志。
??同樣的道理我們看看ConServerDllInitialization這個函數(shù),我們也發(fā)現(xiàn)了類似的表。
??如下圖7:
?????
????????????????????
??所以winsrv.dll里面有兩個重要的保存函數(shù)的表:ConsoleServerApiDispatchTable(控制臺管理),UserServerApiDispatchTable(終端登錄之類)。
??
??
??最后我們發(fā)現(xiàn)basesrv.DLL也存在一張保存函數(shù)的表:BaseServerApiDispatchTable,
如下圖8???
?????????????????????????????? ???????
???????????????????????????????????????????????圖8
??
??Csrsrv.dll存在CsrServerApiDispatchTable這張表。(圖9)
?????????????????????????????
????????????????????????????????圖9
??
??四個分發(fā)表序號如下:
??CsrServerApiDispatchTable:0
??BaseServerApiDispatchTable:1
??ConsoleServerApiDispatchTable:2
??UserServerApiDispatchTable:3
??
??因此我們可以知道csrss.exe啟動時候參數(shù)winsrv:UserServerDllInitialization,3?的意思了。
Win32?子系統(tǒng)進程與CSRSS?的通信是通過lpc?port,在圖3中我們可以看到個名為\Windows\ApiPort?的LPC?端口與名為\Windows\sbApiPort的LPC端口。那么在?Csrss?中,對ApiPort?端口所接收到的LPC?消息的處理,主要是由csrsrv.dll?中的
CsrApiRequestThread?函數(shù)完成。CsrApiRequestThread?函數(shù)調(diào)用NtReplyWaitReceivePort?接收
消息,根據(jù)消息的類型執(zhí)行特定的操作。
CsrApiRequestThread函數(shù)里面有一while循環(huán)處理各種請求,ReceiveMsg參數(shù)的ReceiveMsg.h.u2.s2.Type字段保存了消息的類型,當請求為LPC_REQUEST:
??LPC參數(shù)中某一字段:高16?位指定是哪個分發(fā)表,低16?位為分發(fā)表中函數(shù)的索引值
,定義如下:
#define?CSR_APINUMBER_TO_SERVERDLLINDEX(?ApiNumber?)?\
????((ULONG)((ULONG)(ApiNumber)?>>?16))????//高16?位指定是哪個分發(fā)表
#define?CSR_APINUMBER_TO_APITABLEINDEX(?ApiNumber?)?\
??((ULONG)((USHORT)(ApiNumber)))??//低16?位為分發(fā)表中函數(shù)的索引值
???這樣就可以通過分發(fā)表調(diào)用函數(shù)。
??
??ApiNumber?=?ReceiveMsg.ApiNumber;ServerDllIndex?=?CSR_APINUMBER_TO_SERVERDLLINDEX(?ApiNumber?);LoadedServerDll?=?CsrLoadedServerDll[?ServerDllIndex?](*(LoadedServerDll->ApiDispatchTable[?ApiTableIndex?]))(?????????????????????????????????????&ReceiveMsg,?????????????????????????????????????&ReplyStatus?????????????????????????????????????);
???Csrss(客戶端/服務(wù)器運行時子系統(tǒng))是?Win32?子系統(tǒng)的用戶模式部分,在桌面管理、終端登錄、控制臺管理、錯誤報告報告和DOS?虛擬機等方面起著重要作用,另外還監(jiān)控著系統(tǒng)內(nèi)所有Win32?子系統(tǒng)進程和線程的運行,進程的創(chuàng)建與退出,都需要通知Csrss。
??圖1是用內(nèi)核工具xuetr觀察Csrss進程加載的模塊。(以下的分析環(huán)境為xp?sp2?32位)
???????????????????????????
???????????????????????????????圖1
??
??由圖1中我們可以知道Csrss進程除了加載諸如Kernel32,ntdll等基礎(chǔ)模塊之外,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?里面有一個未導(dǎo)出符號叫做?CsrRootProcess,?對?csrss?起著重要的作用。CsrRootProcess?指向一個?CSR_PROCESS?結(jié)構(gòu)。
??
??CSR_PROCESS?結(jié)構(gòu)?(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;
??
??
??每一個進程都對應(yīng)著一個?CSR_PROCESS?結(jié)構(gòu)體,所有進程的CSR_PROCESS?結(jié)構(gòu)體
??通過成員struct?_LIST_ENTRY?ListLink?構(gòu)成了一個鏈表,通過CsrRootProcess?可以遍歷這個鏈表。當一個進程創(chuàng)建時,Csrss.exe?會新建一個CSR_PROCESS?結(jié)構(gòu)體,加入到這個鏈表
中(從Csrss.dll中我們可以看到插入鏈表是通過未導(dǎo)出函數(shù)CsrInsertProcess實現(xiàn)的);當一個進程退出時,Csrss.exe?會將該進程對應(yīng)的CSR_PROCESS?結(jié)構(gòu)體從鏈表中刪除(從Csrss.dll中我們可以看到插入鏈表是通過未導(dǎo)出函數(shù)CsrRemoveProcess實現(xiàn)的)。
下面我們可以簡單看下這連個函數(shù)的實現(xiàn):
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);??//進程創(chuàng)建的通知
????????}
????}
}
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);???//進程關(guān)閉的通知
????????}
????}
}
??
??
Csrss?里面還存在著一個?關(guān)于線程的未導(dǎo)出符號叫做?CsrThreadHashTable。它是一個有?256?個元素的數(shù)組,?每一個元素都指向一個?CSR_THREAD?結(jié)構(gòu),?而?CSR_THREAD?結(jié)構(gòu)同樣包含一個?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;
相關(guān)操作函數(shù)CsrInsertThread,CsrRemoveThread。
Win32?子系統(tǒng)進程與CSRSS?的通信
???我們首先從csrss是怎么啟動的作為入口點,用進程查看工具procexp.exe查看相關(guān)信息。
??如下圖3
???????????????????????????????????????????
??????????????????????????????圖3
??從圖3中我們可以知道csrss進程的父進程是smss,我們同樣利用procexp.exe工具查看csrss的啟動參數(shù)是什么,如圖4:
?????????????????????????????
??????????????????????????????圖4
從圖4中我們首先能猜想到的就是ServerDll=winsrv:UserServerDllInitialization,3?的意思是winsev.dll這個核心服務(wù)dll里面存在導(dǎo)出函數(shù)UserServerDllInitialization。那么我們就先從這個函數(shù)里面找找看有什么有用的線索沒。
從UserServerDllInitialization代碼片段中我們發(fā)現(xiàn)了兩張表,如圖5
????????????????????????????????????????????
??????我們在IDA中看看這兩張表(UserServerApiDispatchTable?圖6):
?????????????????????????????
???????????????????????????????????????????圖6
??UserServerApiDispatchTable?這張表保存了很多函數(shù)。而UserServerApiServerValidTable這張表保存的是UserServerApiDispatchTable?表里面相對應(yīng)函數(shù)是否有效的標志。
??同樣的道理我們看看ConServerDllInitialization這個函數(shù),我們也發(fā)現(xiàn)了類似的表。
??如下圖7:
?????
????????????????????
??所以winsrv.dll里面有兩個重要的保存函數(shù)的表:ConsoleServerApiDispatchTable(控制臺管理),UserServerApiDispatchTable(終端登錄之類)。
??
??
??最后我們發(fā)現(xiàn)basesrv.DLL也存在一張保存函數(shù)的表:BaseServerApiDispatchTable,
如下圖8???
?????????????????????????????? ???????
???????????????????????????????????????????????圖8
??
??Csrsrv.dll存在CsrServerApiDispatchTable這張表。(圖9)
?????????????????????????????
????????????????????????????????圖9
??
??四個分發(fā)表序號如下:
??CsrServerApiDispatchTable:0
??BaseServerApiDispatchTable:1
??ConsoleServerApiDispatchTable:2
??UserServerApiDispatchTable:3
??
??因此我們可以知道csrss.exe啟動時候參數(shù)winsrv:UserServerDllInitialization,3?的意思了。
Win32?子系統(tǒng)進程與CSRSS?的通信是通過lpc?port,在圖3中我們可以看到個名為\Windows\ApiPort?的LPC?端口與名為\Windows\sbApiPort的LPC端口。那么在?Csrss?中,對ApiPort?端口所接收到的LPC?消息的處理,主要是由csrsrv.dll?中的
CsrApiRequestThread?函數(shù)完成。CsrApiRequestThread?函數(shù)調(diào)用NtReplyWaitReceivePort?接收
消息,根據(jù)消息的類型執(zhí)行特定的操作。
CsrApiRequestThread函數(shù)里面有一while循環(huán)處理各種請求,ReceiveMsg參數(shù)的ReceiveMsg.h.u2.s2.Type字段保存了消息的類型,當請求為LPC_REQUEST:
??LPC參數(shù)中某一字段:高16?位指定是哪個分發(fā)表,低16?位為分發(fā)表中函數(shù)的索引值
,定義如下:
#define?CSR_APINUMBER_TO_SERVERDLLINDEX(?ApiNumber?)?\
????((ULONG)((ULONG)(ApiNumber)?>>?16))????//高16?位指定是哪個分發(fā)表
#define?CSR_APINUMBER_TO_APITABLEINDEX(?ApiNumber?)?\
??((ULONG)((USHORT)(ApiNumber)))??//低16?位為分發(fā)表中函數(shù)的索引值
???這樣就可以通過分發(fā)表調(diào)用函數(shù)。
??
??ApiNumber?=?ReceiveMsg.ApiNumber;ServerDllIndex?=?CSR_APINUMBER_TO_SERVERDLLINDEX(?ApiNumber?);LoadedServerDll?=?CsrLoadedServerDll[?ServerDllIndex?](*(LoadedServerDll->ApiDispatchTable[?ApiTableIndex?]))(?????????????????????????????????????&ReceiveMsg,?????????????????????????????????????&ReplyStatus?????????????????????????????????????);
總結(jié)
- 上一篇: docker - 常用命令详解
- 下一篇: 网页设计公众号相关资源网站