【问题标题】:How does Windows decide whether to display the UAC prompt?Windows 如何决定是否显示 UAC 提示?
【发布时间】:2013-12-04 11:46:48
【问题描述】:

在我的 VB6 应用程序中,我打开其他 EXE 文件。我的应用程序在没有任何 UAC 提示的情况下运行,但我有一个检查软件更新的 EXE。这会提示 UAC 提示。那么Windows是如何决定是否显示UAC提示的呢?我看到了这个link。那么它是否取决于我在应用程序中编写的代码?有趣的是,我的应用程序(即主 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 和其他一些。

但我仍然不清楚。

【问题讨论】:

    标签: windows security windows-7 vb6 uac


    【解决方案1】:

    您几乎肯定会遇到 Windows Installer Detection Technology? 兼容性启发式。 Windows 将尝试检测应用程序何时是安装程序,并且可能需要提升。

    安装程序检测仅适用于:

    1. 32 位可执行文件
    2. 没有requestedExecutionLevel 的应用程序
    3. 以标准用户身份运行并启用 LUA 的交互式进程

    在创建32位进程之前,会检查以下属性以确定它是否是安装程序:

    • 文件名包含“安装”、“设置”、“更新”等关键字。
    • 以下版本控制资源字段中的关键字:供应商、公司名称、产品名称、文件描述、原始文件名、内部名称和导出名称。
    • 嵌入在可执行文件中的并行清单中的关键字。
    • 可执行文件中链接的特定 StringTable 条目中的关键字。
    • 可执行文件中链接的 RC 数据中的关键属性。
    • 可执行文件中的目标字节序列。

    所以,正如你所说:

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

    我的猜测是这个CheckForUpdates.exe 正在触发兼容性试探法。

    正确要做的事情是将程序集清单添加到您的“检查”可执行文件中,通知 Windows 它应该提升效用。这是通过清单中的asInvoker 中的requestedExecutionLevel 完成的:

    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);
        }
    }
    

    注意:任何代码都会发布到公共领域。无需署名。

    【讨论】:

    • 我要补充一点,上面列出的文件名规则几乎肯定是不完整的。有趣的是,我拥有的一个应用程序在命名为 APP123.exe 时需要 UAC,如果重命名为 APP.exe,则不需要 UAC。
    • 感谢@Ian Boyd!我看到了这个:stackoverflow.com/questions/1423492,安装了 Windows SDK 并使用mt.exe 添加了一个清单文件,就像我的.exe 建议的那样!像魅力一样工作!
    • “可执行文件中的目标字节序列。”你能详细说明一下吗?
    • @Sajuuk 我不能。只有 Microsoft 或查看过 Windows 源代码并签署 NDA 的人会知道。
    【解决方案2】:

    您的程序可能缺少将它们标记为非旧版的应用程序清单。因此,Windows 将应用脚本安装程序检测启发式方法来确定您的程序是否是安装程序。这几乎是引发“意外”UAC 提示的唯一方式。

    这些启发式方法包括 EXE 文件名中的关键字搜索和 EXE 的一些扩展属性,甚至可以在文件中查找众所周知的二进制签名(即字节字符串)。

    顺便说一句,您的加密签名根本不参与其中。如果它不是由受信任的 CA 颁发的,它也无济于事。

    就此而言,任何仅仅因为 Windows 在 UAC 提示符上报告公司名称而信任代码的人都是傻瓜。恶意软件作者一直在窃取这些内容,因此它们很容易获得,并且当垃圾程序引起问题时,用户几乎从未报告过。省钱,代码签名证书是一个失败的概念。

    【讨论】:

    • 好的。因此,在我的情况下,如果不以管理员身份运行并拥有适当的清单文件可以避免 UAC 提示?
    • 另外如何创建一个清单文件,使应用程序在没有 UAC 提示的情况下启动?
    • @ITresearcher:如果这是你真正的问题(如何防止提示),你应该问这个问题 - 并提供比这个问题更多的信息。但答案很可能是“UAC 提示是有充分理由的,您正在更改已安装的软件,这应该是用户的故意决定”。
    • 如果您希望衍生程序以父级权限运行,则需要在清单的 元素中指定“asInvoker”。要创建应用程序清单并将其添加到 VB6 应用程序,您可以使用 3rd 方工具或手动创建和嵌入它们。
    【解决方案3】:

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

    How to request Admin Privileges

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

    【讨论】:

    • 我怀疑windows如何决定uac是否应该提示。您的方法以管理员身份运行程序,并且确实要求用户输入管理员密码。
    • 这就是它的工作原理,尽管 Codeproject 文章不是很完整。您可以在该清单中要求具有细微或不存在差异的不同选项的一小部分选择(例如请求最高可能的权限或管理员权限或等等),但基本上就是这样。 Windows 安全性相当愚蠢,但另一方面,我希望我能引用一个不那么愚蠢的系统(Linux 甚至 更愚蠢,因为它会让你输入 root 密码......)。
    【解决方案4】:

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

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

    【讨论】:

    • 更新程序是我创建的。那么其中的一些代码会触发 UAC 提示?我没有在我的代码中以管理员身份运行更新程序 exe(以管理员身份运行,这会导致 UAC 始终提示)。那么是不是一些触发 UAC 的代码?
    • 我相信 Windows 确实有一些额外的启发式方法:例如,它过去是否需要 UAC?是否命名为“setup.exe”?
    • 文件名不是setup.exe。但是 UAC 是否也依赖于文件名?
    猜你喜欢
    • 1970-01-01
    • 2011-05-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-10-28
    • 1970-01-01
    相关资源
    最近更新 更多