熱點推薦:
您现在的位置: 電腦知識網 >> 操作系統 >> Windows系統管理 >> 正文

WindowStations窗口站

2013-11-11 21:42:50  來源: Windows系統管理 
    Window stations 和桌面可能是Windows NT服務中最與眾不同的了絕大多數編程者都不會直接接觸這兩種對象盡管用戶每時每刻都要碰到它們window station 和桌面對象就象其它Windows NT對象如事件互斥量和信號量一樣是安全(securable)的一個window station 對象包括一個剪貼板一個全局原子集和更多的桌面對象一個window station或者是可見的或者是不可見的一個可見的window station接收用戶來自於鼠標或鍵盤的輸入一個顯示設備也與之相連這樣信息可以顯示給交互式用戶
    在 Windows NT 只有一個window station 能被看得到就是WinSta可見的window station也被定義成交互式的一個不可見的window station是不可交互的而且也不能接收任何用戶的輸入也沒有顯示設備與之相連
    如前所述桌面包含在window station對象中一個桌面對象包含一個邏輯的顯示表面和窗口菜單等只有屬於可見window station的桌面才能被看見並接收用戶的輸入這個桌面叫做活動桌面
    作為交互式用戶你在不同的時候碰到三種不同的桌面缺省(Default) Winlogon和ScreensaverWinlogon 桌面是當你按下Ctrl+Alt+Delete組合鍵時顯示在你面前的對話框缺省(Default)桌面是浏覽器(Explorer)或者是由交互式用戶啟動的所有進程它更應當被理解成交互式的應用程序桌面最終的桌面是Screensaver它顯示你的屏幕saver你可能已經注意到可以在不同的桌面之間切換當一個用戶按下Ctrl+Alt+Delete組合鍵時操作系統可以從缺省狀態切換到Winlogon桌面當你在登錄對話框中選擇取消系統將再切換回缺省桌面有人問我當切換進行的時候是否其它桌面上的東西都被破壞掉了答案是 雖然你看不到其它桌面但它們仍然在那裡
    系統中所有的進程都與window station 和桌面相聯系當一個用戶第一次登錄時交互式window station WinSta和缺省桌面都與這個用戶的Shell進程相關聯這樣用戶就能看到shell了如果不是這樣用戶是什麼也看不到的而且在這之後由shell啟動的所有進程也會和WinSta 及缺省桌面相關聯
    你還可以通過STARTUPINFO 數據結構的lpDesktop 成員指定你的進程同哪個window station 和桌面相關聯這個數據結構傳遞給CreateProcess 和 CreateProcessAsUser兩個函數你可以將lpDesktop 初始化為NULL意思是讓CreateProcess函數使用和調用進程相同的window station 和桌面你可以將你自己的window station 和桌面組合定義成WinSta\Default 或者就定義成空字符串這個參數會讓操作系統為啟動進程創建一個新的不可見的window station 及桌面與這兩個新對象關聯的安全性授予每個組對它們的完全訪問權限
    typedef struct _STARTUPINFO { // si
    DWORD cb;
    LPTSTR lpReserved;
    LPTSTR lpDesktop;
    LPTSTR lpTitle;
    DWORD dwX;
    DWORD dwY;
    DWORD dwXSize;
    DWORD dwYSize;
    DWORD dwXCountChars;
    DWORD dwYCountChars;
    DWORD dwFillAttribute;
    DWORD dwFlags;
    WORD wShowWindow;
    WORD cbReserved;
    LPBYTE lpReserved;
    HANDLE hStdInput;
    HANDLE hStdOutput;
    HANDLE hStdError;
    } STARTUPINFO *LPSTARTUPINFO;
    Window stations和桌面是具有安全性的對象與window station 和桌面將關聯的進程必須由對這些對象的合適的訪問權限如果進程沒有訪問權你會看到這兩個消息之一Userdll initialization failure(Userdll初始化失敗)Kerneldll initialization failure(Kerneldll初始化失敗)由進程返回的退出碼為 或 ERROR_NO_WAIT_CHILDREN那麼我所指的合適的訪問權是什麼意思呢?假如你有一個文件這樣的對象你可以為這個文件創建一個DACL以使用戶具有對這個文件的讀訪問權Window station 和 桌面是以相同的方式工作的
    對於一個桌面對象的一個訪問權限叫做DESKTOP_CREATEWINDOW如果用戶沒有被授予這個訪問權限任何由這個用戶啟動的進程都不能創建窗口不幸的是 象CreateWindow 這樣的USER APIs 在發生同CreateFile 或 CreateMutex API類似的安全問題時不會返回 Access Denied(訪問被拒絕) 消息Userdll 中的Windows 應用程序將會被終止導致DLL初始化錯誤的消息Kerneldll 初始化過程是在創建一個控制板窗口時發生的一個例程在沒有對window station和桌面的合適的訪問權限的時候啟動cmdexe然而不幸的是 CreateProcess 沒有任何機制來檢查這個錯誤當用戶不具有對window station和桌面的合適訪問權限時它並不返回一個錯誤信息CreateProcess將會啟動這個應用程序然後這個應用程序本身在DLL失敗後終止
    編程人員還可以有一種方法越過Userdll initialization failure(Userdll初始化失敗消息系統有一個堆用來為window station分配內存內存是有限的缺省設置允許創建七個或八個window station對象如果你用光了所有的內存你就會看到這個消息不過值得慶幸的是有一個注冊表關鍵字可以用來增加這個設置 (參見Knowledge Base article Q
    如果你沒在開發服務而只是普通的應用程序Window stations 和桌面就不是真正的問題你的應用程序只同交互式桌面WinSta\Default 相關聯如果你是在開發一個服務那麼它可能就會同下面的window station 及桌面組合關聯
    WinSta\Default
    Servicexe$\Default
    Service Accounts Logon SID\Default
    WinSta\Default 同運行在LocalSystem帳戶的並且與桌面交互的服務關聯 (在ServiceType必須指明SERVICE_INTERACTIVE_PROCESS標志)如果服務不同桌面交互那麼它是與Servicexe$\Default相關聯的這是個不可見的window station你一定很疑惑這亂七八糟的xe$ 是什麼它是服務的登錄SID 登錄SID是獨一無二的它指的是用戶所屬的組系統中的所有用戶都會有一個登錄SID


    有一個有趣的現象是盡管你為同一個服務帳戶配置了兩個服務但由於它們的登錄SID是不同的所以每個都將有一個獨一無二的window station 及桌面用戶的SID是相同的但是由於它們運行在不同的服務帳戶登錄段中所以它們每一個都有獨一無二的登錄段對於交互式服務和非交互式的LocalSystem 服務情況就不同了因為它們既同WinSta關聯又同Servicexe$關聯
    為什麼知道哪個window station和桌面與服務相關聯是如此的重要呢?第一交互性如果你的服務沒有和WinSta\Default相關聯它就不能以缺省狀態把任何USER對象展示給用戶這意味著你不能顯示一個窗口或者是獲得用戶的輸入你可以為一個非交互式的服務顯示一個MessageBox 關鍵字標志的類型是MB_SERVICE_NOTIFICATION 和 MB_DEFAULT_DESKTOP你不能用它來發送消息這個動作與你的進程相關聯的桌面有關系如果你不為進程重新分配正確的window station 及桌面你就始終不能做這件事
    另外兩種基於服務帳號的登錄SID的window station 和桌面組合是不可見的正如我剛剛提到的與一個不可見window station相關聯的桌面永遠不能顯示或接收來自交互式用戶的輸入信息(除非MessageBox使用兩個特殊的標志)你仍然可以創建USER對象但是用戶永遠不會看到它們很多服務的開發者們經常要犯的一個錯誤是顯示一個對話框提示用戶輸入信息當服務被測試時開發者會注意到服務被掛起了這就是因為服務同一個不可見的window station相關聯操作系統是成功地創建了對話框問題是用戶看不到它
    所以你應當怎樣才能使你的服務能顯示並獲得從用戶那來的信息呢?首先為用戶寫一個啟動的客戶應用程序客戶應用程序將實現顯示及從用戶處獲得信息的功能然後使用進程間通信機制把信息發回給服務這樣做的最大好處是你不必再為window stations及桌面操心一個缺點就是需要用戶做一些事情來啟動你的客戶應用程序
    另外一個方法要求你為LocalSystem帳戶配置你的服務要將服務類型說明為SERVICE_INTERACTIVE_PROCESS這將把你的服務與正確的window station及桌面相關聯唯一的問題就是服務將不能通過NTLM進行任何的網絡訪問有兩種辦法可以解決第一種辦法是NULL 段訪問可以在服務器端通過注冊表調整如果服務開發者有對服務器的合適的安全訪問權限注冊表的關鍵字將會改變允許對LocalSystem 進程的訪問
    另一個解決的辦法是扮演一個已經訪問過NTLM 安全網絡資源的用戶一個問題是服務必須知道用戶的口令以通過LogonUser API生成用戶的標志為什麼用戶不能為服務帳戶配置一個服務那樣就只須重新為服務分配交互式的window station 及桌面就可以了?答案只有一個就是安全對交互式window station 及桌面具有完全訪問權限的唯一用戶是LocalSystem帳戶和交互式用戶(如果有的話)我特別指出完全訪問權限的原因是屬於本地管理員組的用戶對交互式window station 及桌面擁有部分訪問權限有一部分USER API 調用可能會由於安全的原因無法運行
    最好的賭注是冒點風險使用本地管理員帳戶交互式用戶的訪問權限是基於組的登錄SID 而不是單個用戶的SID這意味著你可能有一個與交互式用戶相同帳戶的服務但是組的登錄SID是不同的允許一個為服務帳戶配置的服務具有對交互式window station及桌面訪問的唯一條件是為交互式用戶更改安全性以允許服務訪問
    現在你有了一個為交互式window station 及桌面配置的服務你還會碰上什麼樣的問題呢?第一個要考慮的問題就是當用戶退出時將會發生什麼如果服務是交互式的那麼是否缺省桌面被破壞了呢?不缺省桌面仍然存在唯一的區別是Winlogon 桌面現在是活動桌面當第二個用戶登錄系統時系統將會切換回缺省桌面用戶顯示的任何事物都可以被交互式用戶看到
    交互式服務和由交互式用戶啟動的進程之間的區別是當沒有用戶登錄時服務仍然可以運行這就導致了一些有趣的問題例如基於安全的原因當交互式用戶退出系統後操作系統竟全局原子表清為如果一個交互式服務依賴於存儲在全局原子表中的信息那麼當這個交互式用戶退出後信息全部消失另一個例子是自啟動交互式服務第一個用戶登錄之前缺省桌面還沒有創建這意味著在用戶登錄之前試圖顯示信息的交互式服務一定會出問題
    我想討論的最後一件事是交互式服務是暴露給交互式用戶的這個交互式用戶可以通過任務管理器殺死服務如果你有一個運行在LocalSystem 帳戶上的服務則交互式用戶將不具備必須的安全性來殺死你的進程假設你進入任務管理器列出所有的進程如果你點擊了End Process(終止進程)按紐來終止運行在LocalSystem帳戶上的進程時你將會得到意料之中的 Access is denied(訪問被拒絕) 消息框但是如果這個服務有一個顯示在外層的窗口你可以在任務管理器中列出所有應用程序當你點擊End Task(終止任務)按紐你就可以通過這個暴露的窗口殺死這個服務避免這種情況發生的一種方法就是讓你的窗口不要顯示在應用程序標簽中創建一個隱藏的窗口然後將可見的窗口作為這個隱藏窗口的兒子窗口
    記住最後的手段才是將你的服務交互化最好的選擇是創建一個交互式的客戶應用程序
    注冊表蜂箱
    蜂箱是操作系統用來存儲用戶注冊信息的在注冊表中存儲的注冊信息包括桌面應用程序打印和網絡設置系統將用戶的注冊信息備份在一個象蜂箱一樣的文件中Windows NT的每個用戶都分配一個蜂箱這個蜂箱能放在本地的或遠程的服務器上當一個用戶登錄到Windows NT機器上時系統把用戶的蜂箱裝載到注冊表中在HKEY_USERS 關鍵字下 注冊表關鍵字名稱代表蜂箱時基於用戶的SID的如果你通過regedtexe 或regeditexe檢測到HKEY_USERS下的注冊表關鍵字你將看到至少兩個子關鍵字 DEFAULT 和以S開頭的長字符串這是用戶的SID如果你還不清楚HKEY_CURRENT_USER代表的是什麼意思那麼我告訴你基本上說它是一個HKEY_USERS\users SID的映射通過regedtexe 或regeditexe可以得到驗證
    HKEY_USER\users SID和HKEY_CURRENT_USER的子關鍵字實際上是一模一樣的當一個應用程序是關於HKEY_CURRENT_USER的系統將會基於用戶的安全上下文把用戶映射到合適的蜂箱中包括用戶的SID它用來在HKEY_USERS下查找正確的蜂箱如果由於某種原因用戶的蜂箱沒有被裝載系統將會把用戶的蜂箱映射到DEFAULT
    現在看起來一切都好了但是還有很多問題首先服務要依賴用戶的注冊信息絕大多數應用程序在HKEY_CURRENT_USER中存儲用戶的注冊信息例如用戶的打印信息存儲在用戶的蜂箱中如果服務配置配置給不同的帳戶那這個服務將沒有任何打印信息不是所有的服務都使用DEFAULT 蜂箱如果一個服務配置給一個具有蜂箱的服務帳戶那麼 Service Control Manager將會裝載喲功能戶的蜂箱Windows NT 中已經增添了這一功能
    Service Control Manager不能做的一件事是為服務正確地准備用戶的環境環境變量存儲早用戶的蜂箱中服務繼承的唯一一個環境變量來自於Service Control Manager它的環境基於系統環境變量如果你改變系統環境變量那麼只有在重新啟動機器後所做的改變才能反映到服務中當系統環境變量改變時Service Control Manager不象其它系統進程一樣處理WM_SETTINGCHANGE 消息
    讓我們返回到LocalSystem 帳戶的情況中怎樣得到一個已合理配置的蜂箱呢?有這樣幾種選擇如果你有創建注冊關鍵字的應用程序的控制權就可以創建兩次關鍵字一次是為HKEY_CURRENT_USER另一次是為HKEY_USERS\Default另一種方法是判斷應用程序創建了那些關鍵字進行復制這種方法可以通過手工或編程實現
    如果你不想和注冊表攪在一起你可以用編程的方式裝載你自己的蜂箱如果你知道一個已經正確初始化的蜂箱的用戶名服務將基於用戶名決定蜂箱的位置通過RegLoadKey API裝載蜂箱然後扮演這個用戶
    問題是你需要一個進程標志來扮演這個用戶一個進程標志可以通過LogonUser API調用生成當然你需要一個用戶口令如果由於某種原因你所感興趣的用戶有一些進程運行在系統中服務將會列舉這些進程知道運行在目標用戶的安全上下文中的進程一旦一個進程被定位這個服務將通過調用OpenProcessToken獲得用戶標志在這時服務將用獲得標志扮演這個用戶
    結尾
    討論了在Windows NT服務和由交互式用戶啟動的應用程序之間的區別也討論了服務開發人員最關心的三個領域 Windows NT 安全 window stations 和桌面以及注冊表蜂箱這些信息將使Windows NT服務的開發變得容易一些並能應用於服務中使用的其它技術中


From:http://tw.wingwit.com/Article/os/xtgl/201311/9056.html
    推薦文章
    Copyright © 2005-2013 電腦知識網 Computer Knowledge   All rights reserved.