桌面環境和視窗站
桌面環境
https://msdn.microsoft.com/en-us/library/windows/desktop/ee663298(v=vs.85).aspx
Windows Shell
https://msdn.microsoft.com/en-us/library/windows/desktop/bb773177(v=vs.85).aspx
Windows 桌面UI 為使用者提供訪問執行應用程式和管理作業系統所需要的各種物件。其中我們最最熟悉的物件是駐留在計算機磁碟驅動器上的資料夾和檔案。另外,有許多虛擬物件以允許使用者執行特定的任務,比如傳送檔案到遠端印表機或者訪問回收站。Shell 將這些物件組織成一個分層的名稱空間,並給使用者和應用程式提供了一種有效的方式來訪問和管理物件。
Shell 開發方案
與應用程式開發有關的開發方案。
1. 擴充套件Shell,包括建立一個數據源(相比於使用Shell 資料模型相比)
2. 實現Shell 資料來源任務的一個子集
3. 在Windows 資源管理器中支援庫和專案檢視
4. 使用公共的檔案對話方塊
5. 實施控制面板專案
6. 管理通知
與檔案格式擁有權有關的開發方案
1. 實現Shell 資料來源任務的一個子集
2. 實現任意的處理程式
3. 支援桌面搜尋
與資料儲存擁有者有關的開發方案。
- 支援桌面搜尋和開放搜尋
- 實現Shell 資料來源任務的一個子集(虛擬資料夾)
- 在Windows 資源管理利器中支援庫
下面是一些與裝置支援有關的開發方案。
1. 自動執行和自動播放
Windows Shell SDK 文件
文件分為三大部分。
1. Shell 開發者指南,提供有關Shell 的工作原理以及如何在應用程式中使用Shell 的API 的概念資料
2. Shell 介面,
3. Shell SDK 示例程式碼
Windows 屬性系統
https://msdn.microsoft.com/en-us/library/windows/desktop/ff728898(v=vs.85).aspx
Windows Shell 系統是一個擴充套件的讀/寫資料定義的系統,系統提供了一個唯一的方式來表達Shell 專案的元資料。Windows 屬性系統使得使用者可以儲存和檢索Shell 專案的元資料。一個Shell 專案是任何單獨的內容,比如一個檔案,目錄,郵件或者聯絡人。屬性是與Shell 專案關聯的單個元資料。
Windows 搜尋
https://msdn.microsoft.com/en-us/library/windows/desktop/ff628790(v=vs.85).aspx
Windows Search 是一種桌面搜尋平臺,可以為大多數常見的檔案和資料型別(電子郵件,聯絡人, 日曆約會,文件,照片,多媒體以及可由第三方開發人員擴充套件的其他格式)提供即時搜尋功能。這些功能使用使用者能夠在家庭和企業環境中查詢,管理和組織越來越多的資料。
視窗站和桌面
https://msdn.microsoft.com/en-us/library/windows/desktop/ms687098(v=vs.85).aspx
Windows 建立了三種主要型別的物件:使用者介面,圖形裝置介面,還有核心。核心物件是可保安全的,但是使用者物件和GDI 物件是不可以的。為了提供額外的安全性,使用視窗站和桌面來管理使用者介面物件,這兩個物件本身是可保安全的。
Windows 幫助
描述Windows 中可用的幫助技術。
控制檯
控制檯管理字元模式應用程式(不提供它們自己的圖形使用者介面的應用程式)的輸入和輸出。
上面簡單介紹了桌面環境的組成。下面我們著重介紹視窗站和桌面的資訊。
視窗站
https://msdn.microsoft.com/en-us/library/windows/desktop/ms687096(v=vs.85).aspx
一個視窗站包含剪貼簿,原子表和一個或者多個桌面物件。視窗站物件是可保安全的,當一個視窗站被建立了,它被繫結到呼叫者程序和當前的會話。
互動式視窗站是唯一可以顯示使用者介面或者接收使用者輸入的視窗站。它被繫結到互動式使用者的登陸會話上,其包含了鍵盤,滑鼠,和一個顯示裝置。它有一個固定的名稱“WinSta0”,其它所有的視窗站是不可互動的,因此不可以顯示使用者桌面或者接收使用者輸入。
當一個使用者使用遠端桌面服務登陸了一個計算機,系統將為使用者建立一個登陸會話。每一個會話將有一個和它綁定了的互動式視窗站“WinSta0”。
*遠端桌面會話
當一個使用者登陸到一個遠端登陸服務開啟的計算機上的時候,系統為該使用者建立一個會話。每一個會話用一個唯一的會話SID 標誌。因為每一次登陸到遠端桌面連線(RDC– Remote Desktop Connection )客戶端時都接收到一個單獨的會話ID,因此每個使用者體驗類似於同時登陸到多臺計算機上,例如,辦公室計算機和家庭計算機。
每一個遠端桌面會話繫結一個互動式視窗站。互動式視窗站的名字是唯一的—“WinSta0”,因此每個會話有其自己的“WinSta0”視窗站。每一個視窗站有三個標準的桌面:WinLogon 桌面,桌面保護程式桌面和互動式桌面。
一個會話的互動式視窗站所繫結的使用者就是我們通常所說的互動使用者。在一個RDC 客戶端上,除了當前遠端桌面服務控制檯上的互動式使用者外,還可能有很多個互動式使用者。呼叫WTSGetActiveConsoleSessionId 函式可以得到當前控制檯上的會話的SID。
當一個使用者從RDC 客戶端退出的時候,該遠端會話主機服務上與該使用者繫結的會話被刪除,與該會話繫結的視窗棧和桌面也被清除。因為遠端桌面服務控制檯會話是永遠不會被刪除的,該控制檯會話繫結的視窗站也不被刪除。當應用程式配置為在互動式使用者的安全環境中執行的時候(我們所知道的“Run As 互動式使用者”物件啟用模型),這將影響應用程式在遠端桌面服務環境中的行為。
視窗站安全和訪問許可權
桌面安全和訪問許可權
- 深入理解Windows 作業系統中關於中斷服務和多會話的描述
終端服務指的是在單個系統中,Windows 對於多個可互動使用者會話的支援。利用Windows 的終端服務,一個遠端使用者可以在另一臺機器上建立一個會話,並登入進去,在該伺服器上執行應用程式。伺服器把圖形使用者介面(以及其他可配置的資源,比如音訊和剪貼簿)傳送到客戶機,客戶機把使用者的輸入傳回伺服器。(與X 視窗系統類似,Windows 允許在一個伺服器系統上執行單獨的應用程式,其顯示部分遠端傳送到客戶機,而非將整個桌面遠端到客戶機)。
第一個會話被認為是服務會話,或者零號會話,它包含了宿納系統服務的程序。在機器的物理控制檯上的第一個登入會話為一號會話,而其他的會話可以通過遠端桌面連線程式(Mstsc.exe)來建立,或者通過使用快速使用者切換來建立。
一個可以使用本地方式或者遠端方式使用Windows 客戶機系統,但不能同時以這兩種方式來使用該系統)。- 會話管理器(Smss.exe)
會話管理器是系統中建立的第一個使用者模式程序。這一個程序由服務完成執行體和核心初始化工作最後階段的核心模式系統執行緒建立。
Smss 啟動的時候,檢查自己是第一個例項,還是主Smss 為了建立會話而啟動起來的一個例項(如果存在命令列引數)。通過在引導過程中以及在終端服務會話的建立過程中建立多個多個Smss 例項,Smss 可以同時建立多個會話。一旦一個會話完成了初始化,該會話的Smss 副本便會終止。只有初始的Smss.exe 程序仍然是活動的。
登錄檔中需要用來驅動Smss 初始化的配置資訊都在HKLM\SYSTEM\CurrentControlSet\Control\Session Manager 下。- 主Smss 執行下面的一次性初始化步驟。
- 將該程序和初始執行緒標記為“關鍵的”,關鍵執行緒或程序退出將導致系統崩潰。
- 程序優先順序提升為11
- 如果系統支援動態增加熱處理器,則允許自動更新處理器親和性,這樣,如果新的處理器被加入,新的會話將可以利用這些新加入的處理器。
- 建立相應的命名管道和郵件槽,用於Smss,Csrss,Lsm 之間的通訊。
- 建立ALPC 埠接收命令。
- 根據登錄檔..\Environment設定系統範圍的環境變數。
- 根據登錄檔中..\DOS Devices的定義,在物件管理器名字空間的\Global?? 目錄下為該登錄檔鍵中定義的裝置建立符號連結。
- 在物件管理器名字空間中建立\Sessions 根目錄。
- 執行登錄檔..\BootExecute 中的程序,預設是Autochk.exe ,執行磁碟檢查。
- 根據..\PendingFileRenameOperations 中指定的資訊,處理尚未完成的檔案改名操作。
- 初始化頁面檔案(paging file)
- 初始化登錄檔的其它部分(HKLM Software、SAM和Security 儲巢(hive)。
- 執行..\SetupExecute 中的程式
- 開啟已知DLL (..\Known DLLs),將它們對映為永久記憶體區(對映檔案)。
- 建立一個執行緒來響應會話建立請求。
- 建立Smss 來初始化會話0(非互動會話)
- 建立Smss 來初始化會話1(互動會話)
這些操作完成後,Smss 將在會話0的Csrss.exe 例項的控制代碼上等待。會話啟動的Smss 例項完成以下事項:
- 呼叫NtSetSystemInformation 請求建立起核心模式的會話資料結構—>呼叫內部的記憶體管理器函式MmSessionCreate,它建立起會話虛擬地址空間,其中包含該會話的換頁記憶體池,以及由Win32k.sys 和其它的會話空間裝置驅動程式所分配的屬於每個會話的資料結構。
- 為該會話建立子系統程序(預設Csrss.exe)
- 建立Winlogon 例項(對於互動會話)或者Wininit例項(對於會話0)
然後這一中間Smss 程序退出(留下子系統程序和Winlogon 或 Wininit 成為無父程序)。Windows 初始化程序(Wininit.exe)
- 將自己標記為“關鍵的”
- 初始化使用者模式排程設施
- 建立$windir%\temp 資料夾
- 建立一個視窗站(Winsta0)和兩個桌面(Winlogon 和 Default),以便會話0 中的程序可以在其中執行。
- 建立Services.exe(服務控制管理器,SCM)
- 啟動Lsass.exe(本地安全認證子系統伺服器)
- 啟動Lsm.exe (本地會話管理器)
- 一直等待,直到系統停機
- 本地會話管理器(Lsm.exe)
Lsm.exe 管理本地機器上的終端伺服器會話的狀態。它通過ALPC 斷奶口SmSsWinStationApiPort 向Smss 傳送請求啟動新的會話,比如當用戶在資源管理器中選擇“切換使用者”時,Lsm 也跟Winlogon 和 Csrss 進行通訊(通過一個本地系統RPC)。它通知Csrss 諸如建立連線、斷開連線、終止等時間,也廣播系統訊息。對於以下的事件,它接收Winlogon 的通知:
- 登入和登出
- Shell 啟動和終止
- 連線到一個會話。
- 與一個會話斷開連線
- 鎖住或解鎖桌面。
- Winlogon 、LogonUI 和 Userinit
Windows 登入程序(Winlogon.exe)處理互動式使用者的登陸和登出。當SAS 組合鍵(Ctrl+Alt+Delete)被按下,Winlogon 接收到一個使用者登入請求。登入過程的身份識別和認證是通過一種稱為憑證提供者的DLL來實現的。標準的Windows 憑證提供者實現了預設的Windows 認證介面:口令和智慧卡,但是開發人員可以開發自己的憑證提供者來實現其它的身份識別和認證機制(如聲波,指紋等)。憑證提供者和顯示登入對話方塊的UI 都執行在Winlogon 的一個子程序中,稱為LogonUI,當Winlogon 檢測到SAS 時,啟動這個程序,該程序會初始化憑證提供者。一旦使用者輸入了憑證,或者取消了登入介面,LogonUI 程序就終止。
獲得使用者名稱和口令後,送到本地安全認證伺服器程序(Lsass.exe)進行認證,認證成功後,LSASS 呼叫安全引用監視器中的一個函式,生成一個訪問令牌物件。然後Winlogon 利用此令牌建立該使用者會話中的初始程序(預設Userinit.exe)。Userinit 執行使用者環境的一些初始化工作(比如執行登入指令碼、應用組策略),然後在登錄檔中查詢Shell 值,並建立一個程序來執行系統定義的shell(預設Explorer.exe)。然後,Userinit 退出(explorer 程序無父程序)。
Winlogon 不僅在使用者登入和登出的時候是活動的,擷取到鍵盤的SAS 就是活動的。如果你在登入之後按下了SAS ,Windows 安全螢幕會出現,提示登出、啟動工作管理員、鎖定工作站、關閉系統等選線。Winlogon 和 LogonUI 是負責處理這一互動過程的程序。
除了兩個地方Smss 程序和其它的任何使用者程序都一樣。首先,Windows 認為Smss 是一個可信任的作業系統程序。第二,Smss 是一個native 應用程式。因為它是一個受信任的程序,它可以執行絕大多數其它程序不能執行的操作,比如建立安全令牌。因為它是一個native 應用程式,Smss 不呼叫Windows API(在Smss 啟動時候Csrss 尚未啟動,而且是Smss 建立的Csrss程序),它僅僅呼叫大家已經知道的稱為windows native API 的核心執行體API。
視窗站和桌面建立
系統自動建立互動式視窗站。當一個互動式使用者登陸,系統將使用者登陸會話和互動式視窗站繫結起來。系統為互動式視窗站建立預設的輸入桌面(WinSta0\default)。登入使用者啟動的程序被繫結到Winsta0\default 桌面。
一個程序可以呼叫CreateWindowStation 函式來建立一個新的視窗站,呼叫CreateDesktop 或者 CreateDesktopEx 函式來建立一個新的桌面。系統桌面堆的數量限制了我們所能建立的桌面的數量。更多資訊請參見CreateDesktop 函式。
當一個非互動程序比如服務應用程式嘗試連線到一個視窗站,而程序登入會話沒有視窗站,系統將嘗試為會話建立一個視窗站和桌面。被建立的視窗站的名字是基於登入會話SID 的,而桌面的名字是預設的,正如下面兩點描述的一樣:
1. 如果一個服務執行在本地系統賬戶的安全上下文但是沒有包含SERVICE_INTERACTIVE_PROCESS 屬性,它使用下面的視窗站和桌面:Service-0x0-3e7$\default。這個視窗是不可互動的,因此服務不能顯示使用者互動資訊。另外,服務建立的程序不能顯示使用者互動資訊。
2. 如果一個服務執行在一個使用者賬戶的安全上下文中,視窗站的名稱是基於使用者SID Service-0xZ1-Z2$,Z1 是登入SID 的高部分,Z2 是登入SID 的低部分。因為一個SID 對於登入會話來說是唯一的,兩個執行在同樣的安全環境中的服務接收獨一無二的視窗站。這些視窗站不可互動。
對於服務的使用者賬戶來說,視窗站和桌面的DACL 包含以下的訪問許可權:
Window Station
WINSTA_ACCESSCLIPBOARD
WINSTA_ACCESSGLOBALATOMS
WINSTA_CREATEDESKTOP
WINSTA_EXITWINDOWS
WINSTA_READATTRIBUTES
STANDARD_RIGHTS_REQUIRED
Desktop
DESKTOP_CREATEMENU
DESKTOP_CREATEWINDOW
DESKTOP_ENUMERATE
DESKTOP_HOOKCONTROL
DESKTOP_READOBJECTS
DESKTOP_WRITEOBJECTS
STANDARD_RIGHTS_REQUIRED
程序連線到一個視窗站
當一個程序第一次呼叫USER32 或者 GDI32 函式函式(除了視窗站和桌面函式)的時候,它將與一個視窗站建立連線關係。系統根據下面的規則決定將與程序建立連線的視窗站。
1.如果程序呼叫SetProcessWindowStation 函式,它將連線該函式指定的視窗站。
2.如果程序沒有呼叫SetProcessWindowStation 函式,繼承其父程序所連線的視窗站。
3.如果上述兩個方法沒有得到其視窗站,系統嘗試以MAXIMUM_ALLOWED 訪問許可權來訪問並連線下面列舉的視窗站中中的每一個,直到連線上:
1. 如果建立程序的時候STARTINFO 結構中的lpDesktop 成員指定了一個視窗站名稱,程序將嘗試連線指定的視窗站。
2. 否則, 如果程序執行在互動使用者的登入會話中的話,程序連線到這個互動式視窗站。
3. 如果程序執行在一個非互動式登入會話中,將基於登入會話ID 來構建視窗站名字,並嘗試以這個名字來開啟視窗站。如果因為視窗站不存在而打不開視窗站的話,系統嘗試建立該視窗站和一個預設的桌面。
在這個連線過程中,程序不能通過呼叫CloseWindowStation 函式來關閉這個被繫結的視窗站。
當一個程序正在連線到一個視窗站的時候,系統在程序的控制代碼表中搜索可繼承的控制代碼表。系統使用它所找到的第一個視窗站控制代碼。如果你想讓子程序繼承特定的視窗站控制代碼,必須確保該控制代碼是唯一一個可繼承的控制代碼。如果一個子程序繼承了多個視窗站控制代碼,被連線的視窗站是不確定的。
將程序連線到視窗站時系統開啟的視窗的控制代碼是不可繼承的。
連線執行緒到桌面
在一個程序連線到一個視窗站的時候,系統繫結一個桌面到這個建立連線的執行緒。系統按照下面的規則來決定執行緒將要繫結的桌面。
1.如果執行緒呼叫SetThreadDesktop函式,執行緒將連線到函式指定的桌面。
2.如果執行緒沒有呼叫SetThreadDesktop 函式,它連線到從其父程序繼承的桌面。
3.如果上面的兩個都沒有繫結桌面,系統嘗試按照下面的順序以MAXIMUM_ALLOWED 訪問許可權來開啟桌面。
1. 如果在建立程序的時候在STARTUPINFO 的lpDesktop 成員指定了一個特定的桌面名稱, 執行緒將連線這個特定的桌面。
2. 否則,執行緒連線程序連線的視窗站中的預設桌面。
在這個連線期間,程序不能通過CloseDesktop 函式來關閉被繫結的desktop。
當一個程序在連線一個桌面,系統搜尋程序的控制代碼表中的可繼承控制代碼。系統使用它所找到的第一個桌面控制代碼。如果你想一個子程序來連線一個特定的可程序的桌面,必須確保該控制代碼是唯一可繼承的桌面控制代碼。如果一個子程序繼承了多個可程序的桌面控制代碼,桌面連線的結果是不確定的。
系統在連線一個程序到一個桌面的時候開啟的控制代碼是不可繼承的。
桌面
一個桌面有一個邏輯顯示器幷包含諸如視窗,選單和hook 等使用者介面物件。他可以用來建立和管理視窗。每一個桌面物件都是可保安全的。當建立一個桌面物件的時候,它被繫結到呼叫程序的當前視窗站上,並被繫結到當前執行緒上。
視窗訊息只能在同一個桌面的不同程序之間進行傳遞。另外,一個程序的hook 函式只能接收來自同一個桌面內建立的視窗的特定訊息。
一個互動式視窗站(WinSta0)可以有多個桌面,以用來顯示使用者介面並接收使用者輸入,但是同一時間只能有一個桌面是活動的,這個活動的桌面就是我們通常所說的“輸入桌面”。應用程式可以呼叫OpenInputDesktop 函式來得到“輸入桌面”的控制代碼。如果擁有相應的許可權,應用程式
可以呼叫SwitchDesktop 函式來切換“輸入桌面”為其它的桌面。
預設情況下,一個互動式視窗站中有三個桌面:預設,螢幕保護,Winlogon。
預設桌面是Winlogon 以一個已經登入的使用者的身份啟動初始程序的時候建立的,這時候,預設桌面開始活動,並用來與使用者進行互動。
每當一個安全的螢幕保護程式活動的時候,系統自動轉換到螢幕保護桌面,該桌面禁止沒有認證的使用者訪問預設桌面的程序。不安全的桌面保護桌面執行在Winsta0\Default。