使您的应用程序支持 UAC






4.77/5 (33投票s)
2007年3月10日
7分钟阅读

387795
介绍如何使应用程序具备 UAC 感知功能,以避免虚拟化的陷阱。
引言
本文旨在介绍如何使应用程序具备 Vista 的 UAC 感知功能,并解释未能做到这一点的一些陷阱。通过使用嵌入式清单,可以使应用程序具备 Vista 感知功能。否则,Windows 可能会虚拟化对资源的访问,这会影响文件系统和注册表访问。

背景
正如您可能知道的,Vista 中的权限控制发生了根本性变化。这部分是由于认识到绝大多数 Windows 用户都以管理员账户登录其计算机,而不是使用推荐的权限更受限制的有限账户。在计算机上运行的应用程序会继承这些用户权限,因此通常是以完整的管理员权限运行的。这显然使得操作系统比最初设计的更容易受到恶意软件和病毒的攻击。
Windows 团队提出的解决方案是 UAC,即用户账户控制。有了 UAC,您以管理员身份登录无关紧要,所有账户都运行在相同的有限权限集下,除非明确允许,否则不允许访问受保护的资源。相反,应用程序现在必须向用户请求权限才能访问这些资源,这称为提升。
当一个被标记为需要管理员权限的应用程序首次启动时,或者当用户通过“以管理员身份运行”命令显式启动一个应用程序时,就会发生提升。这是应用程序唯一可以执行此操作的时间,因为应用程序在运行时无法稍后更改其级别并决定提升。要做到这一点,必须终止进程并以一组新的权限重新启动,请求用户授权。唯一的例外是,如果应用程序是从现有的提升进程启动的。在这种情况下,第二个进程将继承第一个进程的权限,用户不会收到提示。
提升请求采取对话框的形式,该对话框会占据整个桌面,并能防止进程间通信。用户必须选择允许应用程序获得所请求的提升权限,或者拒绝它。没有用户的交互,应用程序无法提升,这有助于保护桌面免受不安全资源访问。
UAC 的影响巨大,甚至会影响到任务托盘时钟这样看似无关紧要的东西。在 Vista 中,您会注意到无法通过简单地单击时钟来更改系统时间,这是一个管理员任务,需要提升。
虚拟化
UAC 引入带来的一些问题是,许多旧应用程序仍然需要访问现在受保护的文件夹和注册表设置;例如,那些将配置文件存储在*Program Files*目录而不是使用内置*Common AppData*路径的应用程序。这不再被允许,并会导致兼容性问题。
为了提高兼容性并允许旧应用程序在启用了 UAC 的环境中运行,操作系统会使用虚拟化。它会创建一个应用程序访问的文件系统和注册表资源的虚拟化视图,并在后台透明地将请求重定向到替代的沙箱位置。在大多数情况下,这可以使旧应用程序正常运行,但会带来性能开销,并且只是一个短期解决方案。这些应用程序最终需要重写,以消除对任何受保护资源的依赖,而是使用推荐的位置来存储应用程序和用户数据。
文件系统虚拟化
Real path
C:\Program Files\Foo\Foo bar\config.ini
Virtual path
C:\Users\<account>\AppData\Local\VirtualStore\Program Files\Foo\Foo bar\config.ini
注册表虚拟化
Real path
HKEY_LOCAL_MACHINE\Software\FooKey
Virtual path
HKEY_USERS\<User SID>_Classes\VirtualStore\Machine\Software\FooKey
不用说,开发人员永远不应在代码中引用这些虚拟位置。存储应用程序和用户数据的正确位置由环境变量和 Windows API 确定。例如,已经使用这些来读/写应用程序数据的旧应用程序到*Common AppData*文件夹,将不需要虚拟化。在 Vista 上,此路径将正确解析为*C:\ProgramData*。
清单
清单是一个可以嵌入到应用程序中的 XML 资源文件。在 UAC 方面,它有两个目的。首先,它告诉操作系统该应用程序是为 UAC 设计的,因此不应尝试虚拟化任何文件夹或注册表设置。如果应用程序在声明后仍然尝试访问受保护的资源,这些请求将只会失败,而不会虚拟化。另一件事是它允许应用程序声明它需要运行的权限级别,以及它是否需要提升。
示例清单文件
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
<security>
<requestedPrivileges>
<requestedExecutionLevel level="asInvoker" uiAccess="false"/>
</requestedPrivileges>
</security>
</trustInfo>
</assembly>
这些文件已经存在一段时间了,为 UAC 控制添加的新部分是requestedExecutionLevel
元素。level
属性可以是一个以下值
信号强度 | 描述 |
asInvoker |
不需要提升,使用其父进程的权限运行,无需请求提升。 |
highestAvailable |
请求其父进程可用的最高权限令牌。管理员账户将尝试提升到完全管理员级别,但标准账户只会请求提升到其自己的最高访问令牌集。 |
requireAdministrator |
需要提升到完全管理员权限。 |
大多数应用程序应该使用asInvoker
级别,因为这样每次运行时都不会提示用户提升,并且将使用标准的权限集来访问其所需的未受保护资源。只有需要访问受保护资源的应用程序才应使用更高的访问级别。
uiAccess
属性决定应用程序是否需要访问任何受保护的 UI 元素,例如系统对话框或更高级别的进程。只有经过签名的应用程序才能这样做,因为它需要额外的安全令牌。此值默认为false
。
添加清单的技术因技术和语言而异。对于 .NET 管理型应用程序,可以在生成后步骤或通过命令提示符使用 Microsoft MT.exe
工具来使用以下命令行。请注意,最后一个参数根据应用程序是库还是可执行文件而变化。
在此示例中,一个名为*Foobar.exe*的应用程序被添加了一个保存为*Foobar.exe.manifest*的清单文件。注意应用程序的 #1。
mt.exe -manifest "Foobar.exe.manifest" -outputresource:"Foobar.exe";#1
在此示例中,一个名为*Foobar.dll*的类库被添加了一个保存为*Foobar.dll.manifest*的清单文件。注意代码库的 #2。
mt.exe -manifest "Foobar.dll.manifest" -outputresource:"Foobar.dll";#2
其他注意事项
默认情况下,提升对话框是一个橙色框。要将其转换为友好的蓝色对话框,应用程序需要进行代码签名。请参阅进一步阅读以获取有关此内容的链接。
安装程序的提升过程有点过于复杂,无法在此详细介绍,但请注意,MSI 包上的requiresAdministrator
标志实际上并不提供完全的管理员权限。这实际上表现略有不同,并且运行的权限是完整权限的子集,除非您使用引导程序来获得完全提升。安装程序很少需要这些额外的令牌,因为安装程序的管理员权限通常已足够。
摘要
要使应用程序具备 Vista 的 UAC 感知功能,应将清单文件嵌入到可执行文件或代码库中,并包含requestedExecutionLevel
元素。这可以防止数据访问请求被虚拟化,并提高性能。它还确保了应用程序范围的应用程序数据不会仅限于当前用户范围。
在应用程序/用户范围内引用文件系统和注册表数据时,请确保使用相关环境变量来正确查找未受保护的资源。
如果您的应用程序需要访问受保护的资源,请将requestedExecutionLevel
元素设置为适当的值(非asInvoker
),并考虑使用 Authenticode 证书进行签名。这将确保用户被提示提升进程,并确保应用程序具有执行其任务所需的权限级别。