以前我一直不理解Windows Session(會話)倒底是一個什麼概念,總是感覺這個概念很虛,現在理解了一點。寫下來做一個備忘。簡單的說,使用者登陸到windows系統之後,不管該使用者是本地登陸的,還是遠程登陸,系統都會為這個使用者指派一個新的會話ID(SID)。也就是說會話與使用者的登入是相關連的,沒有使用者登入就不存在會話。因此,會話的含義是指使用者登入之後的一種啟動並執行環境。我們先看看書上是怎麼說的!
會話管理器(\Windows\System32\Smss.exe)是系統中第一個建立的使用者態模式進程,負責完成執行體和核心的初始化工作的核心模式系統線程在最後階段建立了實際的Smss進程(這段摘自: 《深入解析Windows作業系統(第4版)》80頁)。
Windows系統是支援多會話的,因此會話空間(session space)包含了一些針對每個會話的全域資訊。所以會話空間是用來管理會話的。那麼會話具體包含些什麼呢?
會話(session)是由進程和其他的系統對象(比如視窗站、案頭和視窗)構成的,它們代表了一個使用者的工作站登入工作階段。會話具體是由如下幾個部分組成的:
1. 每個會話包含一個單獨的win32k.sys
2. 專門的換頁池地區
3. 私人windows子系統和登陸進程的拷貝
4. 系統空間中被映射的空間,被稱為會話空間的地區
(參考: 《深入解析Windows作業系統(第4版)》 414頁)
現在我把會話同進程做一個比較,發現他們之間有一些相似之處:
1. 都提供一個執行的環境
2. 都有一個私人空間
進程是為了內部的執行的線程提供一個空間和環境,而會話則是為內部所有的進程提供一個執行的空間和環境。(這是我總結的,感覺總結的很好,便於大家理解會話的概念)
X86會話空間的布局,如:(本人手工繪製 參考:《深入解析Windows作業系統(第4版)》 419頁)
也就是說預設情況下會話空間的大小是8+4+20+16=48M
在我的機器上做如下的實驗:
lkd> !session
Sessions on machine: 1
Valid Sessions: 0
Current Session 0
可以看出我的機器上面只有一個會話,因為是我的機器,只有我在登陸。
調用!sprocess 顯示該會話資料結構的地址和該會話中的進程
lkd> !sprocess
Dumping Session 0
_MM_SESSION_SPACE b85dc000 這裡就是會話空間的地址
_MMSESSION b85dc15c
PROCESS 8a11a268 SessionId: 0 Cid: 028c Peb: 7ffdf000 ParentCid: 0190
DirBase: 0aa00060 ObjectTable: e1b01120 HandleCount: 346.
Image: csrss.exe
PROCESS 8a2d0318 SessionId: 0 Cid: 02a4 Peb: 7ffdf000 ParentCid: 0190
DirBase: 0aa00080 ObjectTable: e18c70b0 HandleCount: 581.
Image: winlogon.exe
PROCESS 8a349da0 SessionId: 0 Cid: 02d0 Peb: 7ffda000 ParentCid: 02a4
DirBase: 0aa000a0 ObjectTable: e1e8da78 HandleCount: 266.
Image: services.exe
…….
我現在查看會話的結構
lkd> dt nt!_MM_SESSION_SPACE b85dc000
+0x000 ReferenceCount : 0x15
+0x004 u : __unnamed
+0x008 SessionId : 0
+0x00c SessionPageDirectoryIndex : 0x18626
+0x010 GlobalVirtualAddress : 0xb85dc000 _MM_SESSION_SPACE
+0x014 ProcessList : _LIST_ENTRY [ 0x8a11a31c - 0x89b98c8c ]
+0x01c NonPagedPoolBytes : 0
+0x020 PagedPoolBytes : 0
+0x024 NonPagedPoolAllocations : 0
+0x028 PagedPoolAllocations : 0
+0x02c NonPagablePages : 0x17
+0x030 CommittedPages : 0x5e4
+0x038 LastProcessSwappedOutTime : _LARGE_INTEGER 0x0
+0x040 PageTables : 0x8a0bb3e8 _MMPTE
+0x044 PagedPoolMutex : _FAST_MUTEX
+0x064 PagedPoolStart : 0xb9800000
+0x068 PagedPoolEnd : 0xb9bfffff
+0x06c PagedPoolBasePde : 0xc0602e60 _MMPTE
+0x070 PagedPoolInfo : _MM_PAGED_POOL_INFO
+0x094 Color : 0xba6
+0x098 ProcessOutSwapCount : 5
+0x09c ImageList : _LIST_ENTRY [ 0x8a355ea0 - 0x8a1de1e8 ]
+0x0a4 GlobalPteEntry : 0xc05c2ee0 _MMPTE
+0x0a8 CopyOnWriteCount : 0x13
+0x0ac SessionPoolAllocationFailures : [4] 0
+0x0bc AttachCount : 0
+0x0c0 AttachEvent : _KEVENT
+0x0d0 LastProcess : (null)
+0x0d8 Vm : _MMSUPPORT
+0x118 Wsle : 0xbcc0003c _MMWSLE
+0x11c WsLock : _ERESOURCE
+0x154 WsListEntry : _LIST_ENTRY [ 0x80561b58 - 0x80561b58 ]
+0x15c Session : _MMSESSION
+0x198 Win32KDriverObject : _DRIVER_OBJECT
+0x240 WorkingSetLockOwner : (null)
+0x244 PagedPool : _POOL_DESCRIPTOR
+0x126c ProcessReferenceToSession : 43
+0x1270 LocaleId : 0x409
來自微軟官方的C結構的定義如下:
typedef struct _MM_SESSION_SPACE{ // // This is a pointer in global system address space, used to make various // fields that can be referenced from any process visible from any process // context. This is for things like mutexes, WSL chains, etc. // struct _MM_SESSION_SPACE *GlobalVirtualAddress; LONG ReferenceCount; union { ULONG LongFlags; MM_SESSION_SPACE_FLAGS Flags; } u; ULONG SessionId; // // This is the list of the processes in this group that have // session space entries. // LIST_ENTRY ProcessList; LARGE_INTEGER LastProcessSwappedOutTime; // // All the page tables for session space use this as their parent. // Note that it's not really a page directory - it's really a page // table page itself (the one used to map this very structure). // // This provides a reference to something that won't go away and // is relevant regardless of which process within the session is current. // PFN_NUMBER SessionPageDirectoryIndex; // // This is the count of non paged allocations to support this session // space. This includes the session structure page table and data pages, // WSL page table and data pages, session pool page table pages and session // image page table pages. These are all charged against // MmResidentAvailable. // SIZE_T NonPageablePages; // // This is the count of pages in this session that have been charged against // the systemwide commit. This includes all the NonPageablePages plus the // data pages they typically map. // SIZE_T CommittedPages; // // Start of session paged pool virtual space. // PVOID PagedPoolStart; // // Current end of pool virtual space. Can be extended to the // end of the session space. // PVOID PagedPoolEnd; // // PTE pointers for pool. // PMMPTE PagedPoolBasePde; ULONG Color; LONG ResidentProcessCount; ULONG SessionPoolAllocationFailures[4]; // // This is the list of system images currently valid in // this session space. This information is in addition // to the module global information in PsLoadedModuleList. // LIST_ENTRY ImageList; LCID LocaleId; // // The count of "known attachers and the associated event. // ULONG AttachCount; KEVENT AttachEvent; PEPROCESS LastProcess; // // This is generally decremented in process delete (not clean) so that // the session data page and mapping PTE can finally be freed when this // reaches zero. smss is the only process that decrements it in other // places as smss never exits. // LONG ProcessReferenceToSession; // // This chain is in global system addresses (not session VAs) and can // be walked from any system context, ie: for WSL trimming. // LIST_ENTRY WsListEntry; // // Session lookasides for fast pool allocation/freeing. // GENERAL_LOOKASIDE Lookaside[SESSION_POOL_SMALL_LISTS]; // // Support for mapping system views into session space. Each desktop // allocates a 3MB heap and the global system view space is only 48M // total. This would limit us to only 20-30 users - rotating the // system view space with each session removes this limitation. // MMSESSION Session; // // Session space paged pool support. // KGUARDED_MUTEX PagedPoolMutex; MM_PAGED_POOL_INFO PagedPoolInfo; // // Working set information. // MMSUPPORT Vm; PMMWSLE Wsle; PDRIVER_UNLOAD Win32KDriverUnload; // // Pool descriptor for less than 1 page allocations. // POOL_DESCRIPTOR PagedPool;#if (_MI_PAGING_LEVELS >= 3) // // The page directory that maps session space is saved here so // trimmers can attach. // MMPTE PageDirectory;#else // // The second level page tables that map session space are shared // by all processes in the session. // PMMPTE PageTables;#endif#if defined (_WIN64) // // NT64 has enough virtual address space to support per-session special // pool. // PMMPTE SpecialPoolFirstPte; PMMPTE SpecialPoolLastPte; PMMPTE NextPdeForSpecialPoolExpansion; PMMPTE LastPdeForSpecialPoolExpansion; PFN_NUMBER SpecialPagesInUse;#endif LONG ImageLoadingCount;#if DBG ULONG Debug[MM_SESS_COUNTER_MAX]; MM_SESSION_MEMORY_COUNTERS Debug2[MM_SESS_MEMORY_COUNTER_MAX];#endif} MM_SESSION_SPACE, *PMM_SESSION_SPACE;
查看會話空間的記憶體使用量,調用!vm 4命令
lkd> !vm 4
.
.
.
Terminal Server Memory Usage By Session:
Session Paged Pool Maximum is 4096K
Session View Space Maximum is 49152K
Session ID 0 @ b85dc000:
Paged Pool Usage: 0K
Commit Usage: 6032K
現在我們清楚了,當使用者登陸到系統中之後,使用者下所有的進程都屬於這個會話空間。在每個進程的PEB當中就有SessionID。
typedef struct _PEB{ BYTE Reserved1[2]; BYTE BeingDebugged; BYTE Reserved2[1]; PVOID Reserved3[2]; PPEB_LDR_DATA Ldr; PRTL_USER_PROCESS_PARAMETERS ProcessParameters; BYTE Reserved4[104]; PVOID Reserved5[52]; PPS_POST_PROCESS_INIT_ROUTINE PostProcessInitRoutine; BYTE Reserved6[128]; PVOID Reserved7[1]; ULONG SessionId;} PEB, *PPEB;
該結構最後一個成員就是SessionId。
那麼這裡就產生一個問題了,同一台機器上面分別屬於不同會話空間下的進程之間如何通訊呢?微軟的MSDN裡面的一些API就說的很清楚了。
我舉一個例子吧。如CreateFileMapping MSDN的描述在 http://msdn.microsoft.com/en-us/library/aa366537(VS.85).aspx
lpName 如果使用"Global\" or "Local\" 作用範圍是全域的。
今天先寫到這兒了!