【问题标题】:Force an existing application to always run with UAC virtualization on强制现有应用程序始终使用 UAC 虚拟化运行
【发布时间】:2012-01-13 15:30:54
【问题描述】:

我见过几个与此相反的问题; “如何禁用虚拟化?”那不是我的问题。我想强制应用程序在启用虚拟化的情况下运行。

我有一个在 Windows XP 下运行良好的应用程序,但是,因为它将其配置写入其工作目录(“C:\Program Files (x86)”的子文件夹),它不能在 Windows 7 下完全运行. 如果我使用任务管理器打开 UAC 虚拟化,它会很好地保存它的配置,但当然它不能加载该配置。

我不想将其设置为以管理员身份运行,因为它不需要这些权限。我想将其设置为在启用 UAC 虚拟化的情况下运行。

found a suggestionHKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\AppCompatFlags 的注册表中添加了一些魔法。为了完整起见,我还把它放在了Wow6432Node,但都没有任何效果。

【问题讨论】:

  • 为什么不能只更改应用以将配置文件保留在 AppData 中?
  • @KateGregory 的建议,或者修改文件夹上的 ACL,让 everyone 拥有完全控制权。问题是,并非所有类型的写入都将始终被虚拟化。这是一个权宜之计功能,可以阻止有缺陷的程序崩溃。这真的不是你应该依赖的东西。事实上,可以通过组策略禁用虚拟化——不管你是否愿意。
  • @KateGregory:我没有消息来源。如果我有来源,我会使用它,而不是依赖权宜之计功能的糟糕解决方法。
  • @IanBoyd 修改 ACL 以破坏我通过打开 UAC 运行获得的安全性?我不这么认为。组策略不禁止在我的机器上进行虚拟化(“用户帐户控制:虚拟化文件和注册表...”已启用),因此这不适用于我,尽管它可能适用于其他人。 (我最终放弃了,只修改了配置文件上的ACL。这确实解决了原来的问题,并且没有打开任何安全漏洞,但它没有回答原来的问题。)

标签: uac


【解决方案1】:

文件系统在某些情况下是虚拟化的,那么当您的应用程序不符合条件时,您的问题是如何仍然打开它?不太可能,MSDN

虚拟化在以下情况下不可用:

  • 虚拟化不适用于提升并使用完整管理访问令牌运行的应用程序。

  • 虚拟化仅支持 32 位应用程序。非提升的 64 位应用程序在它们 尝试获取 Windows 对象的句柄(唯一标识符)。 本机 Windows 64 位应用程序需要兼容 UAC 并将数据写入正确的位置。

  • 如果应用程序包含具有请求的执行级别的应用程序清单,则会禁用应用程序的虚拟化 属性。

【讨论】:

  • 1 和 2 不适用;这是一个 32 位应用程序,我没有运行提升,也不想运行。
  • 所以,我想我的问题转移到“应用程序清单显然是谎言。我该如何解决它?”
  • 所以,我尝试使用 mt (mt -inputresource:tool.exe -out:tool.manifest) 提取清单,并被告知:“mt.exe : general error c101008c: Failed to read来自文件资源的清单。在图像文件中找不到指定的资源类型。对包含清单的可执行文件进行相同的尝试。所以,答案似乎是“清单不存在”。
  • 如果你有一个清单,不管它说什么,你都不会得到虚拟化。要尝试获取它,请从没有清单开始。
  • @Kate:mt 告诉我“未能读取清单......在图像文件中找不到指定的资源类型。”这让我怀疑我没有清单。如果您似乎怀疑 mt 在撒谎,我该如何删除清单?
【解决方案2】:

现在这可能来得太晚了,但我是您发现激活 UAC 虚拟化的建议的作者,我的帖子中有一个错误。要修改的注册表项如下:

HKLM\Software\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\Layers\ 
HKCU\Software\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\Layers\

(注意附加的“图层”

所以一个完整的例子是:

[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\Layers]
"C:\\Program Files (x86)\\Some Company\\someprogram.exe"="RUNASINVOKER"

注意,多个参数必须用空格字符分隔。

[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\Layers]
"C:\\Program Files (x86)\\Some Company\\someprogram.exe"="WINXPSP3 RUNASINVOKER"

--

非常抱歉,因为我的错误,您损失了相当多的时间。

顺便说一句,让我表达我对 Ian Boyd 帖子的不同意见。有些地方不应该向每个人授予写入权限,例如这个,因为它违反了“系统范围的写入应该只授权给特权主体”的基本安全规则。 Program Files 是一个系统范围的地方,而不是每个用户的地方。

当然,所有规则都有例外,但在目前的情况下,可以想象恶意制作的配置文件使程序在用户运行时执行任意命令。在较轻的方面,可以想象另一个用户的“错误删除”,这会使应用程序失败。回到更重的方面,Program Files 中的应用程序可执行文件通常迟早由管理员运行。即使您不想这样做,卸载程序也经常会运行 Program Files 中的卸载可执行文件。也许卸载过程将使用该配置文件,如果它被恶意制作,可能会产生后果。

当然,您可能会说,这听起来有点偏执,同意。我确实在 Win XP 的时候修改了 Program Files 中的一些 NTFS ACL,之后就可以休眠了,但是当工具可用时为什么要冒最小的风险呢?

【讨论】:

    【解决方案3】:

    我发现了一个 UAC 虚拟化不起作用的不太被引用的情况:Program Files 中的文件被设为只读

    也就是说,假设文件C:\Program Files\<whatever>\config.ini 被标记为只读。当应用程序尝试更改它时,UAC 虚拟化将返回 拒绝访问错误,而不是将其重新解析为 %LOCALAPPDATA%\VirtualStore\<whatever>\config.ini

    虽然我没有发现这个记录,但这种行为可能是设计使然,因为它有一定的意义。

    解决方案很简单:确保所有应该由应用程序修改的文件都不是只读的(或者只是取消标记所有文件,因为用户无论如何都无法更改它们)。

    【讨论】:

      【解决方案4】:

      您有一个应用程序,并且您希望用户能够在默认情况下只有管理员可以修改的位置修改注册表项或文件。

      如果您运行的是 Windows 2000、Windows XP、Windows Vista、Windows 7 或 Windows 8,则解决方案相同:

      • 向这些位置授予适当的权限

      例如,如果您的程序需要修改以下文件:

      C:\Program Files\Blizzard\World of Warcraft
      

      然后正确操作更改World of Warcraft文件夹的权限。事实上,这是 Microsoft 应用于魔兽世界的垫片。 (在下一次运行时,它授予每个人对文件夹的完全控制权——无论什么用户登录,WoW 还能如何自我更新。)

      如果您希望用户能够修改某个位置的文件:您必须授予他们权限。如果您是标准用户,尝试在 Windows XP 上运行 WoW,您将遇到同样的问题 - 并且需要应用相同的解决方案。


      您的应用程序正在将其配置写入:

      C:\Program Files (x86)\Hyperion Pro\preferences.ini
      

      那么你,事实上确实想要授予用户 完全控制对该文件:

      所以你的:

      • 应用程序未设置为以管理员身份运行
      • 用户不能修改可执行文件
      • 用户可以修改Configuration.ini

      授予权限并不是一件坏事;这就是您管理服务器的方式。


      有两种解决方案:

      • 安装到 C:\ProgramData\Contoso\Preferences.ini 并在安装时对其进行 ACL
      • 安装到C:\Program Files\Contoso\Preferences.ini 并在安装时对其进行 ACL

      如果您查看 Microsoft AppCompat 人员的指导:

      Where Should I Write Program Data Instead of Program Files?

      一个常见的应用程序代码更新是这样的:“我的应用程序用于将文件写入程序文件。感觉就像放置它的好地方一样。它上面已经有我的应用程序的名称,而且因为我的用户是管理员,所以它运行良好。但是现在我发现这可能不像我曾经想象的那样是一个放置东西的好地方,因为使用 UAC,即使是管理员大多数时候都以标准的类似用户的权限运行。那么,我应该把我的文件放在哪里呢?”

      FOLDERID_ProgramData

      用户永远不想在资源管理器中浏览此处,此处更改的设置会影响计算机上的每个用户。默认位置是 %systemdrive%ProgramData,它是 Windows Vista 安装上的隐藏文件夹。 您需要在安装时创建目录并设置所需的 ACL。

      所以你有两个解决方案:

      • 在安装时创建您的文件,并对其进行 ACL 以便所有用户都可以在运行时对其进行修改
      • 在安装时创建您的文件,并对其进行 ACL 以便所有用户都可以在运行时对其进行修改

      唯一的区别是语义。 Program Files 文件夹用于存放程序files。您不想在此处存储数据。

      • 不是,因为 Diego Queiroz 对安全性有任何见解。
      • 这是因为它只是程序所在的地方。

      有时机器会一遍又一遍地使用相同的程序文件进行映像。您不希望映像中包含每台机器的数据。该数据属于 ProgramData

      这不是安全问题。

      有些人必须知道安全边界在哪里。

      【讨论】:

      • 我完全不同意。应用程序不应更改系统区域。由于 Program Files 是系统区域,因此不应更改。问题是遗留应用程序仍然这样做。这就是 UAC 虚拟化存在的原因,您不应该禁用它。禁用与 UAC 相关的任何内容是一种懒惰的解决方案。
      • @DiegoQueiroz 我同意;应用程序应将用户可修改的数据放入CSIDL_ProgramData。但现实情况是,C:\ProgramData 默认情况下对标准用户也是禁止访问的。还有correct guidance is to ACL that location at install time。如果你正确地 ACL 你的数据文件,并在你的进程上禁用虚拟化(运行 asInvoker)那么你做的事情是正确的。
      • 而且,Diego,您还误解了 UAC 是什么。文件虚拟化存在的原因是因为安装程序从不打扰他们需要标准用户修改的 ACL 文件。这些文件是在ProgramFilesProgramData 还是`C:` 中并不重要。您仍然需要正确地 ACL。
      • 我还是不同意。应用程序可以修改文件夹 ACL,但它们不应该,特别是在可以避免的情况下。当然,这一切都与安全有关,但这也与系统设计有关:事情应该在他们应该在的地方。而且我不认为我误解了 UAC 是什么。更改 C:\ProgramData 中任何子文件夹的默认 ACL(即使您的应用程序创建了它)相当于允许任何用户在 Linux 中写入 /etc/your_app,这在任何方面都是完全疯狂的想法。
      • 如果你正在设计一个独立于系统的应用程序,那太好了,把所有东西都放在C:\your_app(类似于Linux 中的/opt/your_app)上,并且对它感到满意。如果您的应用不需要在用户之间共享(正如 Google Chrome 已经使用其标准安装程序所做的那样),您甚至可以坚持使用 %USERPROFILE%\...\your_app(类似于 Linux 上的 ~/your_app)。但是不要试图说服我改变操作系统定义的默认 ACL 是“正确”的解决方案。
      【解决方案5】:

      其他答案也有不少优点。
      实际上,我对所有这些都投了赞成票。
      所以让我们将它们组合在一起,并添加更多方面...

      OP 提到了一些“过去的遗留应用程序”。
      所以我们可以假设它是 x86(32 位)并且 包含任何清单(特别是不指定任何“requestedExecutionLevel”)。

      --

      Roman R. 在他关于x64manifest 文件的回答中有很好的观点:
      https://stackoverflow.com/a/8853363/1468842
      但所有这些条件似乎都不适用于这种情况。

      NovHak 在他的回答中概述了一些AppCompatFlagsRUNASIVOKER
      https://stackoverflow.com/a/25903006/1468842

      Diego Queiroz 在他的回答中添加了关于 read-only 标志的有趣方面:
      https://stackoverflow.com/a/42934048/1468842

      Ian Boyd 表示,您可能甚至不应该进行那种“虚拟化”,而是根据ACL 对那些感兴趣的文件(例如“config.ini”)进行设置:
      https://stackoverflow.com/a/12940213/1468842

      这是附加/新方面:
      可以将policy 设置为禁用所有虚拟化 - 系统范围:

      [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System]
      "EnableVirtualization"=dword:00000000
      

      实际上,我正在对我拥有的每个系统执行此政策。
      因为否则会导致在multi-user 环境中出现令人困惑的行为。
      UserA 应用了一些更改并且一切正常。
      但随后 UnserB 确实得到 UserA 所做的更改。

      如果一些旧的蹩脚软件失败,那么它应该“失败”!
      而不是声称一切都“很好”。
      恕我直言,这个“虚拟化”是微软有史以来最糟糕的设计决定。

      所以也许系统启用了此策略,这就是为什么虚拟化不适合您?

      --

      所以最终的清单可能是:

      • 应用程序是 x86 还是 x64
      • exe 是否有清单(包括requestedExecutionLevel)?
      • 您是否检查了 只读 属性(例如那些 INI 文件)?
      • 是否有政策强制将EnableVirtualization 改为0
      • 您是否尝试过带有RUNASIVOKERAppCompatFlags
      • 或者干脆选择ACL 代替虚拟化

      --

      最后,我们正在讨论如何在旧的遗留应用程序上运行。
      通过使用我们能想到的任何解决方法和技巧。
      这应该在superuserserverfault 上更好地讨论。

      stackoverflow(针对programmers)我们都知道:现在是时候让我们自己的所有程序与 UAC 概念兼容,以及如何以“正确”的方式——“微软”的方式来实现事物了 :)

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-04-02
        • 1970-01-01
        • 1970-01-01
        • 2013-05-12
        • 2011-10-02
        • 1970-01-01
        • 2016-02-09
        • 1970-01-01
        相关资源
        最近更新 更多