Thursday, 1 October 2015

Elevate your .Net Application without a manifest

Administrator privileges are used quite frequently for tasks such as allowing your program to make changes to the file system. One way to go at it would be by adding a manifest when installing the program. But if you're a programmer, there's always a better way to do it.

How does the Windows explorer do it?
The verb 'RunAs' is used when launching a process.

How does this work?
On Vista and above, if UAC (User Account Control) is set to active, it would show a dialog box asking for administrator privileges. If you've disabled it, the application should elevate itself automatically.
Note: On Windows XP it would display a 'Run as' dialog box regardless.

How does this help us?
We can use the same method when coding a .Net application.

The Algorithm

- Application starts
- Checks if it has elevated access
- If true, continue to execute program.
- If false, create a new process with the 'RunAs' verb, forward the arguments, and exit itself.
- The new process starts and asks for Administrator privileges using the UAC dialog.

The Code(C++)

using namespace System::Security::Principal;

int main(array<system::string^> ^args)
{
    // Check Elevation
    bool r = ((gcnew WindowsPrincipal(
        WindowsIdentity::GetCurrent()))
        ->IsInRole(WindowsBuiltInRole::Administrator));
    // If Not Elevated
    if(!r)
    {
        // Prep Elevated Process Data
        ProcessStartInfo^ p;
        // Assign the Application's path to the process
        p = gcnew ProcessStartInfo(Application::ExecutablePath);
        p->Verb = "runas";
        p->UseShellExecute = true;
        //Prep to Forward Arguments
        p->Arguments = String::Join(" ",
            System::Environment::GetCommandLineArgs())
            ->Replace(Application::ExecutablePath," ")->Trim();
        // Execute Process, and Clean Up
        Process::Start(p);
        delete p;
        //Exit Parent Process
        return 0;
    }
    // Else ( If Elevated )
    // Do some work
    return 0;
}