user_account_control_administrator_dialogUser Account Control (UAC) is a new technology introduced by Microsoft in Windows Vista and most of the time it is misunderstood by users and developers. It’s main purpose is to protect the operating system by running applications with reduced privileges.

Why should we use this? Most applications DO NOT require full privileges. Think to the applications you have written and ask yourself if most of the job can be done without full writes (if you write to disk think if you could write in the user’s folder or an isolated storage, if writing in registry to HKLM think if you could write to HKLU, etc). The answer is mostly sure “Yes”.

So why run applications with full privileges when they can be run with limited? Running with more privileges than required is just a security vulnerability –  If an attacker exploits a vulnerability in your application he will gain more control.

There are two mistakes developers tend to do:unidentified_uac

  1. Request the end-user to run an application with full rights even though this is not necessarily (most of the time because of bad design practices)
  2. Do not request to user to run the application elevated but try to perform operations that require more rights

By design UAC can only elevate code at process level and only at process’ startup (means that a running process cannot be elevated). In the .NET world this also means that you cannot elevate code running in another app domain because the app domain is part of a running process. In order to elevate an existing application this must be closed and reopen with more privileges.

There are two types on UAC dialogs: blue and yellow. When you see a blue dialog you can be sure that the application requesting privileges is signed and trusted. The yellow dialog shows for any application that is not digitally signed and is not fully trusted.

User Account Control also prevents a lower privilege process to do the following (list below taken from MSDN):

  • Perform a window handle validation of higher process privilege.
  • SendMessage or PostMessage to higher privilege application windows. These Application Programming Interfaces (APIs) return success but silently drop the window message.
  • Use thread hooks to attach to a higher privilege process.
  • Use Journal hooks to monitor a higher privilege process.
  • Perform DLL injection to a higher privilege process.

Let’s see how an UAC aware application should look.

It should be composed of two executables (one that will be run with limited privileges and another one that will be started only with needed and with full rights) or two working modes (a mode for limited rights and another one for full rights). Either way you must remember that once you elevated the application and finalized the administrative tasks, the process should be destroyed in order to reduce an attacker’s privileges.

In order to launch an elevated process in Windows Vista the process must be started with the “runas” verb. The Verb property is part of System.Diagnostics.Process.StartInfo class. The code snippet that launches “notepad.exe” with full rights is showed below:

    ProcessStartInfo processInfo = new ProcessStartInfo();
    processInfo.Verb = "runas";
    processInfo.FileName = "notepad.exe";
    Process.Start(processInfo);

If you choose to have only one executable file that acts differently based on permissions you should check if the user is part of the administrative group. In Vista even if your user is part of the Administrators group it runs with reduced privileges by default and gains his full rights on demand. The code below stores true in the hasAdministrativeRight boolean variable if the user’s privileges are administrative and false otherwise.

    WindowsPrincipal pricipal = new WindowsPrincipal(WindowsIdentity.GetCurrent());
    bool hasAdministrativeRight = pricipal.IsInRole(WindowsBuiltInRole.Administrator);

To elevate the current application you must create a process with elevated rights and close the existing instance. However you cannot start a process with limited privileges – I couldn’t find a solution. Anyone knows how to start a less privilege process from a higher privilege one? The sample creates an elevated instance of the current executable and closes the existing one.

    RunElevated(Application.ExecutablePath);
    this.Close();

RunElevated is a method that takes the name of an executable and spawns it in a new elevated process (see the attached code).

I have created a sample application that illustrates all the things written so far: it displays the user’s rights, elevates the current application and starts a process with more privileges. In order to see all features of the application you must have UAC enabled. You can download the code from this link.

Please note that here I recommend to run applications with limited privileges but there are situations when applications need to run unrestricted – this is the case of system configuration utilities or other special applications. What I want to say is that you should run applications in an unprivileged environment when possible.

This is part one of the tutorial. Part 2 will explain how to use the manifest file to specify that an executable must be always run with full privleges.

Download Source Code

25 comments

  1. Alexandru on April 1st, 2009 at 12:10 pm

    Have a look on UAC on Windows 7 (beta build 7000) : http://tinyurl.com/df4tpe ,http://tinyurl.com/d8rdcr

  2. Timotei Dolean on April 1st, 2009 at 8:54 pm

    Cool, i didn’t know that’s possible from C#

    Good job!

  3. Using UAC with C# - Part 2 | Ex nihilo nihil fit on April 3rd, 2009 at 8:15 pm

    [...] Recent Comments April Fool’s Day – Live Search | Ex nihilo nihil fit on Chuck Norris LHC FactsApril Fool’s Day – Live Search | Ex nihilo nihil fit on Chuck Norris Java factsTimotei Dolean on Using UAC with C# – Part 1 [...]

  4. Sergio K. on April 22nd, 2009 at 3:05 pm

    Did you try to do it with a different user? I strugle with this for a days. It just does not elevate user rights.
    Code Example:

    ProcessStartInfo processInfo = new ProcessStartInfo();
    SecureString securePassword = new SecureString();
    foreach (char ch in “testpass”)
    {
    securePassword.AppendChar(ch);
    } // foreach
    processInfo.UserName = “testuser”;
    processInfo.Password = securePassword;
    processInfo.Verb = “runas”;
    processInfo.FileName = @”c:\windows\system32\cmd.exe”;
    processInfo.UseShellExecute = false;
    Process.Start(processInfo);

    testuser is administrator. Problem is that this code does not run process elevated. Do you have any idea? Thanks!

  5. Chethan on May 5th, 2009 at 2:22 pm

    I think you should set processInfo.UseShellExecute to true and processInfo.Verb to “runas”

  6. Sergio K. on May 8th, 2009 at 4:58 pm

    We already set .Vert to “runas”. You can not set UserShellExecute to true because than you can not impersonate another user. You will get appropriate exception if you try to do that.
    Thanks for suggestion, but we are still looking to resolve it, since this is currently show stopper for our project.

  7. FM on August 28th, 2009 at 7:04 pm

    Why are you specifying a username?

    If an application needs to run as Administrator, leave off the Username and Password. If the user executing the application has rights to elevate, they will receive a UAC prompting them for this. If they do not, they will be prompted for the password of an account with elevate privilege by the UAC subsystem.

    Doing this means your spawned process will run as the local Administrator user. This is most often what you want if you need administrator privileges.

    In Vista/Win7, making an account “administrator” does not give it privileges on the system, rather it gives it an “elevate” privilege, meaning that account can approve a process to elevate itself to run as Administrator via the UAC dialogs. (Users not marked as Administrator need to supply the password for an Administrator account in order to elevate; users marked as Administrator need only click “OK” or Cancel as desired.)

    Hope this helps

    FM

  8. Sergio K. on November 28th, 2009 at 2:45 pm

    We have to set username because we wanted to use impersonation of a user that did not start original process. Our tool have to behave like ‘runas’ command but without prompting for credentials.
    In the meantime we contacted Microsoft support and in cooperation with their experts we clarify UAC.
    You may read a post in our lab at http://www.icodefactory.com/lab

  9. Devin on December 10th, 2009 at 8:52 pm

    Thanks for the sample code, this helped me a lot.

  10. Giammarco Schisani on December 30th, 2009 at 1:56 pm

    Found this useful. Thanks for sharing.

  11. antohag on May 6th, 2010 at 3:36 pm

    Thanks, from Russia with love… =)

  12. ?????? @ Win7 | ???? on December 11th, 2010 at 4:35 am

    [...] ??????????????????????????????????????“????????”?????????????????????????????????????????????? UAC ????????By design UAC can only elevate code at process level and only at process’ startup.? [...]

  13. Stefan on January 21st, 2011 at 7:41 am

    I have an app that runs in the system tray that starts-up every time the user logs in.
    (It has a shortcut in the startup folder).

    Frequently, it requires Administrator priviliges to write files to Program Files\n
    If i mark the manifest as \requireAdministrator\ it always (when the app starts up) asks for a prompt for admin rights, as the user is not an administrator.

    i does not seem that i can create a prompt for elevation (and get an bollena back) only when i need to do the code that requires “admin rights”??

    Plse advise

  14. Victor on January 21st, 2011 at 9:53 am

    Hi Stefan,

    Use the snippet provided in the post:

    WindowsPrincipal pricipal = new WindowsPrincipal(WindowsIdentity.GetCurrent());
    bool hasAdministrativeRight = pricipal.IsInRole(WindowsBuiltInRole.Administrator);

    Hope this helps

  15. Stefan on January 21st, 2011 at 10:36 am

    Thanks

    If i understand correctly, This should tell me whether the current user is an administrator (in the admin role) or not.
    #1
    How do i prompt for admin credentials if he is not?
    #2
    Or should i then run a second exe application (that will ask for elevation) that does the update under the “\program Files\” directory.
    (I dont really want to split my app.)

  16. Victor on January 21st, 2011 at 11:28 am

    @Stefan,

    You need a second process that will be started with elevated privileges. You cannot elevate a running process.

  17. Stefan on January 25th, 2011 at 12:54 pm

    As soon as i start the second process in elevated mode, It asks for Admin credentials.
    Is there a way i can supress this UI? – Maybe hardcode the admin username and password of the elevated process? (I know this is a no-no).

  18. Victor on January 25th, 2011 at 3:45 pm

    Stefan, can I ask you about the scenario in which you want to supress the dialog?

    IMO, if UAC is active then it should stay active. Why is a problem if the credentials window is displayed?

  19. msp.netdev on February 9th, 2011 at 3:00 pm

    thanks for code, very usefull

  20. Anthony on May 16th, 2011 at 6:05 am

    Much like stefan’s comment above, i have a situation where i need to elevate a process created in C#. Specifically i have to start/stop/restart a windows service. I can query the service just fine but actually getting the service to do something keeps on throwing an “Access is denied” exception. So far i’ve tried:

    -changing the manifest file so that permission level is set to “highestAvailable” (still was deined access)
    -creating my own service that would in turn restart the service i was originally targetting (this new service was then denied access to the original service – or so it seems. furhtermore i was denied access to it.)
    -trying to create my own token? (i wouldn’t consider myself completely new to c# but i’ve never really dealt with the UAC security model and i’m kind of flying blind here)

    Ultimately i’ve settled on hijacking the task scheduler to run the my program in an elevated state, though this seems like an inelegant way to do things.

    I get the fact that this is the very thing UAC is put in place for, namely the prevention of running potentially dangerous code without the prompting the user first.

    In order to give you some background as to why i’m trying to suppress the dialog. My laptop has an illuminated keyboard but no button that directly turns it off/on. You have to drill down through a settings app and manually turn illumination on/off. My goal was to set illumination to a remapped key/key sequence. So far i have the key sequence set up, i’ve found what Xml file controls the on/off value, and the only thing i have left to make it work is to restart the service that controls whether or not the keyboard is lit. My plan was to make the change from on to off transparent and seamless to the user and the UAC prompt ruins that. It’s a shame there isn’t a way to either whitelist a process or to pass user/password info to a process without the dialog. As i’ve said above i’ve kind of given up and intend on using the task scheduler but that’s not really it’s intended purpose and was wondering if anyone had made some progress.

  21. Andre on May 31st, 2011 at 1:01 pm

    Thanks for your code but I’ve a problem using ist with Windows 7 …
    I run a progress using like described:
    ProcessStartInfo info = new ProcessStartInfo(MyApp, cmd);
    info.Verb = “runas”;
    Process.Start(info);

    MyApp try than to change the rights of a file:
    FileSecurity fnew = File.GetAccessControl(target);
    FileSecurity fold = File.GetAccessControl(oldFile);
    AuthorizationRuleCollection arc = fold.GetAccessRules(true, true, typeof(System.Security.Principal.NTAccount));
    System.Collections.IEnumerator ienu = arc.GetEnumerator();
    while (ienu.MoveNext())
    {
    FileSystemAccessRule ar = (FileSystemAccessRule)ienu.Current;
    if (ar.IdentityReference != null)
    {
    fnew.PurgeAccessRules(ar.IdentityReference);
    fnew.AddAccessRule(new FileSystemAccessRule(ar.IdentityReference, ar.FileSystemRights, ar.AccessControlType));
    }
    }
    fnew.SetOwner(fold.GetOwner(typeof(System.Security.Principal.NTAccount)));
    fnew.SetAuditRuleProtection(false, true);
    File.SetAccessControl(target, fnew);

    Now I get the error “SeSecurityPrivilege is missing” with Windows 7.
    Any idea how I can use my code also with W7?

  22. UAC in .NET Anwendungen - seeseekey.net on November 20th, 2011 at 1:49 am

    [...] Infor­ma­tio­nen gibt es unter: http://www.vbarchiv.net/workshop/workshop_115.html http://victorhurdugaci.com/using-uac-with-c-part-1/ http://victorhurdugaci.com/using-uac-with-c-part-2/ [...]

  23. Lawrence Sweet on March 1st, 2012 at 3:04 pm

    Anthony,

    You might try “setacl.exe” as part of your installation. You can grant users and/or groups specific rights to work with specific windows services.

    Also, “local system account” privileges might be required to start your own service…(?). Better double check that one :)

    Best Wishes

  24. Ray on April 1st, 2012 at 7:23 am

    Thank you very much!
    This is very useful!

  25. UAC troubles « Philippsen's Blog on June 12th, 2012 at 12:03 pm

    [...] Using UAC with C# [...]

Leave a comment

Please write the comment in English!

Allowed HTML tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>