2013年6月24日 星期一

自訂應用程式的 UAC 執行層級

在專案屬性中的 "組態屬性、連結器、資訊清單檔、UAC 執行層級" 中共有此 3 種屬性 asInvoker、highestAvailable、requireAdministrator 可以選擇,這三種層級的詳細說明可以參考這裡:Embeds UAC information in manifest

此設定選項預設的值為 asInvoker 代表此應用程式的權限等同於啟動應用程式的身份層級,如果應用程式中做了一些需要 Administrator 權限才能做的事,而使用者又不是 Administrator 群組的身份時,會發生應用程式雖然可以執行,但有些行為無法被正確完成。

大多數情況下我們會覺得無法執行的部份發生 Exception 其實是好事,這樣子是有易於 Debug 的,反之若沒有發生 Exception,且開發者本身也沒意識到這些指令是需要管理者權限而沒有檢查是否執行成功的回傳值,會導致後續不知道在何時發生了不正常的行為,舉個例子來看,以下程式碼片段在 Registry 中的 HKEY_LOCAL_MACHINE 建立了一個值,在這幾行程式碼下不會發生任何的 Exception 所以即便 RegOpenKey 或 RegSetValue 的回傳值非 ERROR_SUCCESS 的情況下,用戶還是可以一直用下去,直到哪天發現哪裡怪怪的,再來追查原因的時後,大概想破頭才想得到是機碼沒有寫成功。

HKEY hKey(0);
RegOpenKey(HKEY_LOCAL_MACHINE, _T("SOFTWARE\\Microsoft\\Internet Explorer\\Main\\FeatureControl\\FEATURE_BROWSER_EMULATION"), &hKey);
DWORD dwValue(10000);
RegSetValueEx(hKey, _T("WebBrowserSample.exe"), NULL, REG_DWORD, (BYTE*)&dwValue, sizeof(DWORD));
RegCloseKey(hKey);

寫入機碼到 HKEY_LOCAL_MACHINE 是需要 Administrator 權限的,所以上述情況很容易在使用者非管理者群組時發生問題,加個判斷檢查才是正確的寫法,例如

HKEY hKey(0);
if(ERROR_SUCCESS == RegOpenKey(HKEY_LOCAL_MACHINE, _T("SOFTWARE\\Microsoft\\Internet Explorer\\Main\\FeatureControl\\FEATURE_BROWSER_EMULATION"), &hKey))
{
DWORD dwValue(10000);
if(ERROR_SUCCESS != RegSetValueEx(hKey, _T("WebBrowserSample.exe"), NULL, REG_DWORD, (BYTE*)&dwValue, sizeof(DWORD)))
{
// 提示寫入失敗
}
}
RegCloseKey(hKey);

當然要避免寫入失敗,最理想的方法還是主動提高應用程式的執行權限,上面有貼一篇 MSDN 說明三種層級的說明,我再簡單的將我測試的結果描述一下,全部都以登入一般帳戶為例子

asInvoker:應用程式的權限層級相當於啟動應用程式的處理序,例如 A 程序啟動 B 程序,B 的層級就與 A 的層級相同,如果由使用者手動啟動,則等於使用者的帳戶權限層級。

highestAvailable:應用程式的權限層級會與從使用者帳戶層級和啟動它的程序中挑出最高的層級,例如使用者為管理者,有個一般權限的 A 啟動了 B,則 B 的層級會是管理者層級,因為管理者層級較高。或是使用者為一般帳戶執行了一個有數位簽章的安裝檔,則此安裝檔在安裝完畢後所啟動的應用程式會是超過使用者帳戶的權限層級。

requireAdministrator:開啟此應用程式時一律要求要獲得管理者帳戶認證,一般用戶開啟則跳帳號密碼認證,管理者開啟即跳此為管理者權限詢問是否開啟並允許修改電腦設定。

修改了 UAC 層級後雖然能做更多的事,但是每次用戶一打開應用程式都要認證或是確認提示也有點麻煩,所以在這方面我比較建議將需要 Administrator 權限的部份寫在安裝的流程中,因為安裝檔的執行權限是很高的,如此應用程式的執行檔本身就設為 asInvoker 即可,以減少跳出訊息的流程。

沒有留言:

張貼留言