转载自:https://blog.csdn.net/qq_22167989/article/details/79425776
用户帐户控制数据重定向
为了确保您的应用程序已经针对Windows 7做好了准备(兼容性),我将开始针对我们在“ 您的应用程序为Windows 7 RTM做好准备了吗?”中讨论的一些兼容性问题提供额外的信息。本文的重点是UAC虚拟化,也就是所谓的数据重定向。
这是说什么的?
截至现在,很多应用程序在设计上依然会向Program Files、Windows目录,或系统盘(通常是C盘)根文件夹写入文件。有些应用程序在设计上需要更新Microsoft® Windows注册表值,尤其是位于HKLM/Software下的值。但这就存在一个问题:这些文件或注册表值可能无法创建或更新。您可能会问了,“这是怎么回事?我的应用程序运行正确,没有出现任何错误,那么我的文件在哪里?”
明确来说,您可能会遇到下列一种或多种现象:
- 您的应用程序写入到Program Files、Windows目录,或系统根(通常是C)文件夹,但您无法在上述位置找到这些文件。
- 您的应用程序写入到Windows注册表,尤其是HKLM/Software,但您看不到这些注册表内容的更新。
- 您切换到其他用户帐户,而您的应用程序无法找到写入到Program Files、Windows目录,或系统根(通常是C)文件夹下的文件,或者只能找到这些文件的老版本。
- 在打开或关闭用户帐户控制(UAC)后,您的应用程序无法在Program Files或Windows目录下找到所需的文件。
如果您的应用程序也遇到这样的问题,则通常是由于UAC虚拟化(通常也叫做数据重定向)所导致的。下文将向您提供有关确定此类应用程序兼容性问题所需要知道的所有信息,并会提供一些解决方案,同时简要介绍有关该兼容性问题的一些本质特征。
真实问题:UAC虚拟化
在Windows Vista之前,通常人们使用管理员身份运行应用程序。因此,应用程序可以随意读取和写入系统文件和注册表键。如果标准用户运行此类应用程序,可能会因为无法访问而失败。Windows Vista通过将写入(以及后续的文件或注册表操作)重定向到每个用户配置文件内可写入位置的方法,改善了此类应用程序兼容性问题。
例如,如果某个应用程序尝试写入到C:\Program Files\Contoso\Settings.ini,而用户没有写入到该目录(Program Files)的权限,写入操作将会被重定向到C:\Users\Username\AppData\Local\VirtualStore\Program Files\Contoso\settings.ini。如果某个应用程序尝试写入到注册表的HKEY_LOCAL_MACHINE\Software\Contoso\位置,则会被自动重定向到HKEY_CURRENT_USER\Software\Classes\VirtualStore\MACHINE\Software\Contoso或HKEY_USERS\UserSID_Classes\VirtualStore\Machine\Software\Contoso。
下图所示的就是Windows中两个组件的虚拟化流程:文件虚拟化,以及注册表虚拟化:
要了解有关UAC虚拟化,以及UAC技术的详细信息,请参考“Windows Vista中心的UAC技术”: http://msdn.microsoft.com/en-us/library/bb756960.aspx。
解决方案
虚拟化技术的目的是帮助现有程序改善应用程序兼容性问题,针对Microsoft Windows 7设计的新应用程序不应当执行对重要系统位置的写操作,因此也不应当依赖虚拟化技术容忍不恰当的应用程序行为。在开发应用程序时,一定要总是以标准用户的特权来考虑,而不应该假定应用程序就一定要使用管理员特权运行。同时对应用程序进行测试时,也需要使用标准用户特权,而不应该使用管理员特权。
如果在Windows 7 之前开发的应用程序遇到了UAC虚拟化问题,请重新设计您的应用程序,将文件写入到恰当的位置。在对现有代码针对Windows 7进行修改时,您应当:
- 确保在运行时,应用程序只将数据存储到计算机上%alluserprofile%目录下的每用户位置,并且设置了恰当的访问控制列表(ACL)设置。有关ACL的详细信息,请参考 访问控制列表。
- 确定要将数据文件写入到的文件夹。被所有用户使用的常规数据应当写入到被所有用户共享的全局位置,所有其他数据则应当写入到每用户位置。
- 常规数据文件包括但不限于:日志文件、设置文件(INI/XML)、保存的应用程序状态,例如游戏进度等。
- 用户文档则要区别对待,这些内容应当保存到文档文件夹(或其他针对当前用户的位置)。
- 确保在决定相应位置时,没有使用硬编码的路径。相反,此时应当使用下列某种编程模型或API获取特定Windows已知文件夹的准确路径:
- C/C++原生应用程序:使用 SHGetKnownFolderPath函数获取由已知文件夹的 KNOWNFOLDERID所指定的完整路径,这种GUID可永久性代表下列可能需要用到的已知位置:
FOLDERID_ProgramData – 所有用户的共享程序数据目录。
FOLDERID_LocalAppData – 每用户的程序数据目录(无法漫游)。
FOLDERID_RoamingAppData – 每用户的程序数据目录(可漫游)。 - 受管代码:可使用 System.Environment.GetFolderPath函数,GetFolderPath可永久性代表下列可能需要的已知位置:
Environment.SpecialFolder.CommonApplicationData –所有用户的共享程序数据目录。
Environment.SpecialFolder.LocalApplicationData –每用户的程序数据目录(无法漫游)。
Environment.SpecialFolder.ApplicationData –每用户的程序数据目录(可漫游)。 - 如果上述方法都无法使用,请使用下列环境变量:
%ALLUSERSPROFILE% –所有用户的共享程序数据目录。
%LOCALAPPDATA% –Vista之后系统的每用户的程序数据目录(无法漫游)。
%APPDATA% – Vista之后系统的每用户的程序数据目录(可漫游)。
- C/C++原生应用程序:使用 SHGetKnownFolderPath函数获取由已知文件夹的 KNOWNFOLDERID所指定的完整路径,这种GUID可永久性代表下列可能需要用到的已知位置:
决定最适合解决方案的步骤
至此,我们已经介绍了与UAC虚拟化有关的特征,并解释了为什么要进行重定向,以及建议了一些解决方案。本节将介绍为了确定实际问题,以及确定解决方法所需要进行的测试和操作。
测试1:
- 使用标准用户特权启动该应用程序。
- 运行需要向任何受保护文件夹,例如Program Files或系统根(C:\)执行写入操作的功能。
- 预期的结果:应用程序“成功”写入了这些受保护文件夹,然而在这些位置找不到所写入的文件。
- 结论:这意味着UAC数据重定向功能已经将文件重定向到其他位置。
测试2:
- 使用Windows资源管理器在VirtualStore文件夹中搜索文件。
- VirtualStore文件夹位于配置文件中,保存了被重定向的文件。
- VirtualStore文件夹的名称和位置在后续版本的Windows中可能会变化。
- 首先尝试在%localappdata%\VirtualStore下寻找文件。
- 如果找不到,可尝试在命令行下运行dir %userprofile%\yourfile.dat /s /a命令(通常位于C:\Users\<user name>\AppData\Local\VirtualStore下)。
- 预期的结果:应当能在虚拟存储,或子文件夹中找到您的文件。
- 结论:这是UAC虚拟化技术发挥作用的证据。
测试3:
- 使用管理员帐户登录,并使用管理员特权启动您的应用程序。
- 要使用管理员特权启动应用程序,请用鼠标右键单击程序可执行文件,选择以管理员身份运行。
- 当使用管理员特权启动应用程序后,虚拟化技术将被关闭,而应用程序也有了足够的特权写入受保护的文件夹。
- 不要以来让程应用程序要求管理员特权这种方法绕过虚拟化技术,这样做会使得系统更容易被攻击,使得应用程序无法以受限或标准用户特权运行,并且会导致大量令人厌烦的UAC提升提示。
- 预期结果:该应用程序成功将文件写入受保护文件夹,可以在相应位置找到文件。
- 结论:使用管理员特权运行应用程序将关闭虚拟化技术并直接分配权限。
测试4:
- 启动Process Monitor(ProcMon)
- 要了解Process Monitor的详细信息,请参考Microsoft TechNet上的 Windows Sysinternals Process Monitor网站。
- 在上手实验室中,我们将介绍有关Process Monitor的详细使用方法。
- 配置筛选器只显示文件操作,以及由您的应用程序的进程所执行的操作。
- 在启动Process Monitor后,会自动打开Process Monitor Filter对话框。
- 向筛选器中添加下列语句:"Column=Process Name, Relation=is, Value=YourApp.exe, Action=Include"
- 要再次打开Process Monitor Filter对话框,可单击工具栏上的
按钮。
- 单击OK后,配置Process Monitor只记录文件事件,为此需要将任务栏按钮设置成下列结果:
- 按下CTRL-X清空日志,按下CTRL-E打开或关闭记录功能。
- 预期结果:您将看到文件操作的结果首先显示为REPARSE,下一行(显示为SUCCESS)则是真正的重定向操作:
- 在结果中,双击代表结果为REPARSE的操作行,然后打开Stack选项卡查看进行该操作时的堆栈调用情况:
- 每个堆栈帧左侧的粉红色K和蓝色U代表着该堆栈帧是否属于内核模式(K)或者用户模式(U),在本例中,我们只需要关注用户模式的堆栈帧。
- 在本例中,BrokenAppNative.exe的SaveFile函数(第21帧)执行的操作最终被重定向处理。
- 另外您还可以配置Symbol以便获得更有意义的显示结果,要了解与Symbol的配置有关的详细信息,请参考 Windows调试工具网站。
- 结论:测试证明UAC虚拟化确实生效了,并且可以从中了解您的应用程序的哪些操作需要调整。
任务5:
- 为您的应用程序添加包含UAC指令的清单。
- 这样您的应用程序将可感知UAC,并将禁用UAC虚拟化。
- 清单是一种XML文件,开发人员可将其作为资源嵌入到DLL或.exe文件,但也可以是一个独立文件,名称为YourApp.exe.manifest或YourDLL.dll.manifest。
- 清单中可包含大量信息,这些信息通常与应用程序兼容性有关,例如需要加载的Visual C++运行时环境的准确版本,要加载的Common Controls Library版本,以及UAC设置等。
- 要了解清单中UAC设置的详细信息,请参考 Windows Vista开发者故事:创建和嵌入应用程序清单(UAC)。
- 预期结果: 应用程序现在将无法写入任何受保护文件夹,会遇到“访问拒绝”错误。
- 这是好事,因为UAC数据虚拟化并没有生效。
- 作为开发人员,您应当能意识到这一点(因为您在清单中将该应用程序标记为可感知UAC的了),并且尽量避免写入任何受保护位置。
- 结论: Windows会因为应用程序无法感知UAC而启用虚拟化,将您的应用程序标记为可感知UAC的即可禁用虚拟化。如果在标记为可感知UAC的情况下您的应用程序依然尝试写入受保护位置,则会遇到访问被拒绝的错误。
上手实验室和参考资料
您可以 下载这篇文档,这篇文档详细介绍了UAC虚拟化,另外还有关于 该话题的两个上手实验室,一个针对受管代码,一个针对原生代码,详情请参考 这里。
工具
为了检测到UAC重定向,我们使用了下列工具:
- Process Monitor,这是一个免费的高级工具,由Microsoft提供,可用于监控和记录文件系统、注册表、网络,以及进程的活动。
- 要了解有关Process Monitor的详细信息,请参考Windows Sysinternals网站 Process Monitor页面。
- 下载Process Monitor: Microsoft TechNet
- Standard User Analyzer,属于Microsoft Application Compatibility Toolkit的一部分,这是一个免费工具,可监控特定应用程序的资源(文件和注册表等)的使用情况,并确定可能导致标准用户遇到问题的活动。
- 要了解有关Standard User Analyzer的详细信息,请参考Microsoft TechNet网站" Standard User Analyzer"。
- 要获得Standard User Analyzer,请 下载Microsoft Application Compatibility Toolkit。
参考资源
- Windows Vista应用程序兼容性:UAC,标准用户的变化: http://msdn.microsoft.com/en-us/library/bb963893.aspx
- Windows Vista中的常见文件和注册表虚拟化问题: http://support.microsoft.com/kb/927387
- Windows Vista中全新的UAC技术: http://msdn.microsoft.com/en-us/library/bb756960.aspx
- 深入介绍Windows Vista用户帐户控制: http://technet.microsoft.com/en-us/magazine/2007.06.uac.aspx