UAC和权限提升提示模式

8

我已经阅读了几篇关于UAC和特权提升的问题,但我没有找到一个令人满意/全面的答案。

我的情况是:在Windows 6或更高版本中,当用户打开配置窗口时,如果需要特权提升才能完成任务,我必须在“确定”按钮上显示盾牌(BCM_SETSHIELD而且只能显示在确定按钮上。-- 我知道在Windows UI中,“管理员任务”始终会显示盾牌,即使UAC已被禁用,但客户有这个具体要求。

我已经起草了以下条件以便显示图标:

  1. 用户没有管理权限
    或者
  2. 当前进程的TOKEN_ELEVATION_TYPE == TokenElevationTypeLimited

条件#1很简单:如果用户没有管理权限,则无论UAC如何都需要提升权限。条件#2意味着用户具有管理权限,并且TOKEN_ELEVATION_TYPE的任何其他值都表示不需要提升权限。

真的那么简单吗?我有什么遗漏的吗?是否有关于此主题的文档或众所周知的模式?


1
如果我看到过一个好问题,那么这就是一个。 - badp
@badp:我已经思考和研究了一些,但它仍然让我感到困惑,因为它看起来太容易了...也许我没有考虑到一些边界条件。 - lornova
2个回答

3

我看到这个主题存在很多混淆,Kate的回答不正确且不完整。自从Vista以来,管理员可能已登录但他的进程不会自动运行提升。管理员有一个所谓的“拆分令牌”,这意味着可能为同一管理员用户运行某些进程并且其中一些运行提升,而其他进程则不运行提升。当管理员运行未提升的进程时,他的令牌中的某些特权已被删除。它不再像XP那样,所有进程都运行提升或未提升。

从www.sysinternals.com安装Process Explorer并启用“Integrity Level”列。如果你在那里看到“Medium”,这个进程就不会运行提升。如果你在那里看到“High”,这个进程将运行提升。如果进程以“High”完整性级别运行,则无需UAC提示即可启动另一个进程。

当UAC完全关闭时,所有进程都运行“High”,所以永远不需要提升。UAC可以在下面关闭。

HKLM\Software\Microsoft\Windows\CurrentVersion\Policies\System

设置键 "EnableLUA"。更改此设置需要重新启动。

但这里还有一个尚未提及的要点。 在控制面板中,可以配置“无需提示即提升”。在这种情况下,管理员用户可以从另一个非提升进程启动提升进程,并且不会出现 UAC 提示。

此设置存储在相同的注册表路径下,键名为 "ConsentPromptBehaviorAdmin"。

对于所有非管理员用户,存在键 "ConsentPromptBehaviorUser",但这只改变行为,无法关闭提升。非管理员用户始终会收到 UAC 提示。(如果 UAC 没有完全关闭)

如何知道您的进程是否正在以提升方式运行: 调用 OpenProcess(),然后调用 OpenProcessToken(),再调用 GetTokenInformation(TokenElevation)

而要获取完整性级别,则调用 GetTokenInformation(TokenIntegrityLevel),然后调用 GetSidSubAuthority()

因此,如果您只想在确实需要提升时显示您的图标,则必须检查您的进程是否正在以提升方式运行,并另外检查这些注册表键,并且您必须知道用户是管理员还是普通用户。这涉及到几行代码,我会考虑始终显示此图标以保持简单。

请注意,API IsUserAnAdmin() 已弃用。自 Vista 以来,不再使用它。现在要检查用户是否属于管理员组需要更多的代码。


如果我打开了UAC,如何找到PE可执行文件中触发UAC的内容?除了1.可执行文件的名称;2.该可执行文件的清单之外,还有什么方法吗? - Sajuuk
正确。如果文件名包含“Setup”或“Install”,Windows会以提升权限的方式启动进程。另外,清单可能定义需要提升权限。但在启动进程之前找到这一点可能会失败。想象一下一个进程,当它发现自己没有以提升权限的方式运行时,通过ShellExecute(使用Verb="runas")重新启动自己以提升权限。 - Elmue
这不是预期的行为吗?所有特权修改仍然被权限拒绝。 - Sajuuk
我不理解你的评论。 - Elmue

3
你说得对。大多数人只会在按钮运行时提升权限时才使用屏蔽,但正确的做法是如果按钮会导致提升权限,则应该使用屏蔽(即如果您已经提升了权限,则除非您费力地启动非提升进程并屏蔽它,否则您启动的所有内容都将保持提升状态,并在UAC关闭时屏蔽它)。
好消息是,如果管理员组中的某个人以非提升方式(在UAC下)运行应用程序,则在询问他们是否为管理员时,您将得到false的返回值。因此,我认为您可能只需要进行这一个测试就可以了。

1
实际上,即使应用程序已被提升(或者UAC已禁用),放置盾牌也有合理性:这样用户将立即知道该按钮执行"管理任务"。我支持这种UI风格,但客户不同意。 - lornova
那么你认为我只能依赖第一项检查吗? - lornova
我认为你应该编写代码为“如果你不是管理员,就戴上盾牌”,然后运行所有测试用例以查看是否足够。我的怀疑是它会的。 - Kate Gregory
1
当UAC启用且您未以提升权限运行时,您将拥有一个受限令牌;此令牌已移除管理员组,因此第一次检查就足够了。 - Luke
当您询问他们是否为管理员时,您将得到false。您指的是哪个API?如果用户属于管理员组,则此事实不会受任何影响。他是管理员还是普通用户都无所谓,无论进程是否运行提升。如果您指的是IsUserAnAdmin() API:自Vista以来,此API已被弃用,不再使用。 - Elmue

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接