Windows 管理权限问题:查找和修复 LUA 错误
 
本文摘自微软网站:
 
  • 最低权限用户帐户
  • 确定真正的 LUA 错误
  • 修复 LUA 错误的技术
您可能熟悉“最低权限原则”,该原则规定,只应为用户提供完成其任务所需的权限。管理安全性时这是一条需要牢记的重要规则,
TechNet 杂志也已对此做过多次讨论。LUA 还可能会引入一些意外的难题。
首字母缩写词 LUA 一般是指“最低权限用户帐户”,不过有时也定义为“受限用户帐户”、“最低用户访问权限”及若干种其他变体。但无论这些字母代表什么,其概念都是相同的。LUA 是一种计算机用户帐户,该帐户无法进行影响系统其他用户或操作系统本身的更改。在 Windows 中,这些帐户通常是内置的 Users 组的成员。该组的成员显然不是高权限组(如 Administrator、Power Users 和 Backup Operators)的成员,它们不具有高级权限(如加载和卸载设备驱动程序及作为操作系统的一部分)。遗憾的是,LUA 会使许多问题显露出来。
如果一个应用程序或应用程序的一个功能在以高级权限运行时能够正常工作,但 LUA 用户却无法使用,而且并没有必须使用高级权限的技术或业务原因,这便是 LUA 错误。一个常见的示例是,应用程序将其设置保存到 HKEY_LOCAL_MACHINE 下的某个注册表项(LUA 用户对其只拥有只读权限),而不是保存到 HKEY_CURRENT_USER 下的某个注册表项。
出现的另一个问题与系统时间有关。Windows XP 不允许 LUA 用户更改系统时间。这并不是 LUA 错误,因为更改系统时间在审核与 Kerberos 协议方面有安全隐患。不过,称 Windows XP 不允许 LUA 用户更改时区这一事实是 LUA 错误却是有根据的。双击任务栏通知区域中的时钟时显示错误消息而不是“日期和时间”小程序的只读视图这一事实也是如此。(请注意,Windows Vista? 极其侧重于提供更加无缝的 LUA 体验,其中包括对“日期和时间”小程序的改进。)
到目前为止,大多数 LUA 错误都归因于注册表和文件系统访问权限。例如,一个程序可能尝试将其设置保存在 %ProgramFiles% 下的安装文件夹中,也可能会尝试使用“完全访问”权限打开 HKLM 下的某个项,即便实际上使用“读取”访问权限便可。其他类型的 LUA 错误包括尝试启动或停止服务、加载设备驱动程序、直接访问硬件资源、创建或管理文件共享,甚至是显式地检查当前用户是否为 Administrators 组的成员。
始终会有一个或多个低级别操作(API 调用),在作为管理员时可以成功执行,但作为 LUA 执行时却会失败。自己可以通过一些工具(如 SysInternals 开发的 Regmon 和 Filemon)来查看其中的一些错误。所查看到的每一个都真的是 LUA 错误吗?这取决于应用程序响应失败的方式。我所见过的响应归类为以下三组:
引发后遗忘:
应用程序只调用操作,不检查结果,但其能否继续正常工作并不取决于操作成功。不是 LUA 错误。

妥善降级:
应用程序调用操作,检查它是否成功,并以适当方式处理故障。不是 LUA 错误。
真正的 LUA 错误:
应用程序调用操作,并假定操作成功,只有操作成功,它才能继续正常工作。这种情况的一个变型是,应用程序检查操作是否成功,但未以适当方式处理故障,如在显示错误消息后死锁。
如果曾使用 Regmon 监视作为 LUA 运行的 GUI 应用程序,则可能看到过可划分为引发后遗忘类别的示例 - 打开 HKLM\System\CurrentControlSet\Control\MediaProperties\PrivateProperties\Joystick\Winmm 以获得“完全访问”权限的尝试失败。为进程初始化游戏杆子系统过程中会出现这种情况。操作会失败,但不会影响应用程序的正常运行。不过,我在 Web 上看到过一条建议(毫无疑问是出自于某个对 Regmon 输出进行了错误解读的人),声称要修复某个特定应用程序,需要为用户授予对该项的完全访问权限。绝对不要这样做!这不是真正的 LUA 错误。永远不需要更改对此项的访问权限!
更改安全性设置之前,请验证所修复的是真正的 LUA 错误,而不只是假想的 LUA 错误,从而确保不存在更好的能够在不增加风险的情况下更正该问题的方法。
如何不修复 LUA 错误
举个例子,有一个您或您的用户需要运行的标准应用程序。该应用程序的设计用途并不是在计算机上执行任何系统管理任务,但由于某个未知的原因,只有通过具有管理员级别访问权限的帐户运行,它才能正常工作。您需要为您的用户授予对该应用程序的访问权限,但又不希望他们以管理员身份运行。您该怎么办呢?
最常见的解决方法是干脆将用户添加到 Administrators 组。有时此操作由服务台技术人员来完成,以确定这样做是否可以修复问题。之后该技术人员便忘记了从 Admins 组中删除该用户,这必然导致他在几周内又接到一个服务台电话,用户在电话中询问“我的计算机为什么运行得这么慢,而且为什么只要我一登录,就会弹出一堆广告呢?”让我们将这种解决方法称作无效方法好了,就不再加以考虑了。
其他两个常见(但不够理想)的解决方法是,只作为管理员运行那一个程序,或在将对该程序的安装文件夹、HKEY_LOCAL_MACHINE 下该程序的所有注册表项以及 HKEY_CLASSES_ROOT 下的所有注册表项的“完全控制”权限授予“每个人”后作为普通用户运行该程序。
对了,在做这件事时,应记得为用户授予“调试”、“取得所有权”以及“作为操作系统的一部分”权限(我当然是在开玩笑,这样做的风险极高,应予避免)。
好了,那么您该怎么办呢?在本文的其余部分,我将介绍一个系统性的方法,既能够解决 LUA 错误,同时又能将风险降至最低。我将按从最可取到最不可取的顺序来介绍这些方法,并列举每个方法的优缺点。顺便说一下,尽管本文中的指导主要面向 Windows XP,这些方法实际上同样适用于 Windows Vista。
它是错误 - 将它视为一个错误并请开发人员进行修复!
这是最佳方法。如果应用程序要求具有管理员权限并无合法理由(无论是业务还是技术上的理由),那么无法通过普通用户帐户运行应用程序就是一种严重的错误,会对系统的安全性、稳定性和可管理性造成危害。请认真考虑让开发人员直接在代码中修复该问题。
如果开发小组答复您的请求时这样说“这是一个关键任务应用程序,因此必须以管理员身份运行”或“必须以管理员身份运行该应用程序,因为它会在 HKEY_LOCAL_MACHINE 中写入信息”,就应该这样回答“你胡说八道”,并坚持让他们修复错误。
优点:
开发小组在应用程序代码中直接修复错误后,就不必再执行任何修补程序、调整程序或解决方法了。此外,开发人员还可以从经验中学习,避免产生新的 LUA 错误。(请注意,LUA 错误的首要成因就是开发人员在编写代码时以管理员身份运行!我将在“放宽访问控制列表”部分对此做详细论述。)
缺点:
时间和金钱两方面的开销都会令人望而却步,如果资源有限,需要修复的应用程序又很多,就更是如此。可能需要重新设计应用程序的结构,而且在此过程中可能会引入新的错误。
另一个障碍是可能找不到开发人员或源代码。需要处理的可能是第三方代码,而开发它的公司已不存在。开发人员可能正在重组,或进了监狱,或更糟糕的是,正在为您的竞争对手工作。您明白了吧。
使用 Application Compatibility Toolkit
Application Compatibility Toolkit (ACT) 提供了有用的“LUA 模式”修补程序。这些修补程序会检测对文件系统和注册表中系统范围位置的写入尝试并在不提示的情况下将这些尝试重定向到每个用户的位置。(Windows Vista 中包括一个更有效的对应程序,叫作“文件和注册表虚拟化”。)在“应用程序兼容性:概述”中,可以找到 Application Compatibility Toolkit。
优点:
使用 Application Compatibility Toolkit 中提供的“LUA 模式”修补程序真正诱人的原因是,它使用方便。还不需要提升权限。
缺点:
在 Windows XP 中,“LUA 模式”修补程序往往无效。(Windows Vista 中的“文件和注册表虚拟化”经过了完全重新编写,其兼容性比 Windows XP 中的 ACT“LUA 模式”高得多。)
工具不奏效时底层操作所增添的复杂性会使故障排除变得更加复杂。
Windows 管理权限问题:查找和修复 LUA 错误_休闲
尝试解决 LUA 错误
如果问题是权限有限所致,可尝试使用许多可能会修复问题的方法。在这些解决方案中,有一些要比其他更好,因为承担的风险较低。如果遇到 LUA 错误,请按照下列步骤操作,先使用最可取的修复方法,必要时再尝试后面的修复方法。
将特定的 HKCR 项复制到 HKCU\Software\Classes
在 Windows 2000 之前,HKCR 只是对 HKLM\Software\Classes(只有管理员才可以向其中写入数据)的一个符号链接。这表示对 HKCR\.txt 执行的操作实际上发生在 HKLM\Software\Classes\.txt 中。Windows 2000 引入了以用户为单位的注册数据,因此现在 HKCR 已成为 HKLM\Software\Classes 和 HKCU\Software\Classes 的合并视图(用户可以向其中写入数据)。如果后者中存在项,它将享有优先权。因此,如果 HKCU\Software\Classes\.txt 中已存在 HKCR\.txt,现在对该项的操作将在 HKCU\Software\Classes\.txt 中进行;如果不存在,将和以前一样,操作将在 HKLM\Software\Classes\.txt 中进行。
问题在于,有许多应用程序会在运行时向 HKCR 写入数据,以增强其文件关联、COM 注册数据等。如果写入失败,即使要写入的数据已经存在,也会产生错误。每次应用程序运行时,都会写入相同的数据。如果相同的注册数据存储在 HKCU\Software\Classes 中,写入操作将会成功,而且不会更改程序的行为。
要修复此问题,首先必须确定应用程序试图写入到的 HKCR 下的项。将这些项导出到一个或多个 .reg 文件中(在“注册表编辑器”中,选择“文件”|“导出”,然后选择“选定的分支”)。然后使用文本编辑器,用 [HKEY_CURRENT_USER\Software\Classes\ 替换 [HKEY_CLASSES_ROOT\ 的所有实例并保存更改。完成后,将编辑过的 .reg 文件导入到需要运行该程序的用户的注册表中。
优点:
此方法可修复应用程序在 HKCR 中执行本应在安装期间完成的操作的问题。该方法好于放宽对 HKCR 下系统范围资源访问控制的方法。恶意软件覆盖 HKCU 下的项将不会影响操作系统组件或计算机的其他用户。
缺点:
直到最近才出现能够将 HKCR 写入识别为 LUA 错误来源并隔离所涉及项的工具。使用 LUA Buglight 执行此任务要容易得多。
使用 IniFileMapping
在 Windows 3.x的时代,我们了解并喜爱的注册表尚未出现,OS 和应用程序将配置和首选项数据存储在 .ini 文件(如 win.ini)中。Windows 过去支持 .ini 文件,现在也仍在通过配置文件 API(如 WritePrivateProfileString)为 .ini 文件提供 API 级别支持。许多应用程序(包括一些 Windows 小程序)仍然使用这些 API 来尝试写入 .ini 格式的文件,这些文件通常位于用户不应写入的文件夹中。
Windows NT 3.1 鼓励用于从使用 .ini 文件迁移到使用可扩展性和可管理性更强的注册表,并提供了用于将 .ini 文件读取和写入自动重定向到注册表项的手段。配置文件 API 的内部实现进行了扩充,以使用 HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\IniFileMapping\ 下的映射。如果在该项下未找到 .ini 文件的映射,将和以前一样,在文件系统中执行操作。
如果通过配置文件 API 访问 .ini 格式文件是 LUA 错误的成因,那么通过在 IniFileMapping 项下添加项,将访问重定向到 HKCU,便可以修复该错误。请注意,IniFileMapping 位于 HKLM 下,配置它需要具有管理权限。配置文件 API 的文档中介绍了配置细节。
优点:
此方法可避免放宽对文件系统内系统范围资源的访问控制。同样,恶意软件覆盖 HKCU 下的项将不会影响操作系统组件或计算机的其他用户。
缺点:
IniFileMapping 条目仅指定文件名,因此将会影响配置文件 API 对任何路径中具有该名称的任何文件的所有访问。这可能会对具有专用的同名 ini 文件的其他应用程序产生副作用。
更新 SafeDisc 驱动程序
许多游戏依赖 Macrovision 开发的 secdrv 设备驱动程序(也称为 SafeDisc)。随 Windows XP 一起提供的 SafeDisc 驱动程序是一种需要时启动的驱动程序;不允许用户停止和启用它,这会导致程序尝试访问该驱动程序时出现错误。有一个更新(可从 Microsoft 及从 Macrovision 站点获得)可以将该驱动程序配置为在系统启动时加载,这样用户启动它时就不需要拥有权限。此更改使非管理员用户能够正常地运行某些游戏。
(请注意,撰写本文时 Microsoft 下载页面针对该更新有一句说明,称该软件“will not alter or patch any component on your system; it will only change the startup state of the system component.(将不会改动或修补系统上的任何组件;它将只更改系统组件的启动状态。)”。事实并非如此 - 它会安装更新的驱动程序。)
优点:
此更新易于实现,而且不需要在访问控制列表 (ACL) 中进行与系统范围资源有关的更改。
缺点:
除了该方法主要用于更正与游戏(而不是生产力应用程序)有关的问题之外,实际上没有任何缺点。
放宽访问控制列表限制
LUA 错误最常见的主要成因是开发人员(往往也是测试人员)通常以管理员身份运行。开发人员可能并非有意要求最终用户以管理员身份运行,但依赖管理员访问权限的东西可能会潜入代码(例如,写入到 C: 驱动器根文件夹中的文件、写入 %ProgramFiles% 下的应用程序安装文件夹中的文件或写入 %windir% 中的文件)。开发人员和测试人员使用时应用程序还能正常工作,但当您以普通用户身份运行应用程序时,它就崩溃了。
一种方法是更改对象的访问控制列表 (ACL),为用户授予程序所需的访问权限。通常,需要调整的对象位于注册表或文件系统(如果使用 NTFS)中。采用此方法时需要进行认真考虑,并应注意一些重要事项。
首先,在已尝试了所有更可取的方法并确认这些方法都不能修复所要处理的 LUA 错误时,才应选择此方法。如果采用此方法,一定要非常小心。
只应考虑对应用程序特有资源而非 OS 范围资源进行 ACL 更改。虽然更改 %ProgramFiles%\VendorX\AppX\DataFolder 的 ACL 可能没有问题,但永远都不应更改 %SystemRoot%\System32 的 ACL,无论目的是放宽还是收紧访问权限。(有关此内容的详细信息,请参阅知识库文章“
安全配置指南支持
”。)此外,应尽一切可能避免更改程序代码的 ACL。这是为了防止恶意软件感染或替换应用程序文件。
还要避免更改由管理员或服务使用的资源(尤其是 .exe 和 .dll 文件)的 ACL。这样做会增加提升权限的风险,从而导致整个系统遭受危害。(即便如此,受攻击面仍远小于所有内容都始终以管理员身份运行的情况。)
理想情况下,资源只应由一位用户进行访问。如果资源被多个非管理员用户访问,则一位用户导致另一位用户的帐户遭受危害的风险会增加。
最后,只要应用程序能够工作,应只为可能的最少数量用户授予访问可能的最少数量资源所需的最少量附加访问权限。在任何情况下都不需要为“每个人”授予对文件系统或注册表一大部分的完全控制权限。
最理想的做法是只为计算机的主要用户授予附加访问权限,但如果系统数量庞大,这样做在管理上可能会有困难(例如,在一个系统上授予 MARY 权限,在另一个系统上授予 STEVE 权限,依此类推)。如果可以定义一组需要使用该程序的用户,应将这些用户添加到一个组,然后为该组授予访问权限。
也可以授予对内置 INTERACTIVE 仿真组的访问权限。这样做将只为当时以交互方式登录的用户授予附加访问权限,而不会授予附加的对资源的远程访问权限。请注意,在终端服务器或“快速用户切换”应用场景中,计算机上可能同时有多位用户的令牌中有 INTERACTIVE。
优点:
此方法会为您的时间投资带来巨大回报。我和我的同事见过的大部分 LUA 错误都与文件和注册表权限有关。调整访问控制列表可能比任何其他方法修复的 LUA 错误都要多。
缺点:
此方法的可取性较低,因为出于某种原因对 ACL 进行了这样的设置。更改 ACL 使得受限用户能够更改共享资源(出于善意或恶意),并会使一位用户(或该用户无意间运行的恶意软件)可以更容易地影响其他用户。如果管理员受到影响,就会危害整个系统。
此外,精确地确定应开放的资源及开放程度并不容易。而且也难以肯定地了解开放对资源的访问是否会无意间公开提升权限的途径,从而使系统被他人接管。
只以提升的权限运行那个有问题的应用程序
一些应用程序解决 LUA 错误的方法是,在启动时显式地检查您是否为管理员组成员,如果您不是,将显示一条错误消息,坚称您必须是管理员,才能使用该程序。这可能是由于开发人员的懒惰、不称职或傲慢(或三者兼而有之),但无论您使用任何其他解决方法,这些应用程序都不会让步。如果已经确认所有其他方法都已失败,就只能考虑以提升的组或权限运行那个有问题的应用程序。
请不要以管理员身份运行应用程序,而是尝试以提高的权限(但仍低于完全管理权限)运行它。可以 Power Users 成员的身份或特定权限(如 SeLoadDriverPrivilege)运行应用程序。但要知道,只需多费一点工夫,就可利用这些其他组和权限中的许多组和权限接管整个系统。
那么,该如何完成此项任务呢?如果您信任拥有管理员密码的用户(或者您信任制定安全决策的用户),则有四种选择:
可以使用 RunAs。(有关这方面的更多详细信息,请参阅我发表的文章“ "RunAs" basic (and intermediate) topics(英文)”和“RunAs with Explorer(英文)”。)
可以使用 MakeMeAdmin。这是一个批处理文件,可以轻松地自定义该文件来运行命令外壳以外的内容。也可以对其进行调整,使提升的上下文低于完全管理上下文。(有关此内容的详细信息,请参阅我的
博客文章。)
SysInternals 提供了 PsExec 和 Process Explorer。这些应用程序提供了各种类似 RunAs 的选项。
最后,可以使用 RunAsAdmin。这是 Valery Pryamikov 开发的一个值得关注而且有用的开源实用程序。RunAsAdmin 采用的方法有点类似于 Windows Vista 的“用户帐户控制”功能 (UAC),就地提升当前用户的权限而不要求使用密码。
另一方面,如果您不信任拥有管理员密码的用户,还有几个第三方选择值得考虑。
DesktopStandard 开发的 PolicyMaker Application Security 使用“组策略”扩展来配置修改进程令牌的规则。它减轻了下面提到的部分缺点的严重程度。可以对其进行配置,使由目标应用程序启动的子进程不继承其修改过的令牌。它还可以执行细微的令牌修改,以提高(或降低)权限或添加(或删除)特权。
Winternals(SysInternals 的商业机构)提供了 Protection Manager,该工具使用轻型客户端-服务器应用程序和白名单技术来封锁所有不受信任的应用程序。可通过 Protection Manager 将应用程序的进程令牌和权限提升到管理员进程令牌和权限的级别或降低到用户进程令牌和权限的级别(当最终用户分别是非管理员或管理员时)。Protection Manager 不允许已提升权限的应用程序的子进程以提升的权限运行,除非也将该子进程显式地配置为已提升权限的应用程序。已降低权限进程的所有子进程的权限将自动降低。可按管理员通过数字签名、散列、NTFS 文件所有权或路径进行的指定对应用程序执行允许、封锁、提升权限或降低权限操作。
PolicyMaker Application Security 和 Protection Manager 都通过内核模式代码确定是否、何时以及如何修改进程令牌。由于不使用密码,因此不存在泄漏风险,而且非管理员无法干涉修改决定。
还可使用其他工具,这些工具执行类似 RunAs 的操作时会将管理员帐户凭据加密(有时只是进行模糊处理)。尽管此方法提高了标准,可阻止一些用户获取管理员凭据,但那些密码仍然需要在用户的安全上下文中解密,因此可能会暴露给拥有适当工具的攻击者。
有一个我听过的常见问题是,RunAs.exe /savecred 选项是否可用作快捷方式,以使用户能够使用保存的密码(不需要再次输入密码)以管理员身份运行某个应用程序。但这会导致无法预料的问题,而且也有许多问题是应该知晓的。凭据并不是绑定到任何单个快捷方式;凭据保存后,就可以使用它们来启动任何应用程序。尽管密码使用用户特有密钥进行了安全的加密,但仍然要在用户的安全上下文中进行解密而被短时间公开。而且,在 Windows XP Home Edition 上无法使用 /savecred 选项。
优点:
使用此方法可以避免始终以管理员身份运行所有内容。遗憾的是,这差不多是此方法的唯一优点。
缺点:
以提高的权限运行应用程序比我已介绍过的任何其他方法的风险都高得多。如果以管理员身份运行应用程序,将很难保护系统不受恶意用户或恶意应用程序的攻击。以下是一个简单的示例。如果以管理员身份运行“记事本”,然后选择“文件”|“打开”,将会显示一个类似资源管理器的小窗口。您仍然位于“记事本”中,这意味着您拥有对整个文件系统的完全管理员级别访问权限,甚至可以从该处以管理员身份启动程序。此项简单技术会被恶意用户或将击键或窗口消息送入已提高权限程序的恶意软件利用。
结束语
“最低权限用户帐户”可以作为安全策略中的一个便利选择,但它可能会引发一些值得关注的难题。这些错误解决方法的效力和安全性有很大差异。虽然确定错误的确切成因,然后使用最佳解决方案进行修复有困难,但这样做很重要。如果使用其中一个可取性较低的方法,则应了解如何尽最大可能保护系统。
本文是根据我的博客上发表的文章改编的。可通过以上链接了解有关以最低权限运行的概念,以及如何利用优点和如何处理难题的详细信息。
LUA Buglight
LUA Buglight 是一个专门用于帮助开发人员和 IT 专业人士确定 Windows XP 上运行的应用程序中 LUA 错误具体成因的工具。确定具体成因后,就可以通过修复应用程序的源代码或进行配置更改来更轻松地解决错误,从而使应用程序能够正常地为非管理员用户工作。
通过使用 LUA Buglight,目标应用程序以非管理员身份运行,使用 Microsoft Research 的 Detours 2.0 截取(“修补”)了大约 200 个 Win32 API。目标应用程序调用修补后的 API 时,它实际调用的是基于 LUA Buglight Detours 的 DLL。该 DLL 随后执行各种操作,包括调用实际的底层 API,及在将控制权返回给应用程序之前检查或修改其结果。
LUA Buglight 会创建代表当前用户的访问令牌(称作 this-user-as-admin 令牌),但创建时会将其作为具有完全管理员权限的 Administrators 组的成员。在进程内运行的 API 修补代码可使用该令牌。LUA Buglight 创建该令牌时使用的方法与 MakeMeAdmin 脚本的方法非常相似。用户必须提供本地管理帐户的凭据才能创建此令牌,这里没有什么未经授权便可提升权限的神奇手段。
LUA Buglight 方法的核心是,应用程序调用修补过的 API 时,修补代码会先调用底层 API。如果该 API 因访问被拒绝(在某些情况下是由于不拥有权限)而失败,修补代码会取得 this-user-as-admin 令牌,模拟该令牌,然后再次调用底层 API。第二次调用的结果便是返回到应用程序的内容。如果以管理员身份的调用成功,有关该调用的信息将作为潜在的 LUA 错误写入日志文件。最终结果是应用程序不会由于 LUA 错误而失败,因为在需要时它可以使用管理员权限,但将会列出每一个需要使用管理员权限的情况。有关 LUA Buglight 即将推出的测试版的最新信息,请参阅 blogs.msdn.com/aaron_margosis。