1
votes

We developed an ActiveX form control to be installed in IE8+. This control checks for a registry key then download and install a small setup if needed. For administrator everything work as expected on Windows 7 and 8 with any IE version 8+.

With non-admin users, the control runs (it must be installed by admin, but it's ok), it downloads the executable client_setup.exe in path C:\users\user\AppData\Local\Temp\Low\ but when it tries to run executable (shellexec or createprocess produce same result) an administrative account is required and UAC elevation prompt appears.

If non-admin user download and install same setup, no administration privilege is required (we declared this in exe manifest). This setup is entirely installed in user profile and HKCU registry.

I understand that ActiveX control runs with low privileges like IE process. But why elevation is required in this case? Our setup do not requires privileges.

I tried to add ActiveX control in Low Rights elevation policy exceptions here

HKEY_LOCAL_MACHINE\SOFTWARE\\Microsoft\Internet Explorer\Low Rights\ElevationPolicy

but still UAC prompt appears.

I want to allow to run this setup for all users. We can run once as administrator a script to give permission for the whole system. Can someone help with this task?

TEST 1

As non-admin user, I tried to manually install the .exe downloaded by the ActiveX and I get a system error, cannot write to temp directory. If I download the same exe file with Internet Explorer I can install this with no problems.

I checked with ICACLS and on exe downloaded by ActiveX control there is a Mandatory Label\Low Mandatory Level:(I)(NW)

TEST 2

Site was added to trusted sites as Taxilian suggested. As non-admin user, ActiveX now saves .exe setup to C:\users\user\AppData\Local\Temp (no Low), .exe hasn't low level label anymore. But still, CreateProcess raises UAC prompt and fails.

This is my CreateProcess code. It's Delphi code but it should be readable.

function RunProcess(FileName: string; ShowCmd: DWORD; wait: Boolean; ProcID: PDWORD): Longword;
var
  StartupInfo: TStartupInfo;
  ProcessInfo: TProcessInformation;
begin
  FillChar(StartupInfo, SizeOf(StartupInfo), #0);
  StartupInfo.cb := SizeOf(StartupInfo);
  StartupInfo.dwFlags := STARTF_USESHOWWINDOW or STARTF_FORCEONFEEDBACK;
  StartupInfo.wShowWindow := ShowCmd;
  if not CreateProcess(nil,
    @Filename[1],
    nil,
    nil,
    False,
    CREATE_NEW_CONSOLE or NORMAL_PRIORITY_CLASS,
    nil,
    nil,
    StartupInfo,
    ProcessInfo)
    then
    Result := WAIT_FAILED
  else
  begin
    if wait = FALSE then
    begin
      if ProcID <> nil then
        ProcID^ := ProcessInfo.dwProcessId;
      result := WAIT_FAILED;
      exit;
    end;
    WaitForSingleObject(ProcessInfo.hProcess, INFINITE);
    GetExitCodeProcess(ProcessInfo.hProcess, Result);
  end;
  if ProcessInfo.hProcess <> 0 then
    CloseHandle(ProcessInfo.hProcess);
  if ProcessInfo.hThread <> 0 then
    CloseHandle(ProcessInfo.hThread);
end;

This is .exe manifest. It is a simple setup that copies some files to user profile and add a registry key in HKCU.

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
    <assemblyIdentity name="JR.Inno.Setup" processorArchitecture="x86" version="1.0.0.0" type="win32" />
    <description>Inno Setup</description>
    <dependency>
        <dependentAssembly>
            <assemblyIdentity type="win32" name="Microsoft.Windows.Common-Controls" version="6.0.0.0" processorArchitecture="x86" publicKeyToken="6595b64144ccf1df" language="*" />
        </dependentAssembly>
    </dependency>
    <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
        <security>
            <requestedPrivileges>
                <requestedExecutionLevel level="asInvoker" uiAccess="false" />
            </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>
    <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
        <application>
            <supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}" />
            <supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}" />
        </application>
    </compatibility>
</assembly>
2
What exactly happens when you use CreateProcess to try to launch the executable? Does CreateProcess return an error code? Have you tried using Process Monitor to track the sequence of events?Harry Johnston
CreateProcess returns error code 1 which doesn't make sense to me. In fact CreateProcess fails due to UAC prompt.Ghigo
Maybe out of topic, but: - why are you calling CloseHandle event when CreateProcess fails? - you are not calling CloseHandle when Wait=False - if your Filename will contain spaces, and it won't be double-quoted, then you it will failKrystian Bigaj
Thanks for the hint. Filename is already double quoted elsewhere. CloseHandle is called only when there's something to close. It should be ok.Ghigo
CreateProcess isn't supposed to be generating a UAC prompt in the first place. If elevation is required, CreateProcess should fail immediately. Are you sure the UAC prompt isn't being generated after the executable has already been started?Harry Johnston

2 Answers

2
votes

Windows UAC uses some heuristics to detect installers.

From http://blogs.msdn.com/b/uac/archive/2006/01/13/512776.aspx :

The O/S makes a decision that the application looks like an installer or updater and will automatically invoke elevation to run the program with administrative permissions/privileges when a user runs it. This decision is based on a heuristic. Here are some of the heuristic detection points, although this list is not exhaustive:

  1. File name detection – looks for the words “setup”, “update”, “install” in the filename

Our setup name is client_setup.exe, so UAC is triggered even if it's not needed, asking for administration privileges, totally ignoring exe manifest. Let's call this a feature.

It was enough to rename client_setup.exe to client.exe, then run it. No UAC prompt appears and setup completes successfully.

This looks like a recent change from Microsoft. As recent as 4 months ago, our setup was launched without errors.

0
votes

It isn't the activex control that has to be registered to run as a medium integrity process, it's the EXE that you are launching from said activex control.