假设您的 Windows 用户帐户位于 Admin 组中,启用了 UAC,并且您正在以普通用户权限运行某些程序 A。 A从不要求提升,也从未得到提升。现在假设 A 想要启动程序 B,该程序的清单中具有 HighestAvailable。
我的问题是:有没有办法实现第三种选择,即我们只需启动 B 而无需提升?
原则上这似乎是可能的,因为“highestAvailable”意味着 Bprefers以海拔运行,但完全能够在普通用户模式下运行。但我想不出任何方法来实现它。我已经尝试了使用令牌和 CreateProcessAsUser() 的各种方法,但这一切似乎都归结为:“highestAvailable”似乎不可改变地指的是用户帐户固有的潜在权限,而不是任何显式表达的实际权限。构建的令牌。
我希望实际上有某种方法可以使用 CreateProcessAsUser() 来执行此操作,并且我只是缺少正确构建令牌的技巧。
更新-已解决:下面的 __COMPAT_LAYER=RunAsInvoker 解决方案效果很好。不过,有一点需要注意。这会强制子进程无条件地“作为调用者”运行:即使被调用的 exe 在其清单中指定了“requireAdministrator”,它也适用。我认为当 exe 指定“requireAdministrator”时,最初的“需要提升”错误通常更可取。我希望标有“highestAvailable”的程序的 RunAsInvoker 行为的全部原因是,此类程序明确表示“我可以在任一模式下正常运行” - 因此,当不方便使用管理模式时,让我们继续以普通用户模式运行。但“requireAdministrator”是另一回事:此类程序会说“如果没有提升的权限,我将无法正常运行”。对于此类程序来说,预先失败似乎比强制它们以未提升的速度运行更好,这可能会使它们遇到未正确编程来处理的特权/访问错误。因此,我认为这里的完整通用解决方案需要检查应用程序清单,并且仅在清单显示“highestAvailable”时才应用 RunAsInvoker 强制。更完整的解决方案是使用其他地方讨论的技术之一,为调用者提供在出现“requireAdministrator”程序时调用 UAC 的选项,并为用户提供启动它的机会。我可以想象一个 CreateProcessEx() 覆盖了几个新标志,用于“将进程权限视为最高可用权限”和“如果需要提升,则调用 UAC”。 (下面描述的另一种方法,挂钩 NTDLL!RtlQueryElevationFlags() 来告诉 CreateProcess() UAC 不可用,对于 requireAdministrator 程序具有完全相同的警告。)
(这可能表明 Windows shell 甚至没有提供执行此操作的方法...直接从 shell 启动 B 将为您提供 UAC 框,让您可以使用管理员权限启动或根本不启动。如果有不管怎样,UAC 框可能会提供第三个按钮,无需特权即可启动。但话又说回来,这可能只是用户体验决定,因为第三个选项对平民来说太令人困惑了。)
(请注意,StackOverflow 和 Microsoft 开发支持网站上有很多帖子询问看似非常相似的场景,但遗憾的是,该场景并不适用于此处。该场景是指您有一个正在运行提升的父程序,并且它想要启动一个非提升的子进程。典型的例子是一个安装程序,按照安装程序倾向于做的方式运行提升,它想要在正常用户级别启动刚刚安装的程序,就在它退出之前。有很多关于如何做到这一点,我已经基于其中一些技术进行了尝试,但这确实是一个不同的场景,并且解决方案在我的情况下不起作用。最大的区别是他们尝试启动的子程序在这种情况下isn't标记为 HighestAvailable - 该子程序只是一个正常程序,在正常情况下无需任何 UAC 参与即可启动。还有另一个区别,即在这些场景中,父级已经在提升的级别运行,而在我的场景中,父级正在以普通用户级别运行;这会稍微改变一些事情,因为在其他场景中,父进程可以访问令牌上的一些特权操作,但我无法使用这些特权操作,因为 A 本身并未提升。但据我所知,那些特权令牌操作无论如何都无济于事;事实上,孩子拥有最高的可用标志,这是我的场景的关键元素。)
Set the __COMPAT_LAYER
环境变量为RunAsInvoker https://devblogs.microsoft.com/oldnewthing/20161117-00/?p=94735在你的过程中。我不认为这在任何地方都有正式记录,但它一直可以追溯到 Vista。
您还可以通过将其设置为永久的AppCompatFlags\Layers
注册表中的密钥。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)