﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>C++博客-gxhzippo</title><link>http://www.cppblog.com/gxhzippo/</link><description /><language>zh-cn</language><lastBuildDate>Sat, 11 Apr 2026 09:25:17 GMT</lastBuildDate><pubDate>Sat, 11 Apr 2026 09:25:17 GMT</pubDate><ttl>60</ttl><item><title>对话框及其子控件的内部创建过程之详细分析 </title><link>http://www.cppblog.com/gxhzippo/archive/2012/04/26/172780.html</link><dc:creator>在路上2011</dc:creator><author>在路上2011</author><pubDate>Wed, 25 Apr 2012 16:56:00 GMT</pubDate><guid>http://www.cppblog.com/gxhzippo/archive/2012/04/26/172780.html</guid><wfw:comment>http://www.cppblog.com/gxhzippo/comments/172780.html</wfw:comment><comments>http://www.cppblog.com/gxhzippo/archive/2012/04/26/172780.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/gxhzippo/comments/commentRss/172780.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/gxhzippo/services/trackbacks/172780.html</trackback:ping><description><![CDATA[创建非模态<span style="text-decoration: underline;"><span style="color: #ff0000;">对话框</span></span>时，首先程序最先开始调用CreateDialogIndirectParam函数来创建对话框&nbsp;&nbsp;， <br />&nbsp;在CreateDialogIndirectParam中调用CreateWindowEx函数创建<span style="text-decoration: underline;"><span style="color: #ff0000;">对话框</span></span>主框架， <br />这时 CreateWindowEx函数发出WM_CREATEX消息，开始调用OnCreate函数。 <br /><span style="color: #ff0000;">注意这时所有<span style="text-decoration: underline;"><span style="color: #ff0000;">对话框</span></span>的子控件都还没创建 ，所以在OnCreate函数中对子控件所作的任何操作都会导致内存非法访问。</span> <br />&nbsp;OnCreate函数成功返回后，创建主<span style="text-decoration: underline;"><span style="color: #ff0000;">对话框</span></span>的CreateWindowEx接着返回。 <span style="color: #cc0000;">注意：这时才开始创建<span style="text-decoration: underline;"><span style="color: #ff0000;">对话框</span></span>子窗口控件。</span> <br />&nbsp;接着根据<span style="text-decoration: underline;"><span style="color: #ff0000;">对话框</span></span>模板中子控件的信息，开始依次调用CreateWindowEx创建子控件， <br />&nbsp;比如这时，<span style="text-decoration: underline;"><span style="color: #ff0000;">对话框</span></span>模板中的子控件的位置和大小信息将作为CreateWindowEx函数的参数被传进函数， 子控件的默认位置，就在这时被确定下来了。 <br />这里<span style="color: #ff0033;"><span style="text-decoration: underline;"><span style="color: #ff0000;">对话框</span></span>模板中有几个子控件，CreateDialogIndirectParam就将调用几次CreateWindowEx函数。</span> <br />等所有子控件创建完毕后，CreateDialogIndirectParam发出WM_INITDIALOG消息， 调用<span style="text-decoration: underline;"><span style="color: #ff0000;">对话框</span></span>的OnInitDialog的函数， <br />这时仍需注意： 否则极易出错，比如这时你将<span style="text-decoration: underline;"><span style="color: #ff0000;">对话框</span></span>基类的OnInitDialog函数注释掉， 那么这时你对子控件的操作将会失败， <br />&nbsp;因为在<span style="text-decoration: underline;"><span style="color: #ff0000;">对话框</span></span>基类的OnInitDialog函数中调用了UpdateData，UpdateData又调用了DoDataExchange，DoDataExchange又调用了DDX_Control，来子类化控件。 <br />&nbsp;<span style="color: #ff3300;">所以如果<span style="text-decoration: underline;"><span style="color: #ff0000;">对话框</span></span>基类的OnInitDialog函数没有得到调用，控件就无法完成子类化， </span>（Toto我猜想你昨天说的控件句柄为NULL，估计是这种情况）， <br />那么这时如果你通过控件的包装类来操作子控件比如MoveWindow移动子控件， <br />你会发现 控件句柄为NULL当然还有可能是你把<span style="text-decoration: underline;"><span style="color: #ff0000;">对话框</span></span>基类的OnInitDialog函数放在了后面来调用了， <br />在这个函数之前操作 子控件，那么也会出现控件句柄为NULL的现象。 <br />&nbsp;最后OnInitDialog返回后,CreateDialogIndirectParam接着返回，就进入模态循环了~~ 完毕！<img src ="http://www.cppblog.com/gxhzippo/aggbug/172780.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/gxhzippo/" target="_blank">在路上2011</a> 2012-04-26 00:56 <a href="http://www.cppblog.com/gxhzippo/archive/2012/04/26/172780.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>WindowNT</title><link>http://www.cppblog.com/gxhzippo/archive/2012/04/26/172779.html</link><dc:creator>在路上2011</dc:creator><author>在路上2011</author><pubDate>Wed, 25 Apr 2012 16:55:00 GMT</pubDate><guid>http://www.cppblog.com/gxhzippo/archive/2012/04/26/172779.html</guid><wfw:comment>http://www.cppblog.com/gxhzippo/comments/172779.html</wfw:comment><comments>http://www.cppblog.com/gxhzippo/archive/2012/04/26/172779.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/gxhzippo/comments/commentRss/172779.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/gxhzippo/services/trackbacks/172779.html</trackback:ping><description><![CDATA[<div id="cnblogs_post_body"><pre>WindowsNT,WindowsNewTechnology, 微软公司的网络视窗操作系统</pre> <p align="left">NT是微软纯32位内核技术的一个叫法。 </p> <p align="left">WINDOWS NT （包括WORKSTATION  和SERVER）是一个32位的操作系统。它是有先使用权的，多任务的操作系统，这意味着操作系统控制CPU时间的分配，而不是控制应用程序的分配；还意   味着能从挂起操作系统来终止一个应用的运行。NT支持多CPU。多CPU提供真正的多任务，使用对称的多处理，意味着处理器分享所有任务，不象非对称的多  处理那样让操作系统使用一个CPU，而让应用程序用另一个CPU。NT也是一个容错的操作系统，32位的应用在自己的虚拟内存地址空间（4GB）上运  行，这意味着一个应用不会干扰另一个应用的内存空间。 <br /> 不象早期的WINDOWS版本（例如Windows for Workgroups 和Windows95），NT是一个完全的操作系统，而不是DOS的一个附加产品。 <br /> <br /> NT支持不同的CPU：Intel x86, IBM PowerPC (不支持 NT5.0) and DEC Alpha. <br /> <br /> NT的另一个主要的附加功能是他的安全性，因为它有一个专门的NT文件系统（NTFS），允许在文件和目录上设置许可权限。 <br /> xp和2000是nt的后续产品。是介于NT结构开发的。</p> <p align="left">&nbsp;</p> <p align="left">Windows NT是基于<a href="http://baike.baidu.com/view/108542.htm" target="_blank">OS/2</a> NT的基础编制的。OS/2是由微软和<a href="http://baike.baidu.com/view/1937.htm" target="_blank">IBM</a>联  合研制，分为微软的Microsoft OS/2 NT与IBM的IBM  OS/2。协作后来不欢而散，IBM继续向市场提供先前的OS/2版本，而微软则把自己的OS/2 NT的名称改为Windows  NT，即第一代的Windows NT 3.1。Windows NT是纯32位<a href="http://baike.baidu.com/view/880.htm" target="_blank">操作系统</a>，采用先进的NT核心技术。NT即新技术(New Technology)。</p> <p align="left">Windows NT是Microsoft推出的面向<a href="http://baike.baidu.com/view/7977.htm" target="_blank">工作站</a>、<a href="http://baike.baidu.com/view/813.htm" target="_blank">网络服务器</a>和大型计算机的网络操作系统，也可做PC操作系统。它与通信服务紧密集成，提供文件和打印服务，能运行客户机／服务器应用程序，内置了Internet／Intranet功能，已逐渐成为企业组网的标准平台。</p> <p align="left"><strong>1.Windows NT</strong><strong>的主要特点</strong><br /> <br /> &#9312;32位操作系统,多重引导功能，可与其它操作系统共存。 <br /> <br /> &#9313;实现了&#8220;抢先式&#8221;多任务和多线程操作。 <br /> <br /> &#9314;采用SMP（对称多处理）技术，支持多CPU系统。 <br /> <br /> &#9315;支持CISC（如Intel系统）和RISC（如Power PC、R4400等）多种硬件平台。 <br /> <br /> &#9316;可与各种网络操作系统实现互操作。如：UNIX、Novel Netware、Macintosh等系统；对客户操作系统提供广泛支持，如MS-DOS、Windows、Windows NT <br /> <br /> Workstation、UINX、OS／2、Macintosh等；支持多种协议：TCP／IP、NetBEUI、DLC、AppleTalk、NWLINK等。 <br /> <br /> &#9317;安全性达到美国国防部的C2标准。</p> <p align="left"><strong>2.Windows NT</strong><strong>的两个版本</strong><br /> <br /> Windows NT的两个版本分别是Windows NT Workstation 和Windows NT Server 。Windows NT <br />  Workstation的设计目标是工作站操作系统，适用于交互式桌面环境；Windows NT  Server的设计目标是企业级的网络操作系统，提供容易管理、反应迅速的网络环境。两者在系统结构上完全一样，只是为适应不同应用环境在运行效率上做相  应调整。Windows NT Server具有更多的高级功能，可把Windows NT Workstation 看作它的子集。 <br /> <br /> Windows NT Server &nbsp;&nbsp; Windows NT Workstation <br /> <br /> 专为服务器进行了优化，硬件 适合个人用户，当工作站上有如 <br /> <br /> 配置要求较高。 &nbsp;&nbsp; &nbsp;&nbsp; CAD／CAM等高级应用要求时选用。 <br /> <br /> 最多支持32个处理器。 &nbsp;&nbsp; 可支持2个处理器。 <br /> <br /> 充当网络服务器，可无限制连 充当网络服务器，可以连入不超过 <br /> <br /> 入客户机，完成繁重的网络任务。 10个客户机，完成有限网络服务功能。 <br /> <br /> 可支持多达256个远程客户。 同时只能支持一个远程客户存取。 <br /> <br /> 支持Macintosh文件及打印， 不支持Macintosh文件及打印，不具备 <br /> <br /> 具备磁盘容错功能。 &nbsp;&nbsp; 磁盘容错功能。</p> <p align="left">&nbsp;</p> <p align="left"><strong>3.Windows NT</strong><strong>引入的新概念</strong><br /> <br /> （1）NTFS（Windows NT File System）：Windows NT采用的新型文件系统。可提供安全存取控制及容错能力，在大容量磁盘上，它的效率比FAT高。 <br /> <br /> （2）共享：对网络资源设置一定的权限许可，没有得到权限许可，就无法访问网络资源。 <br /> <br />  （3）用户账户（User Account）：要想使用网络资源，必须有用户账户。Windows  NT对用户和服务程序，都要求提供合法账户。专为应用程序或服务进程创建的账户即服务账户，在系统启动时，服务进程使用服务账户登录以获得在系统中使用资  源的权利和权限。普通用户账户由用户登录时提供，用于Windows NT控制该用户在系统中的权利和权限，与服务账户本质上无区别。 <br /> <br /> （4）域（Domain）：是Windows NT中数据安全和集中管理的基本单位。网络由域组成，域具有唯一的名称。域可以看作由运行NT的服务器组成的系统，一组电脑共用相同的账户及安全数据库。 <br /> <br /> （5）工作群组（Workgroup）：一种资源与系统管理皆分散的网络结构。工作群组里，每台电脑之间是对等关系，彼此可以是服务器，也可以当作工作站。 <br /> <br /> （6）权利（Right）：授权某用户可以在系统上执行某些操作。权利用来保护系统整体。 <br /> <br /> （7）权限（Permission）：用来保护特定对象。权限规定可以使用某一对象的用户以及用什么方法使用。 <br /> <br /> （8）安全审核：Windows NT将记录发生在电脑上各项与安全系统相关的过程。<br /> <br /> Windows NT获得了比OS/2更大的成功，因为它那永远不能完全了解的特性和微软的市场威力。</p> <p><strong>Windows NT</strong><strong>的版本</strong></p> <p>Windows NT包括两个版本，即Windows NT Workstation和Windows NT Server。若要构建网络操作系统，就需要使用Server版本。</p> <p>从1993年推出Windows NT 3.1开始，微软公司不断开发新版本的NT网络操作系统，主要如下：</p> <p>Windows NT 3.1</p> <p>Windows NT 4.0</p> <p>Windows Server 2000（Windows NT 5.0）</p> <p>Windows XP（Windows NT 5.1）</p> <p>Windows Server 2003（Windows NT 5.2）</p> <p>Windows Vista（Windows NT 6）</p> <p>Windows Server 2008（Windows NT 6.0）</p> <p>Windows 7（Windows NT 6.1）</p> <p>从上面可以看出，常见的PC操作系统Windows XP、Windows Vista和Windows 7也是采用 Windows  NT内核，但它们主要是面向PC机，因此没有提供完善的网络服务管理功能（相当于Workstation版）。而Windows Server  2000、Windows Server 2003和Windows Server 2008则是作为网络操作系统来使用的。</p> <p><strong>更多版本信息</strong></p> <p>NT 3.1&nbsp;Windows NT 3.1&nbsp;Workstation（僅被命名為&#8220;Windows NT&#8221;）, Advanced Server&nbsp;1993年7月27日<br /> NT 3.5&nbsp;Windows NT 3.5&nbsp;Workstation, Advanced Server&nbsp;1994年9月5日&nbsp;<br /> NT 3.51&nbsp;Windows NT 3.51&nbsp;Workstation, Advanced Server&nbsp;1995年5月30日&nbsp;<br /> NT 4.0&nbsp;Windows NT 4.0&nbsp;Workstation, Server, Server Enterprise Edition,<br /> Terminal Server, Embedded&nbsp;1996年7月29日&nbsp;<br /> NT 5.0&nbsp;Windows 2000&nbsp;Professional, Server, Advanced Server, DataCenter Server&nbsp;2000年2月17日<br /> NT 5.1&nbsp;Windows XP&nbsp;Home, Professional, IA-64，Media Center, Tablet PC, Starter, Embadded, N&nbsp;2001年10月15日&nbsp;<br /> NT 5.2&nbsp;Windows Server 2003&nbsp;Standard, Enterprise, DataCenter, Web, Small Business Server&nbsp;2003年4月24日&nbsp;<br /> NT 5.2&nbsp;Windows XP x64&nbsp;Professional x64 Edition&nbsp;2005年4月25日&nbsp;<br /> NT 6.0&nbsp;Windows Vista&nbsp;Starter, Home Basic, Home Premium, Business, Enterprise, Ultimate&nbsp;2007年1月30日&nbsp;<br /> 6001(SP1)<br /> 6002(SP2)<br /> NT 6.0&nbsp;Windows Server 2008&nbsp;Standard，Enterprise，Datacenter&nbsp;2008年2月27日&nbsp;6001(SP1)<br /> 6002(SP2)<br /> NT 6.1&nbsp;Windows 7&nbsp;Starter, Home Basic, Home Premium, Professional, Enterprise, Ultimate&nbsp;2009年10月22日&nbsp;<br />  NT 6.1&nbsp;Windows Server 2008 R2&nbsp;Foundation, Standard, Enterprise,  Datacenter, Web Server, HPC Server, Itanium-Based Systems&nbsp;2009年10月22日</p> <p>&nbsp;</p></div><img src ="http://www.cppblog.com/gxhzippo/aggbug/172779.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/gxhzippo/" target="_blank">在路上2011</a> 2012-04-26 00:55 <a href="http://www.cppblog.com/gxhzippo/archive/2012/04/26/172779.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Making Your Application UAC Aware</title><link>http://www.cppblog.com/gxhzippo/archive/2012/04/24/172660.html</link><dc:creator>在路上2011</dc:creator><author>在路上2011</author><pubDate>Tue, 24 Apr 2012 13:00:00 GMT</pubDate><guid>http://www.cppblog.com/gxhzippo/archive/2012/04/24/172660.html</guid><wfw:comment>http://www.cppblog.com/gxhzippo/comments/172660.html</wfw:comment><comments>http://www.cppblog.com/gxhzippo/archive/2012/04/24/172660.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/gxhzippo/comments/commentRss/172660.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/gxhzippo/services/trackbacks/172660.html</trackback:ping><description><![CDATA[UAC 的目标<br /> <p>UAC 旨在使用户能够使用标准用户权限（而不是管理权限）运行。管理权限使用户能够读取和修改操作系统的任何部份，包括其他用户的代码和数据 &#8212; 甚至是 Windows<sup>&#174;</sup>   本身。如果没有管理权限，用户不会意外（或有意）修改系统设置，恶意软件无法改变系统安全设置或禁用防病毒软件，用户也不会危及共享计算机上其他用户敏感 信息的安全。因此，使用标准用户权限运行可以减少企业环境中紧急咨询台呼叫的次数，减轻恶意软件的影响，使家庭计算机的运行更顺畅，并保护共享计算机上的 敏感数据。</p> <p>要使通过标准用户帐户运行切实可行，UAC  必须要解决几个问题。首先，在 Windows Vista&#8482; 之前，Windows  使用模型一直是某种假定的管理权限。软件开发人员假定他们的程序可以访问和修改任何文件、注册表或操作系统设置。甚至当 Windows NT<sup>&#174;</sup> 引入了安全性并区分了授予管理用户帐户和标准用户帐户的权限后，仍指导用户完成一个设置过程，使他们能够使用内置的 Administrator 帐户或 Administrators 组的成员帐户。</p> <p>UAC 必须解决的第二个问题是用户有时需要管理权限来执行某些操作，如安装软件、更改系统时间以及在防火墙中打开端口。</p> <p>UAC  针对这些问题的解决方案是使用标准用户权限运行大多数应用程序，始终避免对管理员权限的需要，并鼓励软件开发人员创建使用标准用户权限运行的应用程序。 UAC  通过以下方式来实现这些方面：减少对管理权限的需求频率，使旧应用程序能够使用标准用户权限运行，使标准用户在需要时能够方便地访问管理权限，甚至使管理 用户像标准用户那样运行。</p> <br /> <a name="S3"></a>作为标准用户运行<br /> <p>在 Windows Vista  的开发过程中，通过对所有管理操作的全面审核，确定了许多可以为标准用户启用而不会有损系统安全性的操作。例如，即使是为其 Windows XP  桌面系统采用了标准用户帐户的企业也无法从 Administrators 组中删除其移动用户，唯一的原因是 Windows XP  并不区分更改时区与更改系统时间之间的差别。如果便携式计算机用户希望配置本地时区以便旅行时能够在其日历中正确显示预约时间，他们必须具有&#8220;更改系统时 间&#8221;特权（在内部称为 SeSystemTimePrivilege），在默认情况下该特权仅授予管理员。</p> <p>安全协议（如 Kerberos）中通常会使用时间，但是时区仅影响时间的显示方式，因此 Windows Vista 添加了一个新特权&#8220;更改时区&#8221;(SeTimeZonePrivilege)，并将其分配给 Users 组，如图 1 所示。这样许多企业便有可能使其便携式计算机用户在标准用户帐户下运行。</p>  <div id="135400002" style="display: block; margin: 5px 0px 10px 5px; width: 400px"><a><img alt="图 1 &#8220;更改时区&#8221;特权" src="http://www.microsoft.com/technet/technetmag/issues/2007/06/UAC/zh//fig01.gif" width="400" height="135" border="0" /></a><br /> 图 1&nbsp;&#8220;更改时区&#8221;特权 (单击该图像获得较大视图) </div> <p>Windows Vista 还允许标准用户在连接到无线网络时配置  WEP 设置、创建 VPN 连接、更改电源管理设置以及安装重要 Windows 更新。此外，它还引入了&#8220;组策略&#8221;设置，使标准用户能够安装 IT  管理员批准的打印机和其他设备驱动程序，以及从管理员批准的站点安装 ActiveX<sup>&#174;</sup> 控件。</p> <p>对于不能以标准用户帐户正确运行的客户和业务线 (LOB)  应用程序该如何处理？虽然某些软件确实需要管理权限，但许多程序都毫无必要地将用户数据存储在系统全局位置。Microsoft  建议希望使用管理权限来运行的全局应用程序安装程序在 %ProgramFiles% 目录下创建一个目录来存储应用程序的可执行文件和辅助数据，并在  HKEY_LOCAL_MACHINE\Software  下为其应用程序设置创建一个注册表项。当执行某个应用程序时，它可以使用不同的用户帐户运行，因此它应当在针对每个用户的 %AppData%  目录中存储用户特定数据，并在 HKEY_CURRENT_USER\ Software  下的用户注册表配置文件中保存每个用户的设置。标准用户帐户不具备 %ProgramFiles% 目录或  HKEY_LOCAL_MACHINE\Software 的写访问权限，但是因为多数 Windows 系统都是单用户的，并且在 Windows  Vista 之前多数用户都是管理员，所以错误地将用户数据和设置保存到这些位置的应用程序仍能工作。</p> <p>通过文件系统和注册表命名空间虚拟化的帮助，Windows  Vista  使这些旧应用程序能够在标准用户帐户下运行。当应用程序修改文件系统或注册表中的系统全局位置并且该操作由于访问被拒绝而失败时，Windows  会将该操作重定向到特定于用户的区域；当应用程序从某个系统全局位置读取时，Windows  将首先检查每个用户区域中的数据，如果数据不存在，则允许从该全局位置进行读取尝试。</p> <p>针对此虚拟化目的，如果某个进程是 32 位的（与 64  位相对）、不是使用管理权限运行，并且没有指令清单文件表明它是为 Windows Vista 编写的，那么 Windows Vista  会将其视为旧进程。根据此定义，对于任何操作（包括网络文件共享访问），如果它不是源于分类为旧进程的进程，则不会将其虚拟化。进程的虚拟化状态存储为其 令牌中的一个标志，它是跟踪进程安全环境的内核数据结构，包括其用户帐户、组成员身份和特权。</p> <p>您可以通过向&#8220;任务管理器&#8221;的&#8220;进程&#8221;页添加&#8220;虚拟化&#8221;栏来查看进程的虚拟化状态。图 2  显示大多数 Windows Vista 组件（包括桌面窗口管理器 (Dwm .exe)、客户端服务器运行时子系统 (Csrss.exe)  和资源管理器）或者因为它们有 Windows Vista 指令清单而禁用了虚拟化，或者是使用管理权限运行而因此不允许虚拟化。Internet  Explorer<sup>&#174;</sup> (iexplore.exe) 启用了虚拟化，因为它可以承载多个 ActiveX 控件和脚本，并且必须假定它们没有编写为使用标准用户权限即可正确操作。</p>  <div id="285400004" style="display: block; margin: 5px 0px 10px 5px; width: 400px"><a><img alt="图 2 &#8220;任务管理器&#8221;显示虚拟化状态" src="http://www.microsoft.com/technet/technetmag/issues/2007/06/UAC/zh//fig02.gif" width="400" height="285" border="0" /></a><br /> 图 2&nbsp;&#8220;任务管理器&#8221;显示虚拟化状态 (单击该图像获得较大视图) </div> <p>为旧进程虚拟化的文件系统位置为  %ProgramFiles%、%ProgramData% 和  %SystemRoot%，其中不包括某些特定子目录。但是，任何具有可执行文件扩展名的文件（包括 .exe、.bat、.scr、.vbs  等等）都将从虚拟化中排除。这意味着，使用标准用户帐户进行自我更新的程序将失败，而不会创建对于运行全局更新程序的管理员不可见的专有可执行文件版本。 要向排除列表中添加其他扩展名，请在以下注册表项中输入它们并重新启动：</p> <p> </p><pre>HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\Luafv\Parameters\ExcludedExtensionsAdd </pre> <p>&nbsp;</p> <p>使用一种多字符串类型来分隔多个扩展名，并且不要在扩展名中包含前导点。</p> <p>旧进程对虚拟化目录的修改将重定向到用户的虚拟根目录  %LocalAppData%\VirtualStore。例如，如果我的系统上运行的某个虚拟化进程要创建  C:\Windows\Application.ini，那么它实际创建的文件为  C:\Users\Markruss\AppData\Local\VirtualStore\Windows\Application.ini。该路径 的本地部分表明这样一个事实，即当帐户具有漫游配置文件时，虚拟化文件不会随配置文件的其余部分漫游。</p> <p>如果在资源管理器中导航到一个包含虚拟化文件的目录，资源管理器将在其工具栏中显示一个标记为&#8220;兼容性文件&#8221;的按钮，如图 3 所示。单击该按钮可导航至对应的 VirtualStore 子目录以显示虚拟化文件。</p>  <div id="234400006" style="display: block; margin: 5px 0px 10px 5px; width: 400px"><a><img alt="图 3 &#8220;兼容性文件&#8221;按钮指明了附近的虚拟化文件" src="http://www.microsoft.com/technet/technetmag/issues/2007/06/UAC/zh//fig03.gif" width="400" height="234" border="0" /></a><br /> 图 3&nbsp;&#8220;兼容性文件&#8221;按钮指明了附近的虚拟化文件 (单击该图像获得较大视图) </div> <p>图 4  显示 UAC 文件虚拟化筛选器驱动程序 (%SystemRoot%\System32\Drivers\Luafv.sys)  如何实施文件系统虚拟化。因为它是文件系统筛选器驱动程序，所以它会看到所有文件系统操作，但是仅为来自旧进程的操作实施功能。您可以看到它为在系统全局 位置创建文件的旧进程更改了目标文件路径，但是没有为以标准用户权限运行 Windows Vista  应用程序的进程进行此更改。当它确实在用户具有完全访问权限的位置创建了文件时，旧进程便认为操作成功，但在 \Windows  目录上的默认权限会拒绝对为 Windows Vista 编写的应用程序的访问。</p> <div id="434300008" style="display: block; margin: 5px 0px 10px 5px; width: 300px"><img alt="图 4 文件系统虚拟化" src="http://www.microsoft.com/technet/technetmag/issues/2007/06/UAC/zh//fig04.gif" width="300" height="434" border="0" /><br /> 图 4&nbsp;文件系统虚拟化</div> <p>注册表虚拟化的实施与文件系统虚拟化略有不同。虚拟化的注册表项包括 HKEY_LOCAL_MACHINE\Software 分支的大部分，但有许多例外项，例如以下项：</p> <p> </p><pre>HKLM\Software\Microsoft\Windows HKLM\Software\Microsoft\Windows NT HKLM\Software\Classes </pre> <p>&nbsp;</p> <p>只有通常由旧应用程序修改，但不会带来兼容性或互操作性问题的项才能虚 拟化。Windows 将旧应用程序对虚拟化项的修改重定向到位于 HKEY_  CURRENT_USER\Software\Classes\VirtualStore 的用户注册表虚拟根目录。该项位于用户的 Classes  配置单元 %LocalAppData%\Microsoft\Windows\UsrClass.dat  中，与任何其他虚拟化文件数据一样，它并不随漫游用户配置文件漫游。</p> <p>与 Windows  为文件系统维护一个固定虚拟化位置列表不同，注册表项的虚拟化状态作为一个标志 REG_ KEY_DONT_VIRTUALIZE  存储在该项自身。Reg.exe 实用工具可以显示该标志以及另外两个虚拟化相关标志：REG_KEY_ DONT_SILENT_FAIL 和  REG_KEY_ RECURSE_FLAG，如图 5 所示。当设置了  REG_KEY_DONT_SILENT_FAIL 并且该项未虚拟化（已设置  REG_KEY_DONT_VIRTUALIZE）时，除了应用程序请求的访问外，原本被拒绝对该项执行操作访问的旧应用程序还将被授予用户对该项所拥有 的任何访问权限。REG_KEY_RECURSE_FLAG 表明新的子项是否继承父项的虚拟化标志，而不仅仅是默认标志。</p>  <div id="172400010" style="display: block; margin: 5px 0px 10px 5px; width: 400px"><a><img alt="图 5 Reg 实用工具显示虚拟化标志" src="http://www.microsoft.com/technet/technetmag/issues/2007/06/UAC/zh//fig05.gif" width="400" height="172" border="0" /></a><br /> 图 5&nbsp;Reg 实用工具显示虚拟化标志 (单击该图像获得较大视图) </div> <p>图 6 显示了配置管理器如何实施注册表虚拟化，该管理器管理操作系统内核 Ntoskrnl.exe 中的注册表。对于文件系统虚拟化，创建虚拟化项的子项的旧进程将被重定向到用户的注册表虚拟根，但默认权限会拒绝 Windows Vista 进程的访问。</p> <p>除了文件系统和注册表虚拟化以外，某些应用程序还需要其他帮助才能在标 准用户权限下正确运行。例如，对于测试其正在运行的帐户是否是 Administrators  组成员的应用程序，如果是该组成员，则会正常运行，如果不是，则不能正常运行。因此，Windows Vista  定义了许多应用程序兼容性填充，以使这类应用程序无论如何都能够运行。最常应用于旧应用程序以使其在标准权限下操作的填充如<a href="http://www.microsoft.com/technet/technetmag/issues/2007/06/UAC/default.aspx?pf=true&amp;fig=true#fig7" target="_self">图 7</a>  所示。企业 IT 专业人员可以使用诸如应用程序兼容性工具包（ACT，可从 technet.microsoft  .com/windowsvista/aa905066.aspx 获得），及其标准用户分析程序 (SUA) 实用工具，或 Aaron  Margosis 的 <a href="http://blogs.msdn.com/aaron_margosis/archive/2006/08/07/LuaBuglight.aspx">LUA Buglight</a>  等工具来确认其 LOB 应用程序的填充要求。他们使用 Compatibility Administrator（也是 ACT  的一部分）将填充分配给应用程序，然后将得到的兼容性数据库（.sdb  文件）通过组策略部署到桌面。请注意，如果需要，可以对使用全局安全策略设置的系统完全禁用虚拟化。</p> <div> <div>虚拟化的效果</div> <p>在&#8220;任务管理器&#8221;中右键单击某个进程并从上下文菜单中选择&#8220;虚拟化&#8221;，即可更改进程的虚拟化状态。图 A  显示了当其虚拟化状态更改时命令提示符的行为。开始时虚拟化是禁用的，因为它有一个 Windows Vista  指令清单。因为它使用标准用户权限运行，所以无法在 \Windows  目录中创建文件，但是在使用任务管理器将其虚拟化后，它似乎能够成功创建该文件。当其虚拟化返回禁用状态时，它将找不到该文件，该文件实际位于用户的虚拟 存储中。</p>  <div id="296400038" style="display: block; margin: 5px 0px 10px 5px; width: 400px"><a><img alt="图 A 虚拟化状态更改" src="http://www.microsoft.com/technet/technetmag/issues/2007/06/UAC/zh//figA.gif" width="400" height="296" border="0" /></a><br /> 图 A&nbsp;虚拟化状态更改 (单击该图像获得较大视图) </div> <br /> </div> <br /> <a name="S5"></a>管理员批准模式<br /> <p>即使用户只运行与标准用户权限兼容的程序，某些操作仍要求管理权限。绝 大多数软件安装都要求使用管理权限，以便在系统全局位置创建目录或注册表项，或者安装服务或设备驱动程序。修改系统全局 Windows  设置和应用程序设置也要求使用管理权限，Windows Vista  家长控制功能便是如此。通过切换到专用管理帐户可以执行大多数这些操作，但是这样很不方便，导致多数用户仍然会使用管理帐户来执行其日常任务。</p> <p>因此，Windows Vista 提供了一个增强的&#8220;运行身份&#8221;功能，以使标准用户能够方便地以管理权限启动进程。此功能要求为应用程序提供一种方式来标识系统可为之获得管理权限（代表该应用程序）的操作，我将对此进行简要说明。</p> <p>此外，Windows Vista 还引入了一个管理员批准模式  (AAM)，这样，作为系统管理员的用户便可以使用标准用户权限来运行，而不必在每次希望获得管理权限时输入用户名和密码。此功能在登录时为用户创建两个 身份：一个具有标准用户权限，另一个具有管理权限。由于 Windows Vista 系统上的每个用户要么是标准用户，要么多数情况下作为 AAM  中的标准用户来运行，因而开发人员必须假定所有 Windows 用户都是标准用户，这将导致有更多的程序使用不带有虚拟化或填充的标准用户权限来运行。</p> <p>为进程授予管理权限称为提升。由标准用户帐户执行此过程时，称为&#8220;当面式&#8221;(OTS) 提升，因为它要求输入某个管理员组的成员帐户的凭据，这通常由另一个用户当着该标准用户的面完成。由 AAM 用户执行的提升称为&#8220;同意&#8221;提升，因为用户只需批准其管理权限的分配即可。</p> <p>如果用户是<a href="http://www.microsoft.com/technet/technetmag/issues/2007/06/UAC/default.aspx?pf=true&amp;fig=true#fig8" target="_self">图 8</a>  中所列任意管理员类型组的成员，Windows Vista  就会将该用户视为管理员。所列的许多组都只用于加入域的系统，并且不直接赋予用户本地管理权限，但是允许他们修改域范围内的设置。如果用户是其中任何组的 成员，而不是实际的管理员组的成员，该用户将通过 OTS 提升而不是&#8220;同意&#8221;提升来获得其管理权限。</p> <p>当属于所列的某个组的用户登录时，Windows Vista 将创建一个令牌，代表该用户的管理身份的标准用户版本。新令牌解除了分配给该用户的所有特权，只保留了<a href="http://www.microsoft.com/technet/technetmag/issues/2007/06/UAC/default.aspx?pf=true&amp;fig=true#fig9" target="_self">图 9</a> 中所列的那些特权，它们是默认标准用户特权。此外，任何管理员类型组在该新令牌中都带有 USE_FOR_DENY_ONLY 标志。图 10 显示了 Sysinternals Process Explorer（一种进程管理工具，可从 <a href="http://www.microsoft.com/technet/sysinternals">microsoft .com/technet/sysinternals</a> 下载），其左侧显示了使用管理权限运行的进程的组成员关系和特权，右侧显示了不具备管理员权限的情况。（为防止意外错误使用，Windows 安全模型要求先启用带有禁用标志的特权，然后才能使用它。）</p>  <div id="220400012" style="display: block; margin: 5px 0px 10px 5px; width: 400px"><a><img alt="图 10 AAM 管理员和标准用户令牌" src="http://www.microsoft.com/technet/technetmag/issues/2007/06/UAC/zh//fig10.gif" width="400" height="220" border="0" /></a><br /> 图 10&nbsp;AAM 管理员和标准用户令牌 (单击该图像获得较大视图) </div> <p>具有&#8220;仅拒绝&#8221;标志的组只能用于拒绝（而不能允许）用户对某个资源的访 问，这样就消除了当该组被整个删除时所产生的安全漏洞。例如，如果某个文件的访问控制列表 (ACL) 拒绝了 Administrators  组的所有访问，但为该用户所属的另一个组授予某些访问权限，那么如果令牌中没有管理员组，则会为用户授予访问权限，从而为该用户身份的标准用户版本赋予比 管理员身份更多的权限。</p> <p>独立系统（通常是家用计算机）和加入域的系统对来自远程用户的 AAM  访问的处理不同，因为连接了域的计算机可以在其资源权限内使用域管理组。当用户访问独立计算机的文件共享时，Windows  将请求该远程用户的标准用户身份，但在加入域的系统上，Windows 将通过请求该用户的管理身份来支持其所有域组成员。</p> <br /> <a name="S6"></a>方便地获得管理权限<br /> <p>系统和应用程序可以通过多种方式标识对管理权限的需求。其中一个是显示 在资源管理器 UI  中的&#8220;以管理员身份运行&#8221;上下文菜单项和快捷方式选项。这些项目包含一个彩色盾牌图标，它应放在任何按钮或菜单项上，当选中它时会导致权限的提升。选择 &#8220;以管理员身份运行&#8221;菜单项将使资源管理器使用动词&#8220;runas&#8221;调用 ShellExecute API。</p> <p>绝大多数安装程序都要求使用管理权限，因此，映像加载程序（用于触发可 执行文件的启动）包含了安装程序检测代码以发现可能的旧安装程序。它使用的某些启发方式很简单，只需检测该映像在其文件名或内部版本信息中是否具有设置  (setup)、安装 (install) 或更新 (update)  字样；较为复杂的启发方式则涉及扫描可执行文件中的字节序列，第三方安装包装实用工具大多为这种情况。</p> <p>映像加载器还会调用应用程序兼容性 (appcompat) 库，以查看目标可执行文件是否要求使用管理员权限。该库将查询应用程序兼容性数据库，以查看该可执行文件是否关联了 RequireAdministrator 或 RunAsInvoker 兼容性标志。</p> <p>可执行文件请求得到管理权限的最常用方式是在其应用程序指令清单文件中 包含一个 requestedElevationLevel 令牌。指令清单是 XML 文件，其中包含有关某个映像的补充信息。它们是在  Windows XP 中引入的，作为标识与并列 DLL 和 Microsoft .NET Framework  程序集的依赖关系的一种方式。指令清单中出现的 trustInfo 元素（可在下面的 Firewallsettings.exe  字符串转储摘录中看到）表明这是一个为 Windows Vista 编写的可执行文件，并且其中嵌套了  requestedElevationLevel 元素。该元素的 level  属性可具有以下三个值之一：asInvoker、highestAvailable 和 requireAdministrator。</p> <p> </p><pre>&lt;trustInfo xmlns=&#8221;urn:schema-microsoft-com:asm.v3&#8221;&gt; &lt;security&gt; &lt;requestedPrivileges&gt; &lt;requestedExecutionLevel Level=&#8221;requireAdministrator&#8221; uiAccess=&#8221;false&#8221;/&gt; &lt;/requestedPrivileges&gt; &lt;/security&gt; &lt;/trustInfo&gt; </pre> <p>&nbsp;</p> <p>不需要管理权限的可执行文件（如 Notepad.exe）指定  asInvoker 值。某些可执行文件预期管理员始终希望具有最大访问权限，因此他们使用 highestAvailable  值。如果某用户运行具有该值的可执行文件，那么仅当他在 AAM  中运行或被视为管理员（根据早先定义的规测）且必须提升以获得其管理权限时，才会要求提升他的权限。例如，Regedit.exe、Mmc.exe 和  Eventvwr.exe 都是使用 highestAvailable 的应用程序。最后，requireAdministrator  始终会导致提升请求，任何没有管理权限就无法操作的可执行文件需要使用该值。</p> <p>可访问性应用程序为 uiAccess 属性指定&#8220;true&#8221;，以便驱动所提升进程的窗口输入，并且它们还必须带有签名并位于多个安全位置（包括 %SystemRoot% 和 %ProgramFiles%）之一以获取该能力。</p> <p>确定可执行文件所指定值的一种简单方法是使用 Sysinternals Sigcheck 实用工具查看其指令清单，如下所示：</p> <p> </p><pre>sigcheck &#8211;m &lt;executable&gt; </pre> <p>&nbsp;</p> <p>执行一个请求管理权限的映像将导致在服务主机进程  (%SystemRoot%\System32\Svchost .exe) 中运行的应用程序信息服务（也称为 AIS，它包含在  %SystemRoot%\System32\Appinfo.dll 中）启动 Consent.exe  (%SystemRoot%\System32\Consent.exe)。Consent  将捕获屏幕的位图、向其应用一个淡入淡出效果、切换到只能由本地系统帐户访问的桌面、将该位图作为背景、并显示一个提升对话框，其中包含有关该可执行文件 的信息。在单独的桌面上显示可防止用户帐户中的任何恶意软件修改对话框的外观。</p>  <div id="1087400014" style="display: block; margin: 5px 0px 10px 5px; width: 400px"><a><img alt="图 11 OTS 提升对话框" src="http://www.microsoft.com/technet/technetmag/issues/2007/06/UAC/zh//fig11.gif" width="400" height="1087" border="0" /></a><br /> 图 11&nbsp;OTS 提升对话框 (单击该图像获得较大视图) </div> <p>如果映像是由 Microsoft 数字签名的 Windows 组件，并且位于 Windows 系统目录中，则对话框顶部将显示一条蓝带，如图 11  顶部所示。灰带（对话框中间）表明映像由 Microsoft  以外的组织数字签名，橙色带（对话框底部）表明映像未经签名。提升对话框显示了映像的图标、描述以及数字签名映像的发布者，但对于未签名的映像只有一个通 用的图标、文件名和&#8220;未能识别的发布程序&#8221;。这样就使恶意软件更难以模仿合法软件的外观。对话框底部的&#8220;详细信息&#8221;按钮展开后将显示当可执行文件启动时要 传递给它的命令行。图 12 所示的&#8220;AAM 同意&#8221;对话框与此类似，但它不会提示提供管理员凭据，而是包含了&#8220;继续&#8221;和&#8220;取消&#8221;按钮。</p>  <div id="226400016" style="display: block; margin: 5px 0px 10px 5px; width: 400px"><a><img alt="图 12 AAM 提升对话框" src="http://www.microsoft.com/technet/technetmag/issues/2007/06/UAC/zh//fig12.gif" width="400" height="226" border="0" /></a><br /> 图 12&nbsp;AAM 提升对话框 (单击该图像获得较大视图) </div> <p>如果用户拒绝提升，Windows  将向激发该启动过程的进程返回一个拒绝访问错误。当用户通过输入管理员凭据或单击&#8220;继续&#8221;同意提升时，AIS 将调用  CreateProcessAsUser 以使用适当的管理身份启动进程。虽然从技术上讲 AIS 是所提升进程的父项，但 AIS 使用了  CreateProcessAsUser API 中的新支持，后者将该进程的父进程 ID 设为最初启动它的进程的 ID（请参阅图 13）。这就是在显示进程树的工具（如 Process Explorer）中，已提升进程没有显示为 AIS Service Hosting 进程的子项的原因。</p> <div id="363300018" style="display: block; margin: 5px 0px 10px 5px; width: 300px"><img alt="图 13 提升流程" src="http://www.microsoft.com/technet/technetmag/issues/2007/06/UAC/zh//fig13.gif" width="300" height="363" border="0" /><br /> 图 13&nbsp;提升流程</div> <p>即使提升对话框显示在单独的安全桌面上，默认情况下，用户也无法验证他 们查看的是合法对话框，而不是由恶意软件提供的对话框。这并不是 AAM  的问题，因为恶意软件虽无法使用假的&#8220;同意&#8221;对话框获取管理权限，但它可以等待标准用户的 OTS  提升，截获它，并使用特洛伊木马对话框捕获管理员凭据。使用那些凭据，它们可以获得对管理员帐户的访问权限并感染它。</p> <p>因此，强烈建议不要在企业环境中使用 OTS 提升。要禁用 OTS 提升（并减少咨询台呼叫），请运行本地安全策略编辑器 (Secpol.msc) 并将&#8220;用户帐户控制：标准用户的提升提示行为&#8221;配置为&#8220;自动拒绝提升请求&#8221;。</p> <p>注重安全的家庭用户应当将 OTS  提升配置为要求使用一个恶意软件无法截获或模拟的安全注意序列 (SAS)。要配置 SAS，请运行组策略编辑器  (Gpedit.msc)，导航到&#8220;计算机配置&#8221;|&#8220;管理模板&#8221;|&#8220;Windows  组件&#8221;|&#8220;凭据用户界面&#8221;，并启用&#8220;要求输入凭据的受信任路径&#8221;。完成上述步骤后，会要求您输入 Ctrl+Alt+Delete 以访问提升对话框。</p> <br /> <a name="S7"></a>隔离已提升的进程<br /> <p>Windows Vista  在已提升进程周围设置了一道屏障，以保护它们免受在同一桌面上使用标准用户权限运行的恶意软件的侵扰。如果没有这道屏障，恶意软件可能会通过窗口消息发送 合成的鼠标和窗口输入，从而驱动某个管理应用程序。虽然标准 Windows  安全模型可防止使用标准用户权限在进程中运行的恶意软件破坏作为不同用户运行的已提升进程，但它不会禁止作为某个管理用户的标准权限版本运行的恶意软件打 开该用户的已提升进程、向其中插入代码并启动其中的线程以执行插入的代码。</p> <p>Windows Vista  为窗口消息提供的防护称为用户界面特权隔离 (UIPI)。它基于新的 Windows 完整性机制，Windows Vista  同样使用该机制作为已提升进程周围的屏障。在此新安全模型中，所有进程和对象都具有完整性级别，并且对象的完整性策略可以限制访问权限，否则，这些访问权 限将由 Windows 随机访问控制 (DAC) 安全模型授予某个进程。</p> <p>完整性级别 (IL) 由安全标识符 (SID) 表示，后者还表示用户和组；而级别则编码在 SID 的相对标识符 (RID) 中。<a href="http://www.microsoft.com/technet/technetmag/issues/2007/06/UAC/default.aspx?pf=true&amp;fig=true#fig14" target="_self">图 14</a> 显示了四个主要 IL 的显示名称、SID 和 SID 的 RID 的十六进制版本。十六进制数字揭示了每个级别间的 0x1000 的间隔，以便提供由 UI 可访问性应用程序使用的中间级别并考虑未来增长需要。</p> <p><a href="http://www.microsoft.com/technet/technetmag/issues/2007/06/UAC/default.aspx?pf=true&amp;fig=true#fig15" target="_self">图 15</a>  列出了对象 IL 策略以及它们所限制的访问类型，这些访问类型与为对象定义的通用访问权限相对应。例如，No-Write-Up 将禁止低 IL  进程获取任何由 GENERIC_WRITE 访问权限表示的访问权限。大多数对象（包括文件和注册表项）的默认策略都是  No-Write-Up，这将禁止进程从具有比它更高的 IL 的对象获取写访问权限，即使该对象的随机访问控制列表 (DACL)  授予用户这种访问权限也是如此。仅有的具有不同策略的对象是进程对象和线程对象。它们的策略（No-Write-Up 加上  No-Read-Up）会禁止在低 IL 上运行的进程向具有较高 IL 的进程插入代码或从中读取数据（如密码）。</p> <p>Windows 为每个进程分配一个 IL，该 IL 放在进程令牌中组 SID 的旁边，这些组是运行该进程的用户所属的组。<a href="http://www.microsoft.com/technet/technetmag/issues/2007/06/UAC/default.aspx?pf=true&amp;fig=true#fig16" target="_self">图 16</a>  列出了分配给不同 IL 的进程示例。进程通常继承其父项的 IL，但进程也可以在其他 IL 上启动进程，与 AIS  启动已提升进程时的操作相同。您可以通过指定 /all 选项使用内置的 Whoami 实用工具、Sysinternals Process  Explorer 或 AccessChk 来查看进程完整性级别。Process Explorer 可以在附加的&#8220;完整性级别&#8221;列中显示进程 IL。</p> <p>每个安全对象都有一个显式或隐式的  IL。进程、线程和令牌对象始终具有一个显式分配的 IL，它通常与对应进程令牌中存储的 IL 相同。多数对象都没有显式 IL，因此都默认为某个中等  IL。使用中等以外的 IL 创建的仅有对象是由在低 IL 上运行的进程创建的对象，它们因此而具有一个低 IL。您可以使用内置的 iCacls  工具 (%SystemRoot%\System32\iCacls.exe) 查看文件的 IL，并使用 Sysinternals  AccessChk 实用工具查看文件、注册表项、服务和进程的 IL。图 17 显示需要通过保护模式 Internet Explorer 才能访问的目录的 IL 为&#8220;低&#8221;。</p>  <div id="146400020" style="display: block; margin: 5px 0px 10px 5px; width: 400px"><a><img alt="图 17 显示用户收藏夹目录 IL 的 AccessChk" src="http://www.microsoft.com/technet/technetmag/issues/2007/06/UAC/zh//fig17.gif" width="400" height="146" border="0" /></a><br /> 图 17&nbsp;显示用户收藏夹目录 IL 的 AccessChk (单击该图像获得较大视图) </div> <p>如果对象具有显式 IL，则它存储在 Windows Vista 中新引入的一种访问控制项 (ACE) 类型中（即 Label ACE），该 ACE 位于对象安全描述符的系统访问控制列表 (SACL) 中（请参阅图 18）。 ACE 中的 SID 对应于对象的 IL，ACE 的标志为对象的完整性策略进行了编码。在 Windows Vista 之前，SACL 只存储审核  ACE，这需要&#8220;管理审核和安全日志&#8221;特权 (SeSecurityPrivilege)，但读取 Label ACE  只需要&#8220;读取权限&#8221;(READ_CONTROL) 访问权限。如果进程要修改对象的 IL，它必须具有该对象的&#8220;更改所有者&#8221;(WRITE_OWNER)  访问权限以及一个与该对象相同或更高的 IL，并且该进程只能将 IL 设置为自己的 IL 或更低的  IL。新的&#8220;修改对象标签&#8221;(SeRelabelPrivilege) 特权使进程能够更改它可以访问的任何对象的 IL，甚至将 IL  提高到超过进程自己的 IL，但默认情况下，该特权未分配给任何帐户。</p> <div id="203400022" style="display: block; margin: 5px 0px 10px 5px; width: 400px"><img alt="图 18 对象的 Label ACE" src="http://www.microsoft.com/technet/technetmag/issues/2007/06/UAC/zh//fig18.gif" width="400" height="203" border="0" /><br /> 图 18&nbsp;对象的 Label ACE</div> <p>当进程尝试打开某个对象时，内核的 SeAccessCheck  功能中将先进行完整性检查，然后再进行标准的 Windows DACL 检查。在默认完整性策略下，仅当进程的 IL 等于或高于对象的 IL，且  DACL 也为该进程授予了它所需要的权限时，该进程才能打开此对象进行写访问。例如，低 IL 进程不能打开中等 IL 进程进行写访问，即使  DACL 为该进程授予了写访问权限。</p> <p>在默认完整性策略下，进程可以打开任何对象（进程和线程对象除外）进行 读取访问，只要对象的 DACL 为它们授予了读取权限即可。这意味着，在低 IL  上运行的进程可以打开任何其运行所在的用户帐户可以访问的文件。保护模式 Internet Explorer 使用 IL  来帮助防止感染它的恶意软件修改用户帐户设置，但是它不能禁止恶意软件读取用户的文档。</p> <p>上述情况不适用于进程和线程对象，因为它们的完整性策略还包括 No-Read-Up。这意味着，进程的 IL 必须等于或高于它要打开的进程或线程的 IL，且 DACL 必须授予它成功打开所需的访问权限。假设 DACL 允许授予所需的权限，图 19 显示了在中等和低 IL 上运行的进程针对其他进程和对象所拥有的访问权限。</p> <div id="249300024" style="display: block; margin: 5px 0px 10px 5px; width: 300px"><img alt="图 19 对象和进程访问权限" src="http://www.microsoft.com/technet/technetmag/issues/2007/06/UAC/zh//fig19.gif" width="300" height="249" border="0" /><br /> 图 19&nbsp;对象和进程访问权限</div> <p>Windows 消息传递子系统还支持完整性级别通过以下方式实施  UIPI：禁止进程向具有较高 IL  的进程所拥有的窗口发送除信息性窗口消息以外的任何消息。这将不允许标准用户进程向已提升进程的窗口进行输入，或不允许通过向其发送可触发内部缓冲区溢出 的格式不正确的消息来破坏已提升进程。进程可以通过调用 ChangeWindowMessageFilter API  选择允许其他消息通过这层防范。UIPI 还会防止窗口挂接影响较高 IL  进程的窗口，这样，例如标准用户进程便无法记录用户在管理应用程序中的键击情况。</p> <br /> <a name="S8"></a>提升和安全边界<br /> <p>UAC 提升是一种方便性，而不是安全边界，清楚这一点很重要。安全边界要求安全策略指明能够通过该边界的内容。用户帐户就是 Windows 中安全边界的一个示例，因为如果没有另一个用户的许可，某个用户就无法访问属于另一个用户的数据。</p> <p>因为提升不是安全边界，所以无法保证使用标准用户权限在系统上运行的恶 意软件不会侵扰已提升进程以获取管理权限。例如，提升对话框只标识了即将提升的可执行文件；其中没有提供执行时将如何操作的任何信息。可执行文件将处理命 令行参数、加载 DLL、打开数据文件并与其他进程通信。可以想象，上述任何操作都可能允许恶意软件侵扰已提升进程，进而获取管理权限。</p> <div> <div>低 IL 沙盒中的游戏</div> <p>保护模式 Internet Explorer 在低 IL  上运行，以便在可能感染其进程的恶意软件周围筑起一道围墙。这将防止恶意软件更改用户帐户设置并将自己安装在一个自动启动位置。您可以使用  Sysinternals PsExec 实用工具和 -l 开关，在低 IL 上启动任意进程以探究沙盒的秘密。图 B 显示了在低 IL  上运行的命令提示符如何无法在用户的临时目录（具有中等 IL）中创建文件，却能够在具有低 IL 的 Internet Explorer  临时目录中创建该文件。 </p>  <div id="259400036" style="display: block; margin: 5px 0px 10px 5px; width: 400px"><a><img alt="图 B 命令提示符只能在相似的 IL 中创建文件" src="http://www.microsoft.com/technet/technetmag/issues/2007/06/UAC/zh//figB.gif" width="400" height="259" border="0" /></a><br /> 图 B&nbsp;命令提示符只能在相似的 IL 中创建文件 (单击该图像获得较大视图) </div> <p>&nbsp;</p> <br /> </div> <p>已提升的 AAM 进程尤其易受侵扰，因为它们在与 AAM  用户的标准权限进程相同的用户帐户下运行，并共享用户的配置文件。许多应用程序读取在用户配置文件中注册的设置并加载在其中注册的扩展，这为恶意软件的提 升提供了机会。例如，常用控制对话框会加载在用户的注册表项（位于 HKEY_CURRENT_USER  下）中配置的外壳扩展，因此恶意软件可以将其自身作为一项扩展添加进去，以加载到使用那些对话框的任何已提升进程中。</p> <p>即使是从标准用户帐户提升的进程也必定会因共享状态而受到侵扰。在某个 登录会话中运行的所有进程将共享 Windows  用来存储对象（如事件、mutex、信号和共享内存）的内部命名空间。如果恶意软件知道某个已提升进程将在进程启动时尝试打开并读取特定共享内存对象，它 可以创建该对象，而其内容将触发缓冲区溢出以便将代码插入到已提升进程中。这种攻击类型比较复杂，但其存在的可能性使得 OTS  提升无法成为一种安全边界。</p> <p>我们的底线是引入提升以提供方便，从而鼓励要获得管理权限的用户在默认 情况下使用标准用户权限运行。希望安全边界有保障的用户可以用方便性换取这种保障，此时，可以为日常任务使用标准用户帐户，同时使用快速用户切换  (FUS) 切换到专用管理员帐户来执行管理操作。另一方面，希望用安全性换取方便性的用户可以在&#8220;控制面板&#8221;的&#8220;用户帐户&#8221;对话框中禁用系统上的  UAC，但是必须清楚，这同时也会禁用 Internet Explorer 的保护模式。</p> <br /> <a name="S10"></a>结束语<br /> <p>以标准用户身份运行有许多好处，其中包括有助于保护系统免受无意或有意 的损害，以及防止共享系统的用户的数据和完整性受到未经授权的访问。UAC 的各种变化和技术将导致 Windows 使用模型发生重要改变。在  Windows Vista 中，Windows  用户第一次能够使用标准用户权限执行大多数日常任务并运行大多数软件，现在，许多企业都能够部署标准用户帐户。</p><img src ="http://www.cppblog.com/gxhzippo/aggbug/172660.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/gxhzippo/" target="_blank">在路上2011</a> 2012-04-24 21:00 <a href="http://www.cppblog.com/gxhzippo/archive/2012/04/24/172660.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>UAC讲解深入了解 Windows Vista 用户帐户控制  </title><link>http://www.cppblog.com/gxhzippo/archive/2012/04/24/172658.html</link><dc:creator>在路上2011</dc:creator><author>在路上2011</author><pubDate>Tue, 24 Apr 2012 12:57:00 GMT</pubDate><guid>http://www.cppblog.com/gxhzippo/archive/2012/04/24/172658.html</guid><wfw:comment>http://www.cppblog.com/gxhzippo/comments/172658.html</wfw:comment><comments>http://www.cppblog.com/gxhzippo/archive/2012/04/24/172658.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/gxhzippo/comments/commentRss/172658.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/gxhzippo/services/trackbacks/172658.html</trackback:ping><description><![CDATA[<table border="0" cellpadding="0" cellspacing="0"><tbody><tr><td colspan="2"><div>概览:</div></td></tr>  <tr>  <td>  <ul><li>作为标准用户运行   </li><li>文件和注册表虚拟化   </li><li>提升帐户状态</li></ul></td>  <td style="background-color: white;"><br /></td></tr></tbody></table><br />  <p>Windows Vista 中的用户帐户控制 (UAC) 通常令人感到误解。我在<em>《TechNet 杂志》</em>上就 Windows Vista 的内核变化发表了三篇系列文章（请参阅 <a rel="nofollow" href="http://www.technetmagazine.com/">technetmagazine.com</a>），但其中未涉及 UAC，因为我觉得应当为其单独写一篇文章。 </p>  <p>在 本文中，我将探讨 UAC  解决的问题，并说明其组件技术的体系结构和实施。这些技术包括对以前要求管理权限的操作进行重构、可帮助程序在没有管理权限的情况下正确运行的轻型虚拟 化、使程序显式请求管理权限的能力，以及将在同一用户桌面上运行的管理流程与非管理流程相隔离。</p><br />UAC 的目标<br />  <p>UAC 旨在使用户能够使用标准用户权限（而不是管理权限）运行。管理权限使用户能够读取和修改操作系统的任何部份，包括其他用户的代码和数据 &#8212; 甚至是 Windows<sup>&#174;</sup>   本身。如果没有管理权限，用户不会意外（或有意）修改系统设置，恶意软件无法改变系统安全设置或禁用防病毒软件，用户也不会危及共享计算机上其他用户敏感 信息的安全。因此，使用标准用户权限运行可以减少企业环境中紧急咨询台呼叫的次数，减轻恶意软件的影响，使家庭计算机的运行更顺畅，并保护共享计算机上的 敏感数据。</p>  <p>要使通过标准用户帐户运行切实可行，UAC  必须要解决几个问题。首先，在 Windows Vista? 之前，Windows  使用模型一直是某种假定的管理权限。软件开发人员假定他们的程序可以访问和修改任何文件、注册表或操作系统设置。甚至当 Windows NT<sup>&#174;</sup> 引入了安全性并区分了授予管理用户帐户和标准用户帐户的权限后，仍指导用户完成一个设置过程，使他们能够使用内置的 Administrator 帐户或 Administrators 组的成员帐户。</p>  <p>UAC 必须解决的第二个问题是用户有时需要管理权限来执行某些操作，如安装软件、更改系统时间以及在防火墙中打开端口。</p>  <p>UAC   针对这些问题的解决方案是使用标准用户权限运行大多数应用程序，始终避免对管理员权限的需要，并鼓励软件开发人员创建使用标准用户权限运行的应用程序。 UAC  通过以下方式来实现这些方面：减少对管理权限的需求频率，使旧应用程序能够使用标准用户权限运行，使标准用户在需要时能够方便地访问管理权限，甚至使管理 用户像标准用户那样运行。</p><br />作为标准用户运行<br />  <p>在  Windows Vista  的开发过程中，通过对所有管理操作的全面审核，确定了许多可以为标准用户启用而不会有损系统安全性的操作。例如，即使是为其 Windows XP  桌面系统采用了标准用户帐户的企业也无法从 Administrators 组中删除其移动用户，唯一的原因是 Windows XP  并不区分更改时区与更改系统时间之间的差别。如果便携式计算机用户希望配置本地时区以便旅行时能够在其日历中正确显示预约时间，他们必须具有&#8220;更改系统时 间&#8221;特权（在内部称为 SeSystemTimePrivilege），在默认情况下该特权仅授予管理员。</p>  <p>安全协议（如 Kerberos）中通常会使用时间，但是时区仅影响时间的显示方式，因此 Windows Vista 添加了一个新特权&#8220;更改时区&#8221;(SeTimeZonePrivilege)，并将其分配给 Users 组，如图 1 所示。这样许多企业便有可能使其便携式计算机用户在标准用户帐户下运行。</p>    <div style="display: block; margin: 5px 0px 10px 5px; width: 400px;"><a rel="nofollow" href="http://blog.163.com/wumings_2005/blog/static/231434032007930552891/%27247729002%27%29;"><img alt="图 1 &#8220;更改时区&#8221;特权" src="http://www.microsoft.com/technet/technetmag/issues/2007/06/UAC/zh//fig01.gif" width="400" height="135" border="0" /></a><br />图 1&nbsp;&#8220;更改时区&#8221;特权 (单击该图像获得较大视图) </div>  <p>Windows  Vista 还允许标准用户在连接到无线网络时配置 WEP 设置、创建 VPN 连接、更改电源管理设置以及安装重要 Windows  更新。此外，它还引入了&#8220;组策略&#8221;设置，使标准用户能够安装 IT 管理员批准的打印机和其他设备驱动程序，以及从管理员批准的站点安装 ActiveX<sup>&#174;</sup> 控件。</p>  <p>对 于不能以标准用户帐户正确运行的客户和业务线 (LOB)  应用程序该如何处理？虽然某些软件确实需要管理权限，但许多程序都毫无必要地将用户数据存储在系统全局位置。Microsoft  建议希望使用管理权限来运行的全局应用程序安装程序在 %ProgramFiles% 目录下创建一个目录来存储应用程序的可执行文件和辅助数据，并在  HKEY_LOCAL_MACHINE\Software  下为其应用程序设置创建一个注册表项。当执行某个应用程序时，它可以使用不同的用户帐户运行，因此它应当在针对每个用户的 %AppData%  目录中存储用户特定数据，并在 HKEY_CURRENT_USER\ Software  下的用户注册表配置文件中保存每个用户的设置。标准用户帐户不具备 %ProgramFiles% 目录或  HKEY_LOCAL_MACHINE\Software 的写访问权限，但是因为多数 Windows 系统都是单用户的，并且在 Windows  Vista 之前多数用户都是管理员，所以错误地将用户数据和设置保存到这些位置的应用程序仍能工作。</p>  <p>通 过文件系统和注册表命名空间虚拟化的帮助，Windows Vista  使这些旧应用程序能够在标准用户帐户下运行。当应用程序修改文件系统或注册表中的系统全局位置并且该操作由于访问被拒绝而失败时，Windows  会将该操作重定向到特定于用户的区域；当应用程序从某个系统全局位置读取时，Windows  将首先检查每个用户区域中的数据，如果数据不存在，则允许从该全局位置进行读取尝试。</p>  <p>针 对此虚拟化目的，如果某个进程是 32 位的（与 64 位相对）、不是使用管理权限运行，并且没有指令清单文件表明它是为 Windows Vista  编写的，那么 Windows Vista  会将其视为旧进程。根据此定义，对于任何操作（包括网络文件共享访问），如果它不是源于分类为旧进程的进程，则不会将其虚拟化。进程的虚拟化状态存储为其 令牌中的一个标志，它是跟踪进程安全环境的内核数据结构，包括其用户帐户、组成员身份和特权。</p>  <p>您可以通过向&#8220;任务管理器&#8221;的&#8220;进程&#8221;页添加&#8220;虚拟化&#8221;栏来查看进程的虚拟化状态。图 2  显示大多数 Windows Vista 组件（包括桌面窗口管理器 (Dwm .exe)、客户端服务器运行时子系统 (Csrss.exe)  和资源管理器）或者因为它们有 Windows Vista 指令清单而禁用了虚拟化，或者是使用管理权限运行而因此不允许虚拟化。Internet  Explorer<sup>&#174;</sup> (iexplore.exe) 启用了虚拟化，因为它可以承载多个 ActiveX 控件和脚本，并且必须假定它们没有编写为使用标准用户权限即可正确操作。</p>    <div style="display: block; margin: 5px 0px 10px 5px; width: 400px;"><a rel="nofollow" href="http://blog.163.com/wumings_2005/blog/static/231434032007930552891/%27461647004%27%29;"><img alt="图 2 &#8220;任务管理器&#8221;显示虚拟化状态" src="http://www.microsoft.com/technet/technetmag/issues/2007/06/UAC/zh//fig02.gif" width="400" height="285" border="0" /></a><br />图 2&nbsp;&#8220;任务管理器&#8221;显示虚拟化状态 (单击该图像获得较大视图) </div>  <p>为 旧进程虚拟化的文件系统位置为 %ProgramFiles%、%ProgramData% 和  %SystemRoot%，其中不包括某些特定子目录。但是，任何具有可执行文件扩展名的文件（包括 .exe、.bat、.scr、.vbs  等等）都将从虚拟化中排除。这意味着，使用标准用户帐户进行自我更新的程序将失败，而不会创建对于运行全局更新程序的管理员不可见的专有可执行文件版本。 要向排除列表中添加其他扩展名，请在以下注册表项中输入它们并重新启动：</p>  <pre>HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\Luafv\Parameters\ExcludedExtensionsAdd   </pre>    <p>使用一种多字符串类型来分隔多个扩展名，并且不要在扩展名中包含前导点。</p>  <p>旧 进程对虚拟化目录的修改将重定向到用户的虚拟根目录  %LocalAppData%\VirtualStore。例如，如果我的系统上运行的某个虚拟化进程要创建  C:\Windows\Application.ini，那么它实际创建的文件为  C:\Users\Markruss\AppData\Local\VirtualStore\Windows\Application.ini。该路径 的本地部分表明这样一个事实，即当帐户具有漫游配置文件时，虚拟化文件不会随配置文件的其余部分漫游。</p>  <p>如果在资源管理器中导航到一个包含虚拟化文件的目录，资源管理器将在其工具栏中显示一个标记为&#8220;兼容性文件&#8221;的按钮，如图 3 所示。单击该按钮可导航至对应的 VirtualStore 子目录以显示虚拟化文件。</p>    <div style="display: block; margin: 5px 0px 10px 5px; width: 400px;"><a rel="nofollow" href="http://blog.163.com/wumings_2005/blog/static/231434032007930552891/%27390666006%27%29;"><img alt="图 3 &#8220;兼容性文件&#8221;按钮指明了附近的虚拟化文件" src="http://www.microsoft.com/technet/technetmag/issues/2007/06/UAC/zh//fig03.gif" width="400" height="234" border="0" /></a><br />图 3&nbsp;&#8220;兼容性文件&#8221;按钮指明了附近的虚拟化文件 (单击该图像获得较大视图) </div>  <p>图 4  显示 UAC 文件虚拟化筛选器驱动程序 (%SystemRoot%\System32\Drivers\Luafv.sys)  如何实施文件系统虚拟化。因为它是文件系统筛选器驱动程序，所以它会看到所有文件系统操作，但是仅为来自旧进程的操作实施功能。您可以看到它为在系统全局 位置创建文件的旧进程更改了目标文件路径，但是没有为以标准用户权限运行 Windows Vista  应用程序的进程进行此更改。当它确实在用户具有完全访问权限的位置创建了文件时，旧进程便认为操作成功，但在 \Windows  目录上的默认权限会拒绝对为 Windows Vista 编写的应用程序的访问。</p>  <div style="display: block; margin: 5px 0px 10px 5px; width: 300px;"><img alt="图 4 文件系统虚拟化" src="http://www.microsoft.com/technet/technetmag/issues/2007/06/UAC/zh//fig04.gif" width="300" height="434" border="0" /><br />图 4&nbsp;文件系统虚拟化</div>  <p>注册表虚拟化的实施与文件系统虚拟化略有不同。虚拟化的注册表项包括 HKEY_LOCAL_MACHINE\Software 分支的大部分，但有许多例外项，例如以下项：</p>  <pre>HKLM\Software\Microsoft\Windows  HKLM\Software\Microsoft\Windows NT  HKLM\Software\Classes   </pre>    <p>只 有通常由旧应用程序修改，但不会带来兼容性或互操作性问题的项才能虚拟化。Windows 将旧应用程序对虚拟化项的修改重定向到位于 HKEY_  CURRENT_USER\Software\Classes\VirtualStore 的用户注册表虚拟根目录。该项位于用户的 Classes  配置单元 %LocalAppData%\Microsoft\Windows\UsrClass.dat  中，与任何其他虚拟化文件数据一样，它并不随漫游用户配置文件漫游。</p>  <p>与  Windows 为文件系统维护一个固定虚拟化位置列表不同，注册表项的虚拟化状态作为一个标志 REG_ KEY_DONT_VIRTUALIZE  存储在该项自身。Reg.exe 实用工具可以显示该标志以及另外两个虚拟化相关标志：REG_KEY_ DONT_SILENT_FAIL 和  REG_KEY_ RECURSE_FLAG，如图 5 所示。当设置了 REG_KEY_DONT_SILENT_FAIL  并且该项未虚拟化（已设置  REG_KEY_DONT_VIRTUALIZE）时，除了应用程序请求的访问外，原本被拒绝对该项执行操作访问的旧应用程序还将被授予用户对该项所拥有 的任何访问权限。REG_KEY_RECURSE_FLAG 表明新的子项是否继承父项的虚拟化标志，而不仅仅是默认标志。</p>    <div style="display: block; margin: 5px 0px 10px 5px; width: 400px;"><a rel="nofollow" href="http://blog.163.com/wumings_2005/blog/static/231434032007930552891/%27216501010%27%29;"><img alt="图 5 Reg 实用工具显示虚拟化标志" src="http://www.microsoft.com/technet/technetmag/issues/2007/06/UAC/zh//fig05.gif" width="400" height="172" border="0" /></a><br />图 5&nbsp;Reg 实用工具显示虚拟化标志 (单击该图像获得较大视图) </div>  <p>图 6 显示了配置管理器如何实施注册表虚拟化，该管理器管理操作系统内核 Ntoskrnl.exe 中的注册表。对于文件系统虚拟化，创建虚拟化项的子项的旧进程将被重定向到用户的注册表虚拟根，但默认权限会拒绝 Windows Vista 进程的访问。</p>  <p>除 了文件系统和注册表虚拟化以外，某些应用程序还需要其他帮助才能在标准用户权限下正确运行。例如，对于测试其正在运行的帐户是否是  Administrators 组成员的应用程序，如果是该组成员，则会正常运行，如果不是，则不能正常运行。因此，Windows Vista  定义了许多应用程序兼容性填充，以使这类应用程序无论如何都能够运行。最常应用于旧应用程序以使其在标准权限下操作的填充如<a target="_self" rel="nofollow" href="http://www.microsoft.com/technet/technetmag/issues/2007/06/UAC/default.aspx?pf=true&amp;fig=true#fig7">图 7</a>  所示。企业 IT 专业人员可以使用诸如应用程序兼容性工具包（ACT，可从 technet.microsoft  .com/windowsvista/aa905066.aspx 获得），及其标准用户分析程序 (SUA) 实用工具，或 Aaron  Margosis 的 <a rel="nofollow" href="http://blogs.msdn.com/aaron_margosis/archive/2006/08/07/LuaBuglight.aspx">LUA Buglight</a>  等工具来确认其 LOB 应用程序的填充要求。他们使用 Compatibility Administrator（也是 ACT  的一部分）将填充分配给应用程序，然后将得到的兼容性数据库（.sdb  文件）通过组策略部署到桌面。请注意，如果需要，可以对使用全局安全策略设置的系统完全禁用虚拟化。</p>  <div>  <div>虚拟化的效果</div>  <p>在 &#8220;任务管理器&#8221;中右键单击某个进程并从上下文菜单中选择&#8220;虚拟化&#8221;，即可更改进程的虚拟化状态。图 A  显示了当其虚拟化状态更改时命令提示符的行为。开始时虚拟化是禁用的，因为它有一个 Windows Vista  指令清单。因为它使用标准用户权限运行，所以无法在 \Windows  目录中创建文件，但是在使用任务管理器将其虚拟化后，它似乎能够成功创建该文件。当其虚拟化返回禁用状态时，它将找不到该文件，该文件实际位于用户的虚拟 存储中。</p>    <div style="display: block; margin: 5px 0px 10px 5px; width: 400px;"><a rel="nofollow" href="http://blog.163.com/wumings_2005/blog/static/231434032007930552891/%27443600038%27%29;"><img alt="图 A 虚拟化状态更改" src="http://www.microsoft.com/technet/technetmag/issues/2007/06/UAC/zh//figA.gif" width="400" height="296" border="0" /></a><br />图 A&nbsp;虚拟化状态更改 (单击该图像获得较大视图) </div></div><br />管理员批准模式<br />  <p>即 使用户只运行与标准用户权限兼容的程序，某些操作仍要求管理权限。绝大多数软件安装都要求使用管理权限，以便在系统全局位置创建目录或注册表项，或者安装 服务或设备驱动程序。修改系统全局 Windows 设置和应用程序设置也要求使用管理权限，Windows Vista  家长控制功能便是如此。通过切换到专用管理帐户可以执行大多数这些操作，但是这样很不方便，导致多数用户仍然会使用管理帐户来执行其日常任务。</p>  <p>因此，Windows Vista 提供了一个增强的&#8220;运行身份&#8221;功能，以使标准用户能够方便地以管理权限启动进程。此功能要求为应用程序提供一种方式来标识系统可为之获得管理权限（代表该应用程序）的操作，我将对此进行简要说明。</p>  <p>此 外，Windows Vista 还引入了一个管理员批准模式  (AAM)，这样，作为系统管理员的用户便可以使用标准用户权限来运行，而不必在每次希望获得管理权限时输入用户名和密码。此功能在登录时为用户创建两个 身份：一个具有标准用户权限，另一个具有管理权限。由于 Windows Vista 系统上的每个用户要么是标准用户，要么多数情况下作为 AAM  中的标准用户来运行，因而开发人员必须假定所有 Windows 用户都是标准用户，这将导致有更多的程序使用不带有虚拟化或填充的标准用户权限来运行。</p>  <p>为进程授予管理权限称为提升。由标准用户帐户执行此过程时，称为&#8220;当面式&#8221;(OTS) 提升，因为它要求输入某个管理员组的成员帐户的凭据，这通常由另一个用户当着该标准用户的面完成。由 AAM 用户执行的提升称为&#8220;同意&#8221;提升，因为用户只需批准其管理权限的分配即可。</p>  <p>如果用户是<a target="_self" rel="nofollow" href="http://www.microsoft.com/technet/technetmag/issues/2007/06/UAC/default.aspx?pf=true&amp;fig=true#fig8">图 8</a>  中所列任意管理员类型组的成员，Windows Vista  就会将该用户视为管理员。所列的许多组都只用于加入域的系统，并且不直接赋予用户本地管理权限，但是允许他们修改域范围内的设置。如果用户是其中任何组的 成员，而不是实际的管理员组的成员，该用户将通过 OTS 提升而不是&#8220;同意&#8221;提升来获得其管理权限。</p>  <p>当属于所列的某个组的用户登录时，Windows Vista 将创建一个令牌，代表该用户的管理身份的标准用户版本。新令牌解除了分配给该用户的所有特权，只保留了<a target="_self" rel="nofollow" href="http://www.microsoft.com/technet/technetmag/issues/2007/06/UAC/default.aspx?pf=true&amp;fig=true#fig9">图 9</a> 中所列的那些特权，它们是默认标准用户特权。此外，任何管理员类型组在该新令牌中都带有 USE_FOR_DENY_ONLY 标志。图 10 显示了 Sysinternals Process Explorer（一种进程管理工具，可从 <a rel="nofollow" href="http://www.microsoft.com/technet/sysinternals">microsoft .com/technet/sysinternals</a> 下载），其左侧显示了使用管理权限运行的进程的组成员关系和特权，右侧显示了不具备管理员权限的情况。（为防止意外错误使用，Windows 安全模型要求先启用带有禁用标志的特权，然后才能使用它。）</p>    <div style="display: block; margin: 5px 0px 10px 5px; width: 400px;"><a rel="nofollow" href="http://blog.163.com/wumings_2005/blog/static/231434032007930552891/%27499905012%27%29;"><img alt="图 10 AAM 管理员和标准用户令牌" src="http://www.microsoft.com/technet/technetmag/issues/2007/06/UAC/zh//fig10.gif" width="400" height="220" border="0" /></a><br />图 10&nbsp;AAM 管理员和标准用户令牌 (单击该图像获得较大视图) </div>  <p>具 有&#8220;仅拒绝&#8221;标志的组只能用于拒绝（而不能允许）用户对某个资源的访问，这样就消除了当该组被整个删除时所产生的安全漏洞。例如，如果某个文件的访问控制 列表 (ACL) 拒绝了 Administrators  组的所有访问，但为该用户所属的另一个组授予某些访问权限，那么如果令牌中没有管理员组，则会为用户授予访问权限，从而为该用户身份的标准用户版本赋予比 管理员身份更多的权限。</p>  <p>独立系统（通常是家用计算机）和加 入域的系统对来自远程用户的 AAM  访问的处理不同，因为连接了域的计算机可以在其资源权限内使用域管理组。当用户访问独立计算机的文件共享时，Windows  将请求该远程用户的标准用户身份，但在加入域的系统上，Windows 将通过请求该用户的管理身份来支持其所有域组成员。</p><br />方便地获得管理权限<br />  <p>系 统和应用程序可以通过多种方式标识对管理权限的需求。其中一个是显示在资源管理器 UI  中的&#8220;以管理员身份运行&#8221;上下文菜单项和快捷方式选项。这些项目包含一个彩色盾牌图标，它应放在任何按钮或菜单项上，当选中它时会导致权限的提升。选择 &#8220;以管理员身份运行&#8221;菜单项将使资源管理器使用动词&#8220;runas&#8221;调用 ShellExecute API。</p>  <p>绝 大多数安装程序都要求使用管理权限，因此，映像加载程序（用于触发可执行文件的启动）包含了安装程序检测代码以发现可能的旧安装程序。它使用的某些启发方 式很简单，只需检测该映像在其文件名或内部版本信息中是否具有设置 (setup)、安装 (install) 或更新 (update)  字样；较为复杂的启发方式则涉及扫描可执行文件中的字节序列，第三方安装包装实用工具大多为这种情况。</p>  <p>映像加载器还会调用应用程序兼容性 (appcompat) 库，以查看目标可执行文件是否要求使用管理员权限。该库将查询应用程序兼容性数据库，以查看该可执行文件是否关联了 RequireAdministrator 或 RunAsInvoker 兼容性标志。</p>  <p>可 执行文件请求得到管理权限的最常用方式是在其应用程序指令清单文件中包含一个 requestedElevationLevel 令牌。指令清单是  XML 文件，其中包含有关某个映像的补充信息。它们是在 Windows XP 中引入的，作为标识与并列 DLL 和 Microsoft .NET  Framework 程序集的依赖关系的一种方式。指令清单中出现的 trustInfo 元素（可在下面的  Firewallsettings.exe 字符串转储摘录中看到）表明这是一个为 Windows Vista 编写的可执行文件，并且其中嵌套了  requestedElevationLevel 元素。该元素的 level  属性可具有以下三个值之一：asInvoker、highestAvailable 和 requireAdministrator。</p>  <pre>&lt;trustInfo    xmlns=&#8221;urn:schema-microsoft-com:asm.v3&#8221;&gt;   &lt;security&gt;    &lt;requestedPrivileges&gt;     &lt;requestedExecutionLevel      Level=&#8221;requireAdministrator&#8221;      uiAccess=&#8221;false&#8221;/&gt;    &lt;/requestedPrivileges&gt;   &lt;/security&gt;  &lt;/trustInfo&gt;  </pre>    <p>不 需要管理权限的可执行文件（如 Notepad.exe）指定 asInvoker  值。某些可执行文件预期管理员始终希望具有最大访问权限，因此他们使用 highestAvailable  值。如果某用户运行具有该值的可执行文件，那么仅当他在 AAM  中运行或被视为管理员（根据早先定义的规测）且必须提升以获得其管理权限时，才会要求提升他的权限。例如，Regedit.exe、Mmc.exe 和  Eventvwr.exe 都是使用 highestAvailable 的应用程序。最后，requireAdministrator  始终会导致提升请求，任何没有管理权限就无法操作的可执行文件需要使用该值。</p>  <p>可访问性应用程序为 uiAccess 属性指定&#8220;true&#8221;，以便驱动所提升进程的窗口输入，并且它们还必须带有签名并位于多个安全位置（包括 %SystemRoot% 和 %ProgramFiles%）之一以获取该能力。</p>  <p>确定可执行文件所指定值的一种简单方法是使用 Sysinternals Sigcheck 实用工具查看其指令清单，如下所示：</p>  <pre>sigcheck &#8211;m &lt;executable&gt;   </pre>    <p>执 行一个请求管理权限的映像将导致在服务主机进程 (%SystemRoot%\System32\Svchost .exe)  中运行的应用程序信息服务（也称为 AIS，它包含在 %SystemRoot%\System32\Appinfo.dll 中）启动  Consent.exe (%SystemRoot%\System32\Consent.exe)。Consent  将捕获屏幕的位图、向其应用一个淡入淡出效果、切换到只能由本地系统帐户访问的桌面、将该位图作为背景、并显示一个提升对话框，其中包含有关该可执行文件 的信息。在单独的桌面上显示可防止用户帐户中的任何恶意软件修改对话框的外观。</p>    <div style="display: block; margin: 5px 0px 10px 5px; width: 400px;"><a rel="nofollow" href="http://blog.163.com/wumings_2005/blog/static/231434032007930552891/%271194439014%27%29;"><img alt="图 11 OTS 提升对话框" src="http://www.microsoft.com/technet/technetmag/issues/2007/06/UAC/zh//fig11.gif" width="400" height="1087" border="0" /></a><br />图 11&nbsp;OTS 提升对话框 (单击该图像获得较大视图) </div>  <p>如果映像是由 Microsoft 数字签名的 Windows 组件，并且位于 Windows 系统目录中，则对话框顶部将显示一条蓝带，如图 11  顶部所示。灰带（对话框中间）表明映像由 Microsoft  以外的组织数字签名，橙色带（对话框底部）表明映像未经签名。提升对话框显示了映像的图标、描述以及数字签名映像的发布者，但对于未签名的映像只有一个通 用的图标、文件名和&#8220;未能识别的发布程序&#8221;。这样就使恶意软件更难以模仿合法软件的外观。对话框底部的&#8220;详细信息&#8221;按钮展开后将显示当可执行文件启动时要 传递给它的命令行。图 12 所示的&#8220;AAM 同意&#8221;对话框与此类似，但它不会提示提供管理员凭据，而是包含了&#8220;继续&#8221;和&#8220;取消&#8221;按钮。</p>    <div style="display: block; margin: 5px 0px 10px 5px; width: 400px;"><a rel="nofollow" href="http://blog.163.com/wumings_2005/blog/static/231434032007930552891/%27249439016%27%29;"><img alt="图 12 AAM 提升对话框" src="http://www.microsoft.com/technet/technetmag/issues/2007/06/UAC/zh//fig12.gif" width="400" height="226" border="0" /></a><br />图 12&nbsp;AAM 提升对话框 (单击该图像获得较大视图) </div>  <p>如 果用户拒绝提升，Windows 将向激发该启动过程的进程返回一个拒绝访问错误。当用户通过输入管理员凭据或单击&#8220;继续&#8221;同意提升时，AIS 将调用  CreateProcessAsUser 以使用适当的管理身份启动进程。虽然从技术上讲 AIS 是所提升进程的父项，但 AIS 使用了  CreateProcessAsUser API 中的新支持，后者将该进程的父进程 ID 设为最初启动它的进程的 ID（请参阅图 13）。这就是在显示进程树的工具（如 Process Explorer）中，已提升进程没有显示为 AIS Service Hosting 进程的子项的原因。</p>  <div style="display: block; margin: 5px 0px 10px 5px; width: 300px;"><img alt="图 13 提升流程" src="http://www.microsoft.com/technet/technetmag/issues/2007/06/UAC/zh//fig13.gif" width="300" height="363" border="0" /><br />图 13&nbsp;提升流程</div>  <p>即 使提升对话框显示在单独的安全桌面上，默认情况下，用户也无法验证他们查看的是合法对话框，而不是由恶意软件提供的对话框。这并不是 AAM  的问题，因为恶意软件虽无法使用假的&#8220;同意&#8221;对话框获取管理权限，但它可以等待标准用户的 OTS  提升，截获它，并使用特洛伊木马对话框捕获管理员凭据。使用那些凭据，它们可以获得对管理员帐户的访问权限并感染它。</p>  <p>因此，强烈建议不要在企业环境中使用 OTS 提升。要禁用 OTS 提升（并减少咨询台呼叫），请运行本地安全策略编辑器 (Secpol.msc) 并将&#8220;用户帐户控制：标准用户的提升提示行为&#8221;配置为&#8220;自动拒绝提升请求&#8221;。</p>  <p>注 重安全的家庭用户应当将 OTS 提升配置为要求使用一个恶意软件无法截获或模拟的安全注意序列 (SAS)。要配置 SAS，请运行组策略编辑器  (Gpedit.msc)，导航到&#8220;计算机配置&#8221;|&#8220;管理模板&#8221;|&#8220;Windows  组件&#8221;|&#8220;凭据用户界面&#8221;，并启用&#8220;要求输入凭据的受信任路径&#8221;。完成上述步骤后，会要求您输入 Ctrl+Alt+Delete 以访问提升对话框。</p><br />隔离已提升的进程<br />  <p>Windows  Vista  在已提升进程周围设置了一道屏障，以保护它们免受在同一桌面上使用标准用户权限运行的恶意软件的侵扰。如果没有这道屏障，恶意软件可能会通过窗口消息发送 合成的鼠标和窗口输入，从而驱动某个管理应用程序。虽然标准 Windows  安全模型可防止使用标准用户权限在进程中运行的恶意软件破坏作为不同用户运行的已提升进程，但它不会禁止作为某个管理用户的标准权限版本运行的恶意软件打 开该用户的已提升进程、向其中插入代码并启动其中的线程以执行插入的代码。</p>  <p>Windows  Vista 为窗口消息提供的防护称为用户界面特权隔离 (UIPI)。它基于新的 Windows 完整性机制，Windows Vista  同样使用该机制作为已提升进程周围的屏障。在此新安全模型中，所有进程和对象都具有完整性级别，并且对象的完整性策略可以限制访问权限，否则，这些访问权 限将由 Windows 随机访问控制 (DAC) 安全模型授予某个进程。</p>  <p>完整性级别 (IL) 由安全标识符 (SID) 表示，后者还表示用户和组；而级别则编码在 SID 的相对标识符 (RID) 中。<a target="_self" rel="nofollow" href="http://www.microsoft.com/technet/technetmag/issues/2007/06/UAC/default.aspx?pf=true&amp;fig=true#fig14">图 14</a> 显示了四个主要 IL 的显示名称、SID 和 SID 的 RID 的十六进制版本。十六进制数字揭示了每个级别间的 0x1000 的间隔，以便提供由 UI 可访问性应用程序使用的中间级别并考虑未来增长需要。</p>  <p><a target="_self" rel="nofollow" href="http://www.microsoft.com/technet/technetmag/issues/2007/06/UAC/default.aspx?pf=true&amp;fig=true#fig15">图 15</a>  列出了对象 IL 策略以及它们所限制的访问类型，这些访问类型与为对象定义的通用访问权限相对应。例如，No-Write-Up 将禁止低 IL  进程获取任何由 GENERIC_WRITE 访问权限表示的访问权限。大多数对象（包括文件和注册表项）的默认策略都是  No-Write-Up，这将禁止进程从具有比它更高的 IL 的对象获取写访问权限，即使该对象的随机访问控制列表 (DACL)  授予用户这种访问权限也是如此。仅有的具有不同策略的对象是进程对象和线程对象。它们的策略（No-Write-Up 加上  No-Read-Up）会禁止在低 IL 上运行的进程向具有较高 IL 的进程插入代码或从中读取数据（如密码）。</p>  <p>Windows 为每个进程分配一个 IL，该 IL 放在进程令牌中组 SID 的旁边，这些组是运行该进程的用户所属的组。<a target="_self" rel="nofollow" href="http://www.microsoft.com/technet/technetmag/issues/2007/06/UAC/default.aspx?pf=true&amp;fig=true#fig16">图 16</a>  列出了分配给不同 IL 的进程示例。进程通常继承其父项的 IL，但进程也可以在其他 IL 上启动进程，与 AIS  启动已提升进程时的操作相同。您可以通过指定 /all 选项使用内置的 Whoami 实用工具、Sysinternals Process  Explorer 或 AccessChk 来查看进程完整性级别。Process Explorer 可以在附加的&#8220;完整性级别&#8221;列中显示进程 IL。</p>  <p>每 个安全对象都有一个显式或隐式的 IL。进程、线程和令牌对象始终具有一个显式分配的 IL，它通常与对应进程令牌中存储的 IL  相同。多数对象都没有显式 IL，因此都默认为某个中等 IL。使用中等以外的 IL 创建的仅有对象是由在低 IL  上运行的进程创建的对象，它们因此而具有一个低 IL。您可以使用内置的 iCacls 工具  (%SystemRoot%\System32\iCacls.exe) 查看文件的 IL，并使用 Sysinternals AccessChk  实用工具查看文件、注册表项、服务和进程的 IL。图 17 显示需要通过保护模式 Internet Explorer 才能访问的目录的 IL 为&#8220;低&#8221;。</p>    <div style="display: block; margin: 5px 0px 10px 5px; width: 400px;"><a rel="nofollow" href="http://blog.163.com/wumings_2005/blog/static/231434032007930552891/%27248677020%27%29;"><img alt="图 17 显示用户收藏夹目录 IL 的 AccessChk" src="http://www.microsoft.com/technet/technetmag/issues/2007/06/UAC/zh//fig17.gif" width="400" height="146" border="0" /></a><br />图 17&nbsp;显示用户收藏夹目录 IL 的 AccessChk (单击该图像获得较大视图) </div>  <p>如果对象具有显式 IL，则它存储在 Windows Vista 中新引入的一种访问控制项 (ACE) 类型中（即 Label ACE），该 ACE 位于对象安全描述符的系统访问控制列表 (SACL) 中（请参阅图 18）。 ACE 中的 SID 对应于对象的 IL，ACE 的标志为对象的完整性策略进行了编码。在 Windows Vista 之前，SACL 只存储审核  ACE，这需要&#8220;管理审核和安全日志&#8221;特权 (SeSecurityPrivilege)，但读取 Label ACE  只需要&#8220;读取权限&#8221;(READ_CONTROL) 访问权限。如果进程要修改对象的 IL，它必须具有该对象的&#8220;更改所有者&#8221;(WRITE_OWNER)  访问权限以及一个与该对象相同或更高的 IL，并且该进程只能将 IL 设置为自己的 IL 或更低的  IL。新的&#8220;修改对象标签&#8221;(SeRelabelPrivilege) 特权使进程能够更改它可以访问的任何对象的 IL，甚至将 IL  提高到超过进程自己的 IL，但默认情况下，该特权未分配给任何帐户。</p>  <div style="display: block; margin: 5px 0px 10px 5px; width: 400px;"><img alt="图 18 对象的 Label ACE" src="http://www.microsoft.com/technet/technetmag/issues/2007/06/UAC/zh//fig18.gif" width="400" height="203" border="0" /><br />图 18&nbsp;对象的 Label ACE</div>  <p>当 进程尝试打开某个对象时，内核的 SeAccessCheck 功能中将先进行完整性检查，然后再进行标准的 Windows DACL  检查。在默认完整性策略下，仅当进程的 IL 等于或高于对象的 IL，且 DACL  也为该进程授予了它所需要的权限时，该进程才能打开此对象进行写访问。例如，低 IL 进程不能打开中等 IL 进程进行写访问，即使 DACL  为该进程授予了写访问权限。</p>  <p>在默认完整性策略下，进程可以 打开任何对象（进程和线程对象除外）进行读取访问，只要对象的 DACL 为它们授予了读取权限即可。这意味着，在低 IL  上运行的进程可以打开任何其运行所在的用户帐户可以访问的文件。保护模式 Internet Explorer 使用 IL  来帮助防止感染它的恶意软件修改用户帐户设置，但是它不能禁止恶意软件读取用户的文档。</p>  <p>上述情况不适用于进程和线程对象，因为它们的完整性策略还包括 No-Read-Up。这意味着，进程的 IL 必须等于或高于它要打开的进程或线程的 IL，且 DACL 必须授予它成功打开所需的访问权限。假设 DACL 允许授予所需的权限，图 19 显示了在中等和低 IL 上运行的进程针对其他进程和对象所拥有的访问权限。</p>  <div style="display: block; margin: 5px 0px 10px 5px; width: 300px;"><img alt="图 19 对象和进程访问权限" src="http://www.microsoft.com/technet/technetmag/issues/2007/06/UAC/zh//fig19.gif" width="300" height="249" border="0" /><br />图 19&nbsp;对象和进程访问权限</div>  <p>Windows  消息传递子系统还支持完整性级别通过以下方式实施 UIPI：禁止进程向具有较高 IL  的进程所拥有的窗口发送除信息性窗口消息以外的任何消息。这将不允许标准用户进程向已提升进程的窗口进行输入，或不允许通过向其发送可触发内部缓冲区溢出 的格式不正确的消息来破坏已提升进程。进程可以通过调用 ChangeWindowMessageFilter API  选择允许其他消息通过这层防范。UIPI 还会防止窗口挂接影响较高 IL  进程的窗口，这样，例如标准用户进程便无法记录用户在管理应用程序中的键击情况。</p><br />提升和安全边界<br />  <p>UAC 提升是一种方便性，而不是安全边界，清楚这一点很重要。安全边界要求安全策略指明能够通过该边界的内容。用户帐户就是 Windows 中安全边界的一个示例，因为如果没有另一个用户的许可，某个用户就无法访问属于另一个用户的数据。</p>  <p>因 为提升不是安全边界，所以无法保证使用标准用户权限在系统上运行的恶意软件不会侵扰已提升进程以获取管理权限。例如，提升对话框只标识了即将提升的可执行 文件；其中没有提供执行时将如何操作的任何信息。可执行文件将处理命令行参数、加载  DLL、打开数据文件并与其他进程通信。可以想象，上述任何操作都可能允许恶意软件侵扰已提升进程，进而获取管理权限。</p>  <div>  <div>低 IL 沙盒中的游戏</div>  <p>保 护模式 Internet Explorer 在低 IL  上运行，以便在可能感染其进程的恶意软件周围筑起一道围墙。这将防止恶意软件更改用户帐户设置并将自己安装在一个自动启动位置。您可以使用  Sysinternals PsExec 实用工具和 -l 开关，在低 IL 上启动任意进程以探究沙盒的秘密。图 B 显示了在低 IL  上运行的命令提示符如何无法在用户的临时目录（具有中等 IL）中创建文件，却能够在具有低 IL 的 Internet Explorer  临时目录中创建该文件。 </p>    <div style="display: block; margin: 5px 0px 10px 5px; width: 400px;"><a rel="nofollow" href="http://blog.163.com/wumings_2005/blog/static/231434032007930552891/%27389600036%27%29;"><img alt="图 B 命令提示符只能在相似的 IL 中创建文件" src="http://www.microsoft.com/technet/technetmag/issues/2007/06/UAC/zh//figB.gif" width="400" height="259" border="0" /></a><br />图 B&nbsp;命令提示符只能在相似的 IL 中创建文件 (单击该图像获得较大视图) </div></div>  <p>已 提升的 AAM 进程尤其易受侵扰，因为它们在与 AAM  用户的标准权限进程相同的用户帐户下运行，并共享用户的配置文件。许多应用程序读取在用户配置文件中注册的设置并加载在其中注册的扩展，这为恶意软件的提 升提供了机会。例如，常用控制对话框会加载在用户的注册表项（位于 HKEY_CURRENT_USER  下）中配置的外壳扩展，因此恶意软件可以将其自身作为一项扩展添加进去，以加载到使用那些对话框的任何已提升进程中。</p>  <p>即 使是从标准用户帐户提升的进程也必定会因共享状态而受到侵扰。在某个登录会话中运行的所有进程将共享 Windows  用来存储对象（如事件、mutex、信号和共享内存）的内部命名空间。如果恶意软件知道某个已提升进程将在进程启动时尝试打开并读取特定共享内存对象，它 可以创建该对象，而其内容将触发缓冲区溢出以便将代码插入到已提升进程中。这种攻击类型比较复杂，但其存在的可能性使得 OTS  提升无法成为一种安全边界。</p>  <p>我们的底线是引入提升以提供方 便，从而鼓励要获得管理权限的用户在默认情况下使用标准用户权限运行。希望安全边界有保障的用户可以用方便性换取这种保障，此时，可以为日常任务使用标准 用户帐户，同时使用快速用户切换 (FUS)  切换到专用管理员帐户来执行管理操作。另一方面，希望用安全性换取方便性的用户可以在&#8220;控制面板&#8221;的&#8220;用户帐户&#8221;对话框中禁用系统上的  UAC，但是必须清楚，这同时也会禁用 Internet Explorer 的保护模式。</p><br />结束语<br />  <p>以 标准用户身份运行有许多好处，其中包括有助于保护系统免受无意或有意的损害，以及防止共享系统的用户的数据和完整性受到未经授权的访问。UAC  的各种变化和技术将导致 Windows 使用模型发生重要改变。在 Windows Vista 中，Windows  用户第一次能够使用标准用户权限执行大多数日常任务并运行大多数软件，现在，许多企业都能够部署标准用户帐户。</p><br />  <hr /><img src ="http://www.cppblog.com/gxhzippo/aggbug/172658.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/gxhzippo/" target="_blank">在路上2011</a> 2012-04-24 20:57 <a href="http://www.cppblog.com/gxhzippo/archive/2012/04/24/172658.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>UAC 虚拟化</title><link>http://www.cppblog.com/gxhzippo/archive/2012/04/24/172652.html</link><dc:creator>在路上2011</dc:creator><author>在路上2011</author><pubDate>Tue, 24 Apr 2012 12:38:00 GMT</pubDate><guid>http://www.cppblog.com/gxhzippo/archive/2012/04/24/172652.html</guid><wfw:comment>http://www.cppblog.com/gxhzippo/comments/172652.html</wfw:comment><comments>http://www.cppblog.com/gxhzippo/archive/2012/04/24/172652.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/gxhzippo/comments/commentRss/172652.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/gxhzippo/services/trackbacks/172652.html</trackback:ping><description><![CDATA[<strong>UAC 虚拟化</strong><br /> <br /> <strong>虚拟化</strong><br /> <br /> <strong>注意</strong><br /> 虚拟化的引入是为了改进 Windows Vista 上以标准用户运行的程序的兼容性。开发人员不应依赖于现在及后续版本 Windows 中存在的虚拟化。<br /> <br /> 在 Windows Vista  之前，许多应用程序通常是被管理员运行的。结果是，应用程序可以自由地读写系统文件和注册表键。如果标准用户运行这些程序，这些操作会由于权限不足而失 败。Windows Vista  通过重定向对用户配置文件中每个用户的写操作（以及后续的文件或注册表操作）来改进标准用户程序的兼容性。例如，如果一个程序试图写入到  C:\Program Files\Contoso\Settings.ini，但用户没有写入那个目录的权限，这个写操作就会被重定向至  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。<br /> <br /> 下图详细显示了 Windows Vista 中的虚拟化过程。在这个例子里，Denise 是处于 <strong><a href="http://blogs.itecn.net/blogs/ahpeng/archive/2007/05/21/InsideUAC2.aspx" target="_blank">管理员批准模式</a></strong>中的管理员，而 Brian 是标准用户。虚拟化由两部分构成：<strong>文件虚拟化</strong>和 <strong>注册表虚拟化</strong>。<br /> <br /> <strong>虚拟化过程</strong><br /> <img src="http://i.msdn.microsoft.com/dynimg/IC85459.gif" alt="" width="311" height="287" border="0" /><br /> <br /> <strong>注意</strong><br /> 当开发 Windows Vista 程序时，为了减少虚拟化文件和注册表的复杂度，确保内嵌一个包含适当 requestedExecutionLevel（请求执行等级）的应用程序清单(manifest) 以关闭文件和注册表虚拟化。<br /> <br /> <strong>虚拟化在以下情况启用：</strong><br /> <ul><li>32 位交互式程序<br /> </li></ul><ul><li>管理员才可写入的文件/文件夹和注册表键<br /> </li></ul><br /> <strong>虚拟化在以下情况禁用：</strong><br /> <ul><li>64 位程序</li><li>非交互式程序</li><li>模拟（令牌？）的进程 (Processes that impersonate)</li><li>内核模式调用方<br /> </li></ul><ul><li>带有 requestedExecutionLevel（请求执行等级）的可执行程序<br /> </li></ul><br /> <br /> <strong>虚拟化与漫游:</strong> （漫游：<a href="http://baike.baidu.com/view/119296.htm" target="_blank">http://baike.baidu.com/view/119296.htm</a>）<br /> 虚拟化的文件/文件夹和注册表键不漫游<br /> 和全局对象有关的不漫游<br /> <br /> <strong>文件虚拟化</strong><br /> <br /> 文件虚拟化解决了应用程序需要在仅管理员可写位置存储文件 &#8212;&#8212; 比如配置文件 &#8212;&#8212; 的情况。这种情况下以标准用户运行程序可能会由于权限不足导致程序错误。<br /> <br /> 当应用程序写入到仅管理员可写位置时，Windows 就会将所有后续文件操作写入到 VirtualStore  目录下的指定路径，VirtualStore 目录位于  %LOCALAPPDATA%\VirtualStore。然后，当程序再次读取这个文件时，电脑会提供 VirtualStore  目录里的那一份文件。因为 Windows 安全基础设施可以在没有应用程序协助的情况下完成虚拟化，程序认为它自己成功地直接读写了 Program  Files 目录。文件虚拟化的透明使应用程序觉得它们正在读写受保护的资源，然而事实是它们在访问虚拟化的资源。<br /> <br /> <strong>注意</strong><br /> 当你枚举文件夹和注册表中的资源时，Windows Vista 会将这些文件/文件夹和注册表键合并到一个列表中。在这种合并视图中，受保护资源看起来和虚拟化的资源在同一个目录里。<br /> <br /> <strong>重要</strong><br /> 虚拟化的副本总是被优先提供给程序。例如，config.ini 同时在 \PF\App\config.ini 和  %LOCALAPPDATA%\VirtualStore\config.ini 中出现，程序总是会读取到 VirtualStore(后者)  里的文件，就算 \PF\App\config.ini 已经更新了也一样。<br /> <br /> <br /> <strong>虚拟化资源和视图</strong><br /> <br /> <img src="http://i.msdn.microsoft.com/dynimg/IC16888.gif" alt="" width="329" height="237" border="0" /><br /> <br /> <strong>注册表虚拟化</strong> <br /> 注册表虚拟化与文件虚拟化类似，但应用于 HKEY_LOCAL_MACHINE\SOFTWARE 下的注册表键。这个功能允许以标准用户运行的，需要在 HKEY_LOCAL_MACHINE\SOFTWARE 中存储信息的程序继续工作。键和数据被重定向至 HKEY_CLASSES_ROOT\VirtualStore\SOFTWARE。和文件虚拟化的情况一样，每个用户有一份程序存储在 HKEY_LOCAL_MACHINE中的值的拷贝。 <br /> <br /> <strong>虚拟化建议</strong><br /> 虚拟化只是为了协助已存在的程序改进兼容性。为 Windows Vista 设计的程序不应写入系统敏感区域，也不应依赖虚拟化来纠正错误的程序行为。当更新现有代码以适应 Windows Vista 时，开发人员应确保运行时程序仅在用户个人目录或 %allusersprofile% 这些有合适的访问控制列表(ACL)的地方存储数据。 <br /> <br /> <strong>重要</strong><br /> 微软计划当越来越多的程序兼容 Vista 后，在未来版本的 Windows 中移除虚拟化功能。例如，64位程序的虚拟化是停用的。 <br /> <br /> <strong>下面列出其他文件和注册表虚拟化建议：</strong><br /> 为你的交互式应用程序添加包含合适 requestedExecutionLevel 的应用程序清单。这会将列入清单的程序的虚拟化关闭。 <br /> <br /> 不要将注册表用作进程间通信机制。服务和用户程序所看到的键是不同的。 <br /> <br /> 在 Windows Vista 上测试你的程序：确保以标准用户运行的程序不会写入全局命名空间例如 %systemroot%。 <br /> <br /> 记住虚拟化资源是全局资源（受保护资源）在每个用户中的一份副本（拷贝）。<img src ="http://www.cppblog.com/gxhzippo/aggbug/172652.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/gxhzippo/" target="_blank">在路上2011</a> 2012-04-24 20:38 <a href="http://www.cppblog.com/gxhzippo/archive/2012/04/24/172652.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Windows Vista虚拟化功能故障解决方法</title><link>http://www.cppblog.com/gxhzippo/archive/2012/04/24/172651.html</link><dc:creator>在路上2011</dc:creator><author>在路上2011</author><pubDate>Tue, 24 Apr 2012 12:37:00 GMT</pubDate><guid>http://www.cppblog.com/gxhzippo/archive/2012/04/24/172651.html</guid><wfw:comment>http://www.cppblog.com/gxhzippo/comments/172651.html</wfw:comment><comments>http://www.cppblog.com/gxhzippo/archive/2012/04/24/172651.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/gxhzippo/comments/commentRss/172651.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/gxhzippo/services/trackbacks/172651.html</trackback:ping><description><![CDATA[<p>使用 Windows Vista操作系统的虚拟化功能，你可能会遇到下面所描述的文件和注册表虚拟化问题。</p> <p><strong>情形 1：安装、升级或使用应用程序时收到错误消息</strong></p> <p>在安装、升级或使用应用程序时，可能会收到各种表明拒绝访问的错误消息。例如，您可能会遇到下列症状之一： &#8226; 在文件夹 %programfiles% 之外的其他文件夹中安装了应用程序后，会收到&#8220;拒绝访问&#8221;的错误消息。此外，该应用程序无法正常工作。</p> <p>&#8226; 您收到类似于以下内容的应用程序错误消息：</p> <p>Cannot create folder under C:\MyApp\Temp</p> <p>Cannot create folder under C:\MyApp\Temp\output.dat</p> <p>&#8226; 您收到类似于以下内容的错误消息：</p> <p>写入 MyFile.exe 时出错</p> <p>当您执行下列任一操作时，可能会出现此问题： &#8226; 在虚拟位置创建链接。</p> <p>&#8226; 使用加密文件系统 (EFS) 加密文件。</p> <p>&#8226; 试图查看压缩文件。</p> <p>&#8226; 使用命令提示符向一个虚拟位置复制 .exe、.sys 或 .dll 文件。</p> <p>&#8226; 应用程序中需要文件输入或输出的部分不再正常工作。</p> <p><strong>情形 2：找不到刚创建的文件或文件夹</strong></p> <p>在使用已启用虚拟化的应用程序时，您在文件系统的虚拟位置创建了数据文件。当使用其他应用程序或 Windows  资源管理器访问这些新创建的文件时，却找不到这些文件。例如，如果在照片编辑应用程序中将某文件保存到  %programfiles%、%systemroot% 或 %programdata% 文件夹中，则找不到此文件。</p> <p><strong>情形 3：升级某个应用程序后遇到意外程序行为</strong></p> <p>在升级某个应用程序后，收到类似于以下内容的错误消息：</p> <p>Error. Please upgrade your application</p> <p>此外，该应用程序无法正常工作。应用程序似乎正在使用错误的或升级前的数据。</p> <p><strong>情形 4：在卸载应用程序之后，该应用程序的文件仍在计算机上</strong></p> <p>在这种情况下，您会遇到下列症状之一： &#8226; 在其他应用程序中，您注意到已卸载应用程序的文件和文件夹信息仍存在于 %programfiles%、%programdata% 或 %systemroot% 文件夹中。</p> <p>&#8226; %userprofile%\AppData\Local\VirtualStore 文件夹比预期的大。在卸载应用程序时，未删除在该应用程序运行时创建的虚拟化文件。</p> <p><strong>原因</strong></p> <p>以下一种或多种情况可能会引起这些问题： &#8226; 应用程序试图在某些指定的虚拟化文件夹之外创建文件或文件夹。</p> <p>&#8226; 应用程序在 %programfiles% 文件夹中保存的文件可能指向用户虚拟存储文件夹以外的文件夹。</p> <p>&#8226; 应用程序使用了一个虚拟化不支持的文件。</p><p><strong>解决方案</strong></p> <p><strong>情形 1</strong></p> <p>要确定是否存在情形 1 中描述的问题，请在事件查看器中查找 FileCreateVirtualExclude  事件。为此，请按照下列步骤操作： 1. 单击&#8220;开始&#8221;，在&#8220;开始搜索&#8221;框中键入  eventvwr，然后单击&#8220;程序&#8221;列表中的&#8220;eventvwr.exe&#8221;。</p> <p>如果系统提示您输入管理员密码或进行确认，请键入密码或单击&#8220;继续&#8221;。</p> <p>2.  依次展开&#8220;应用程序和服务日志&#8221;、&#8220;Microsoft&#8221;、&#8220;Windows&#8221;和&#8220;UacFileVirtualization&#8221;，然后选择 &#8220;Operational&#8221;。如果事件 ID 为 5000，则说明已发生 FileCreateVirtualExclude 事件。</p> <p>要解决此问题，请使用下列方法之一： &#8226; 如果该程序尚未安装在 %programfiles% 文件夹中，请将其重新安装在 %programfiles% 文件夹中。</p> <p>&#8226; 使用具有管理凭据的帐户运行此应用程序。为此，请找到并右键单击该应用程序的快捷方式，然后单击&#8220;以管理员身份运行&#8221;。</p> <p>如果系统提示您输入管理员密码或进行确认，请键入密码或单击&#8220;继续&#8221;。</p> <p>&#8226; 在提升的命令提示符处运行该应用程序。为此，请按照下列步骤操作： 1. 单击&#8220;开始&#8221;，然后在&#8220;开始搜索&#8221;框中键入 cmd。</p> <p>2. 在&#8220;程序&#8221;列表中，右键单击&#8220;cmd&#8221;，然后单击&#8220;以管理员身份运行&#8221;。</p> <p>如果系统提示您输入管理员密码或进行确认，请键入密码或单击&#8220;继续&#8221;。</p> <p>3. 键入 MyAppsPath/MyApp，然后按 Enter。MyAppsPath/MyApp 代表应用程序的路径和名称。</p> <p>&#8226; 更改应用程序文件夹的安全设置。为此，请按照下列步骤操作： 1. 以具有管理凭据的用户身份登录，然后使用 Windows 资源管理器打开该应用程序的文件夹。</p> <p>2. 右键单击该应用程序的文件夹，然后单击&#8220;属性&#8221;。</p> <p>3. 在&#8220;安全&#8221;选项卡上，单击&#8220;编辑&#8221;。</p> <p>如果系统提示您输入管理员密码或进行确认，请键入密码或单击&#8220;继续&#8221;。</p> <p>4. 在&#8220;组或用户名&#8221;下，单击您的用户帐户。</p> <p>5. 在&#8220;Users 的权限&#8221;下，对以下权限单击&#8220;允许&#8221;： &#8226; 修改</p> <p>&#8226; 读取和执行</p> <p>&#8226; 列出文件夹目录</p> <p>&#8226; 读取</p> <p>&#8226; 写入</p> <p>6. 单击&#8220;确定&#8221;。</p> <p><strong>情形 2</strong></p> <p>要解决此问题，请使用下列方法之一： &#8226; 单击浏览器栏上显示的&#8220;兼容性文件&#8221;按钮，以查看该文件夹中的虚拟化文件。仅当该文件夹中存在虚拟化文件时，才显示&#8220;兼容性文件&#8221;按钮。</p> <p>&#8226; 在 C:\Users\User_name\AppData\Local\VirtualStore 文件夹中查找文件和文件夹。</p> <p>&#8226; 将应用程序的数据保存在用户配置文件下的文件夹中。</p><p><strong>情形 3</strong></p> <p>警告：如果使用注册表编辑器或其他方法错误地修改了注册表，则可能会出现严重问题。这些问题可能需要重新安装操作系统才能解决。Microsoft 不能保证可以解决这些问题。修改注册表需要您自担风险。</p> <p>要解决此问题，请使用下列方法之一： &#8226; 在提升的命令提示符处运行该应用程序。为此，请按照下列步骤操作： 1. 单击&#8220;开始&#8221;，在&#8220;开始搜索&#8221;框中键入 cmd，然后在&#8220;程序&#8221;列表中单击&#8220;cmd.exe&#8221;。</p> <p>如果系统提示您输入管理员密码或进行确认，请键入密码或单击&#8220;继续&#8221;。</p> <p>2. 键入 MyAppsPath/MyApp。MyAppsPath/MyApp 代表该应用程序的路径和名称，然后按 Enter。</p> <p>&#8226; 打开虚拟存储，然后删除原来的应用程序数据文件。为此，请使用 Windows 资源管理器打开  C:\Users\User_name\AppData\Local\VirtualStore\Program Files\MyApp  文件夹，然后删除您的文档或数据文件之外的所有文件。</p> <p>&#8226; 从注册表中删除虚拟存储。</p> <p>要在注册表中查找虚拟存储并删除所有不需要的注册表项，请按照下列步骤操作： 1. 单击&#8220;开始&#8221;，在&#8220;开始搜索&#8221;框中键入 regedit，然后在&#8220;程序&#8221;列表中单击&#8220;regedit.exe&#8221;。</p> <p>如果系统提示您输入管理员密码或进行确认，请键入密码或单击&#8220;继续&#8221;。</p> <p>2. 找到并单击下面的注册表子项：</p> <p>HKEY_CURRENT_USER\Software\Classes\VirtualStore</p> <p>3. 对于不再需要的任何应用程序注册表项，请右键单击该项，单击&#8220;删除&#8221;，然后单击&#8220;是&#8221;。</p> <p><strong>情形 4</strong></p> <p>要解决此问题，请使用 Windows 资源管理器打开 C:\Users\User_name\AppData\Local\VirtualStore\MyApp 文件夹，然后删除所有过时的应用程序数据。</p> <p><strong>更多信息</strong></p> <p>文件和注册表虚拟化可以帮助对注册表和文件系统只有受限访问权限的用户向这些受保护的区域写入内容。虚拟化会创建一个&#8220;每个用户&#8221;副本，然后重定向 连续的数据操作。 例如，在受限用户帐户下或者在需要&#8220;用户访问控制&#8221;权限的帐户下运行应用程序。当此应用程序向系统位置(如  %programfiles% 文件夹)写入内容时，Windows Vista 会将写入操作和读取操作重定向到用户配置文件文件夹  (%localappdata%\VirtualStore) 中的用户特定位置。默认情况下，此位置为  C:\Users\User_name\AppData\Local\VirtualStore\Program  Files\Application_name。注册表虚拟化的工作原理与之类似，但应用于 HKEY_LOCAL_MACHINE\SOFTWARE  子树下的注册表项。此子树下的注册表项和数据重定向到  HKEY_CURRENT_USER\Software\Classes\VirtualStore 子项。</p><img src ="http://www.cppblog.com/gxhzippo/aggbug/172651.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/gxhzippo/" target="_blank">在路上2011</a> 2012-04-24 20:37 <a href="http://www.cppblog.com/gxhzippo/archive/2012/04/24/172651.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>