2010-03-11 62 views
14

我正在使用第三方Windows服務,它通過使用CreateProcessAsUser()運行腳本和可執行文件來處理一些自動化任務。由於UAC,我遇到了Windows Server 2008上的問題,並且通過API處理LUA提升的方式。從非交互式服務(win32/.net/powershell)啓動UAC提升進程

該服務作爲LocalSystem運行,但未啓用「與桌面交互」。這些進程以管理員組中的用戶身份運行,但不是管理員帳戶(它受到許多UAC限制的豁免)。所有的UAC默認設置都已到位。

我可以將任意命令或PowerShell代碼傳遞給該服務,但似乎無法「爆發」由服務啓動的非提升非交互式進程。

問題的癥結似乎是啓動升級過程的唯一(公共)API選項是帶有'runas'動詞的ShellExecute(),但據我所知,不能從一個非交互式的服務,或者你會得到像「這個操作需要一個交互式窗口站」的錯誤。

我發現的唯一的解決方法就是這裏所說的: http://www.eggheadcafe.com/software/aspnet/29620442/how-to-proper-use-sendinp.aspx

在Vista中,官方記錄的方式 提升處理僅使用 外殼API的ShellExecute(防爆)(未 的CreateProcess或CreateProcessAsUser)。 因此,您的應用程序必須調用 ShellExecute(Ex)才能啓動一個幫助程序 以提升調用SendInput。 此外,由於會話0 隔離,服務只能使用 CreateProcessAsUser或 CreateProcessWithLogonW(不能用 的ShellExecute(實施例))來指定 交互式桌面。

..我認爲沒有直接的方式來 產生從 窗口服務的升級過程。我們只能首先使用 CreateProcessAsUser或 CreateProcessWithLogonW將 未提升進程產生到用戶會話(交互式桌面) 會話中。然後在 的非升級過程中,可能會使用ShellExecute(Ex) 爲實際任務產生提升的 進程。

從.NET/PowerShell代碼做到這一點,它看起來像我不得不做一些精細的P/Invoke東西調用CreateProcessAsUser或CreateProcessWithLogonW由於.NET System.Diagnostics.ProcessStartInfo不具有相當於我可以設置爲「winsta0 \ default」的lpDesktop。我並不清楚LocalSystem是否有權調用CreateProcessAsUser或CreateProcessWithLogonW。

我也看了 http://blogs.msdn.com/alejacma/archive/2007/12/20/how-to-call-createprocesswithlogonw-createprocessasuser-in-net.aspxProcess.Start with different credentials with UAC on

基於這一切,我到達的結論是,有這樣做沒有直接的方法。我錯過了什麼嗎?這似乎並不像它應該那麼難。感覺就像UAC從來沒有設計過處理非交互式用例。

如果有任何微軟的人最終讀到這個,我注意到ShellExecute內部處理提升的方式是通過調用Application Information Service(AIS)。爲什麼對於通過一些Win32或.NET API可用的AIS進行相同的調用? http://msdn.microsoft.com/en-us/library/bb756945.aspx

對不起,跑了一會兒。感謝您的任何想法。

+0

反而說服務器核心不支持UAC。似乎證實我的評估。 http://blogs.technet.com/server_core/archive/2009/01/19/user-account-control-uac-and-server-core.aspx – 2010-03-11 16:37:01

+0

看到我的帖子在這裏解釋如何,特別是看看LinkedToken部分:http://brianbondy.com/blog/id/100/understanding-windows-at-a-deeper-level-sessions-window-stations-and-desktops – 2010-10-22 14:49:03

回答

16

打破會話零隔離的「官方」方法是使用終端服務API和CreateProcessAsUser()的組合來在用戶會話中啓動進程。在我以前的工作中,我們這樣做了,因爲我們需要在安裝下載的更新之前通過服務向用戶顯示一個對話框所以,至少在WinXP,Win2K3,Vista和Win7上我知道它可行,但我不要指望Win 2K8會有太大的不同。基本上,過程如下:

  1. 呼叫WTSGetActiveConsoleSessionId()獲取活動控制檯會話ID(非常重要,因爲交互式會話是總是會話1,即使在客戶端系統)。如果沒有活動用戶登錄到交互式會話(即,本地登錄到物理機器,而不是使用RDP),則此API還會返回-1
  2. 將來自先前API調用的會話標識傳遞給WTSQueryUserToken()以獲取表示登錄到控制檯的用戶的開放標記。
  3. 致電DuplicateTokenEx()將模擬令牌(從WTSQueryUserToken)轉換爲主令牌。
  4. 致電CreateEnvironmentBlock()爲流程創建一個新環境(可選,但如果您不這樣做,流程將不會有)。
  5. 將第3步中的主令牌傳遞給CreateProccessAsUser()的調用以及可執行文件的命令行。如果您從步驟#4創建了一個環境塊,則您也必須通過CREATE_UNICODE_ENVIRONMENT標誌(始終)。這可能看起來很愚蠢,但如果你不這樣做,API會失敗(使用ERROR_INVALID_PARAMTER)。
  6. 如果你創建了一個環境塊,那麼你需要調用DestroyEnvironmentBlock,否則你會產生內存泄漏。該過程在啓動時會分別獲得環境塊的副本,因此您只會銷燬本地數據。

瞧! Windows有一些內在的魔力,你會看到應用程序的啓動。不過,雖然這將從服務啓動和互動過程,但我不確定它是否會繞過UAC(但不要引用我的意思)。換句話說,除非註冊管理機構或內部清單聲明要這樣做,否則它可能不會啓動爲升級過程,即使如此,您仍然可能會得到UAC提示。如果您從第3步獲得的令牌是受限令牌,則可以使用AdjustTokenPrivileges()來恢復提升(完整)令牌,但不要在此引用我的話。但是,正如MSDN文檔中所述,請注意,無法對尚未擁有它們的令牌「添加」權限(例如,您不能通過使用AdjustTokenPrivileges將受限用戶令牌轉變爲管理員;底層用戶必須是管理員才能開始)。

在技術上可以從Win2K轉發所有這些。但是,從WinXP開始,Win2K缺少WTSGetActiveConsoleSessionId()WTSQueryUserToken() API(以及用於Win2K Pro的WTSEnumerateProcesses()),所以它才真正可行。你可以硬編碼0作爲會話ID(因爲在Win2K中情況總是如此),我想你可以通過枚舉正在運行的進程並複製其中一個令牌來獲得用戶令牌(它應該是一個擁有交互式SID存在)。無論如何,即使您未從服務設置中選擇「與桌面交互」,CreateProcessAsUser()在傳遞交互式用戶令牌時的行爲方式也是如此。它也比直接從服務直接啓動更安全,因爲該過程不會繼承神聖的LocalSystem訪問令牌。

現在,我不知道您的第三方應用程序在運行腳本/進程時是否執行了任何操作,但是如果您想從服務中執行此操作,那麼(與Vista或Win7一樣)克服會話0隔離的唯一方法)。

+3

沒有必要調用'DuplicateTokenEx'。 'CreateProcessAsUser'會運行從'WTSQueryUserToken'獲得的令牌的過程。您的回答非常詳細,但不回答「如何從服務啓動升級過程?(啓用UAC)」 – Ajay 2011-08-23 10:40:54

+1

確實沒有。這會給你一個受限的令牌。 – Joshua 2013-09-19 03:41:17

+0

有以下幾點需要注意:1)由於@Ajay提到'WTSQueryUserToken'已經返回一個主令牌,所以你可以跳過步驟3. 2)啓用UAC後,你實際上需要在步驟2之後得到所謂的鏈接令牌,你可以通過'TokenLinkedToken'信息類來調用'GetTokenInformation',但只有在查詢'TokenElevationType'時說明海拔是有限的。 3)如果你沒有創建一個環境塊,新的進程將具有創建過程的環境,這是你的服務 – 2017-12-07 21:09:43

1

根據您的使用情況,您可以做我所做的事情。我追蹤活動會話的winlogon進程並竊取它的標記。如果沒有活動會話(API返回-1),則在WINVER> = 6時使用1,否則爲0.這將在活動會話中產生SYSTEM。