How to run WIX bootstrapper application UI with elevated privileges?

WIX bootstrapper application (BA) can easily determine if it runs as admin with the following code:

using System;
using System.Diagnostics;
using System.Security.Principal;

static bool IsAdmin()
{
    WindowsIdentity id = WindowsIdentity.GetCurrent();
    WindowsPrincipal principal = new WindowsPrincipal(id);
    return principal.IsInRole(WindowsBuiltInRole.Administrator);
}

and if it does not, run a new instance as admin and exit:

static void RunAsAdmin()
{
    ProcessStartInfo proc = new ProcessStartInfo
    {
        UseShellExecute = true,
        WorkingDirectory = Environment.CurrentDirectory,
        FileName = Process.GetCurrentProcess().MainModule.FileName,
        Verb = "runas"
    };

    Process.Start(proc);
}

But in this case the installation fails with the following message in the log file:

Failed to resolve source for file: C:\Users\izam\AppData\Local\Temp\{A33F0145-DA8F-4E56-8E2D-4FFAF10EA8DE}\.cr\MyBa.exe, error: 0x80070002.
Error 0x80070002: Failed while prompting for source (original path 'C:\Users\izam\AppData\Local\Temp\{A33F0145-DA8F-4E56-8E2D-4FFAF10EA8DE}\.cr\MyBa.exe').
Failed to acquire container: WixAttachedContainer to working path: C:\WINDOWS\Temp\{D3D98F56-BCEE-4EE7-B6EC-F9B6BD5DB65E}\C4B97876D570D75BA705654792340F1D409FA4FD, error: 0x80070002.
Error 0x80070002: Failed while caching, aborting execution.

My another attempt was to replace level in the manifest of BA with ‘requireAdministrator‘ using the following commands::

mt.exe -inputresource:MyBA.exe -out:extracted.manifest
mt.exe -manifest app.manifest -outputresource:MyBA.exe

For example, the manifest extracted from my BA with replaced ‘level’ looks like this (this manifest can be found in WIX source code on GitHub):

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
    <assemblyIdentity name="setup.exe" version="1.0.0.0" processorArchitecture="x86" type="win32"></assemblyIdentity>
    <description>WiX Toolset Bootstrapper</description>
    <dependency>
        <dependentAssembly>
            <assemblyIdentity type="win32" name="Microsoft.Windows.Common-Controls" version="6.0.0.0" processorArchitecture="X86" publicKeyToken="6595b64144ccf1df" language="*"></assemblyIdentity>
        </dependentAssembly>
    </dependency>
    <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
        <security>
            <requestedPrivileges>
                <requestedExecutionLevel level="requireAdministrator" uiAccess="false"></requestedExecutionLevel>
            </requestedPrivileges>
        </security>
    </trustInfo>
    <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
        <application>
            <supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"></supportedOS>
            <supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"></supportedOS>
            <supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"></supportedOS>
            <supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"></supportedOS>
            <supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"></supportedOS>
        </application>
    </compatibility>
</assembly>

but BA refused to run with modified manifest. Probably replacing the manifest breaks its internal structure somehow.

In general this technique of replacing the manifest in an existing exe file works fine, for example, if I create an MFC application with default settings in VS2015, it has the following manifest:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
    <dependency>
        <dependentAssembly>
            <assemblyIdentity type="win32" name="Microsoft.Windows.Common-Controls" version="6.0.0.0" processorArchitecture="x86" publicKeyToken="6595b64144ccf1df" language="*"></assemblyIdentity>
        </dependentAssembly>
    </dependency>
    <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
        <security>
            <requestedPrivileges>
                <requestedExecutionLevel level="asInvoker" uiAccess="false"></requestedExecutionLevel>
            </requestedPrivileges>
        </security>
    </trustInfo>
    <application xmlns="urn:schemas-microsoft-com:asm.v3">
        <windowsSettings>
            <dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true</dpiAware>
        </windowsSettings>
    </application>
</assembly>

and if I replace ‘asInvoker‘ with ‘requireAdministrator‘ using mt.exe, the application successfully runs with elevated privileges.

The commands I used (in Git Bash) to search the manifests in WIX sources are (RTM is a short for “release to manufacturing”):

git clone https://github.com/wixtoolset/wix3.git
git tag
git reset --hard wix3111rtm
cd wix3
find . -iname "*.manifest"
grep -ri --include="*.manifest" "setup.exe"
grep -ri --include={*.cpp,*.rc} "stub.manifest"

Links:

  1. Wix Bootstrapper manifest or elevated custom action

Leave a Reply

Your email address will not be published. Required fields are marked *