Windows Vista如何以SYSTEM權(quán)限啟動進(jìn)程(1)(圖)
SYSTEM帳戶啟動的實(shí)質(zhì)
其實(shí)不管用哪種方法,其本質(zhì)都一樣。都是利用SYSTEM登錄會話里已有的某個進(jìn)程A,幫助我們創(chuàng)建一個進(jìn)程B,進(jìn)程B會自然而然地運(yùn)行在SYSTEM登錄會話里-從而具有SYSTEM權(quán)限。
這里提到登錄會話(Logon Session)的概念,這個概念比較抽象,甚至連MSDN里都有點(diǎn)語焉不詳。這里我們且不去管它(將會在后續(xù)的文章里給大家細(xì)述這個抽象概念)。只需要了解:登錄會話用來代表特定的安全主體,代表該安全主體的一次登錄實(shí)例。
每個進(jìn)程,都必須運(yùn)行在特定的登錄會話里。這里就有一個問題,在用戶登錄之前,Windows系統(tǒng)里已經(jīng)運(yùn)行了一些進(jìn)程,這些進(jìn)程顯然也應(yīng)該運(yùn)行在登錄會話里,這就是所謂的SYSTEM登錄會話,它所代表的安全主體就是SYSTEM帳戶。
在Windows的安全機(jī)制里,特定登錄會話里的某個進(jìn)程所啟動的其他進(jìn)程,也會運(yùn)行在該登錄會話里,從而繼承安全上下文。
《以System帳戶身份運(yùn)行應(yīng)用程序的三種辦法》這篇文章所描述的方法,都是運(yùn)用這種原理。例如借助At命令以SYSTEM帳戶身份啟動進(jìn)程,實(shí)際上是由Task Scheduler服務(wù)啟動的,而Task Scheduler服務(wù)所在的進(jìn)程svchost正是運(yùn)行在SYSTEM登錄會話,如附圖所示。
圖中所示的Task Scheduler服務(wù)的進(jìn)程svchost所在的登錄會話ID(Logon Session ID)是0x0-3e7,這就是代表SYSTEM登錄會話。
用Psexec命令,道理也一樣,實(shí)際上啟動進(jìn)程的是PsexecSvc服務(wù),該服務(wù)的進(jìn)程運(yùn)行在SYSTEM登錄會話。
如何讓用戶能夠看到SYSTEM下的進(jìn)程? 在Windows 2000/XP下,這個不是什么問題。然而在Windows Vista下問題就來了。如果企圖用AT命令啟動某個Local SYSTEM進(jìn)程,就會警告說不能和用戶進(jìn)行交互,哪怕加上/Interactive參數(shù)也不行! 原來在Windows Vista下,存在一個會話0隔離的問題。而AT命令所對應(yīng)的Task Scheduler服務(wù)運(yùn)行在會話0,而會話0是不能和用戶進(jìn)行交互的。 盆盆評注:這里要注意,會話和登錄會話,是兩碼事。具體的介紹,敬請期待后續(xù)的文章。 原來在會話0里,并沒有WinSta0這個窗口站。天哪,又來了一個窗口站的概念,嗯,先不用管它,這里只需理解,窗口站用來保護(hù)進(jìn)程的用戶界面。只有WinSta0這個特殊的窗口站才可以接受用戶的鼠標(biāo)、鍵盤事件,才能和用戶進(jìn)行交互。 在Windows系統(tǒng)里,如果沒有特別指定,SYSTEM登錄會話里的進(jìn)程,將會默認(rèn)運(yùn)行在Service-0X0-3E7$窗口站里,所以無法和用戶進(jìn)行交互。 所以很顯然,要讓以SYSTEM權(quán)限運(yùn)行的進(jìn)程,能夠和用戶進(jìn)行交互,必須滿足以下條件: 1. 必須不能運(yùn)行在會話0下,例如可以運(yùn)行在當(dāng)前用戶所在的會話下(例如會話1、2等) 2. 該SYSTEM進(jìn)程必須運(yùn)行在WinSta0窗口站。 對于開發(fā)人員來說,推薦參考Leo Jiang朋友的Blog文章,以便了解如何通過編程的方法,創(chuàng)建運(yùn)行在WinSta0里的Local SYSTEM進(jìn)程。 而對于IT Pro來說,我們可以借助Mark Russinovich所寫的Psexec工具,讓任意指定的進(jìn)程運(yùn)行在SYSTEM權(quán)限下。 而對于Windows Vista來說,其實(shí)有好些Local SYSTEM進(jìn)程本身運(yùn)行在WinSta0下(非會話0),例如Winlogon進(jìn)程、某個csrss進(jìn)程,還有我們大家很熟悉的UAC提示對話框(consent進(jìn)程),都運(yùn)行在SYSTEM下,但是可以和用戶進(jìn)行交互。 google_protectAndRun('render_ads.js::google_render_ad', google_handleError, google_render_ad);