Windows如何决定是否显示UAC提示?

22
在我的VB6应用程序中,我打开其他EXE文件。 我的应用程序在没有任何UAC提示的情况下运行,但是我有一个EXE文件用于检查软件更新。 这会提示UAC提示。 所以Windows如何决定何时显示UAC提示? 我看到了这个链接。那么它是否取决于我在应用程序中编写的代码? 有趣的是,我的应用程序(即主EXE文件)不会提示UAC,而检查和下载更新的小型EXE会提示UAC。 我所有的EXE文件都已数字签名。 我已经浏览了以下链接: http://msdn.microsoft.com/en-us/library/windows/desktop/aa511445.aspx http://technet.microsoft.com/en-us/library/cc505883.aspx 和一些其他链接。
但我仍然不清楚。
4个回答

30

您几乎肯定正在触发 Windows Installer Detection Technology 兼容性启发式。Windows 将尝试检测应用程序是否是安装程序,并且可能需要提升权限。

安装程序检测仅适用于以下内容:
  1. 32位可执行文件
  2. 没有“requestedExecutionLevel”的应用程序
  3. 作为启用了LUA的标准用户运行的交互式进程
在创建32位进程之前,将检查以下属性以确定它是否为安装程序:
  • 文件名包括关键字,如“install”,“setup”,“update”等。
  • 版本资源字段中的关键字:供应商、公司名称、产品名称、文件说明、原始文件名、内部名称和导出名称。
  • 嵌入在可执行文件中的并排清单中的关键字。
  • 链接在可执行文件中的特定StringTable条目中的关键字。
  • 链接在可执行文件中的RC数据中的关键属性。
  • 可执行文件中的目标字节序列。
因此,正如您所说:

但我有一个检查软件更新的exe文件

我的猜测是,这个CheckForUpdates.exe正在触发兼容性启发式算法。

正确的做法是为您的“检查”可执行文件添加一个程序集清单,通知Windows它不应该提升实用程序。这可以通过在清单中使用asInvokerrequestedExecutionLevel来完成:

AssemblyManifest.xml:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"> 
   <assemblyIdentity 
      version="1.0.0.0"
      processorArchitecture="X86"
      name="ITReasearchAssociates.Contoso.Updater"
      type="win32"
   /> 

   <description>Update checker</description> 

   <!-- Run as standard user. Disable file and registry virtualization -->
   <trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
      <security>
         <requestedPrivileges>
            <requestedExecutionLevel level="asInvoker" uiAccess="false"/>
         </requestedPrivileges>
      </security>
   </trustInfo>
</assembly>

这样,您的“检查更新”应用程序将永远不会提升,并且永远不会错误地获得管理特权。
如果您希望您的更新程序实际应用需要管理特权的更新,则需要以管理员身份启动您的更新程序。
示例代码
//Check if there are updates available
if (!CheckForUpdatesAvailable())
   return; //no updates. We're done

//If the user is an administrator, then get the update
if (IsUserAnAdmin())
{
    //Maybe throw in a "Hey, user, wanna get the update now?" dialog
    DownloadAndApplyUpdates();
    return;
}

//The user is not an admin. 
//Relaunch ourselves as administrator so we can download the update
//Maybe throw in a "Hey, user, wanna get the update now?" dialog. A button with a UAC shield on it
ExecuteAsAdmin(Application.ExecutablePath, "/downloadUpdate");

用辅助函数:
private Boolean IsUserAnAdmin()
{
    //Public domain: no attribution required
    //A user can be a member of the Administrator group, and yet not be an administrator.
    //Conversely, the user can be an administrator while not being a member of the administrators group.
    var identity = WindowsIdentity.GetCurrent();
    return (null != identity && new WindowsPrincipal(identity).IsInRole(WindowsBuiltInRole.Administrator));
}

private void ExecuteAsAdmin(string Filename, string Arguments)
{
    //Public domain: no attribution required
    ProcessStartInfo startInfo = new ProcessStartInfo(Filename, Arguments);
    startInfo.Verb = "runas";
    System.Diagnostics.Process.Start(startInfo);
}

在启动时,您只需要查找/downloadUpdate命令行参数,就知道您的工作是实际工作:

public Form1()
{
    InitializeComponent();

    //Ideally this would be in program.cs, before the call to Application.Run()
    //But that would require me to refactor code out of the Form file, which is overkill for a demo
    if (FindCmdLineSwitch("downloadUpdate", true))
    {
        DownloadAndApplyUpdates();
        Environment.Exit(0);
    }
}

请注意:任何代码均已释放到公共领域,无需归属。

1
我要补充的是,上面列出的文件名规则几乎肯定是不完整的。有趣的是,我有一个应用程序,如果命名为APP123.exe,则需要UAC,但如果将其重命名为APP.exe,则不需要UAC。 - StayOnTarget
1
感谢@Ian Boyd!我看到了这个:https://dev59.com/GHM_5IYBdhLWcg3wUxjF,安装了Windows SDK,并使用mt.exe按建议将清单文件添加到我的.exe! 完美运行! - ewerybody
可执行文件中的目标字节序列。你能详细说明一下吗? - Sajuuk
@Sajuuk 我不知道。只有微软,或者那些已经审查了Windows源代码并签署了保密协议的人才会知道。 - Ian Boyd

1

有人可以在exe的配置中指定该文件需要以更高的权限执行。

如何请求管理员权限

我不知道这个更新是用来做什么的,但我建议它需要更新一个组件,比如一个服务,或者一些位于ProgramFiles目录中的文件。因此它需要管理员权限。


我有疑问,Windows 是如何决定是否提示 UAC 的。您的方法以管理员身份运行程序,并要求用户输入管理员密码。 - IT researcher
这就是它的工作方式,尽管Codeproject文章不是很完整。你可以在清单中选择几个不同的选项,这些选项之间有微妙或不存在的差异(例如请求最高特权或管理员特权,或其他),但基本上就是这样。Windows安全性相当愚蠢,但另一方面,我希望我能引用一个更不愚蠢的系统(Linux甚至更加愚蠢,因为它要求你输入root密码...)。 - Damon

1
你的程序可能缺少应用程序清单,将其标记为非传统应用程序。因此,Windows将应用脚本安装检测启发式来决定您的程序是否是安装程序。这几乎是唯一会引发“意外”UAC提示的方式。
这些启发式包括在EXE文件名和EXE的几个扩展属性中进行关键字搜索,甚至可能在文件内部查找众所周知的二进制签名(即字节字符串)。
顺便说一下,你的加密签名完全与此无关。如果它不是由受信任的CA颁发的,则没有任何帮助。
就此而言,任何仅因为Windows在UAC提示上报告公司名称就信任代码的人都是愚蠢的。恶意软件作者经常窃取这些信息,而且这些信息很容易获得,当垃圾程序导致问题时,用户几乎从不报告。省下你的钱,代码签名证书是一个失败的概念。

好的。所以在我的情况下,不以管理员身份运行并拥有正确的清单文件可以避免UAC提示吗? - IT researcher
如何创建清单文件以使应用程序在无需UAC提示的情况下启动? - IT researcher
1
@ITresearcher:如果这是你真正想问的问题(如何防止提示),你应该提出更多信息而不仅仅是这个问题。但答案很可能是:“UAC提示框存在有充分的理由,因为你正在更改已安装的软件,这应该是用户有意识的决定。” - MSalters
如果你想要一个衍生程序以父级权限运行,那么它需要在清单的<requestedExecutionlevel>元素中指定"asInvoker"。要为VB6应用程序创建和添加应用程序清单,您可以使用第三方工具或手动创建和嵌入它们。 - Bob77

0

当需要提升权限时,UAC提示框会被使用。您自己的VB6应用程序不需要它,因此默认行为是可以的。更新程序需要该权限,因此其作者将可执行文件标记为需要该权限。Windows会检测到这一点并弹出UAC提示框。

现在,根据确切的Windows版本和安全更新,该权限可能会保持一段时间,甚至对其他(子)进程也是如此。这可能会防止重复的UAC提示框。


更新程序是由我创建的。因此,其中一些代码会触发UAC提示?在我的代码中,我没有以管理员身份运行更新程序exe(始终作为管理员运行会导致UAC提示)。那么是某些代码触发了UAC吗? - IT researcher
1
我相信Windows确实有一些额外的启发式:例如,它以前是否需要UAC?它的名称是“setup.exe”吗? - MSalters
文件名称不是setup.exe。但UAC是否也依赖于文件名称? - IT researcher

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接