Launch a Process as Standard User from an Elevated Process
There are many well-documented ways for launching an elevated (administrative) process from within a process that is running using standard user credentials. The cleanest way is by giving that process a manifest; if this can’t be done, the ShellExecute “runas” verb is the way to go. This is all yesterday’s news, really.
However, there’s a more interesting question: how do you launch a process as the standard user, if the current process is already elevated? As you probably know, a process can’t change its elevation status – an elevated process can’t downgrade itself to a standard user, and a non-elevated process can’t elevate itself. Additionally, there is no special API that obtains the token of the standard user – the token that the elevated process is using is a high-privileged token.
A naive (and very error-prone) approach would be to strip some privileges and rights away from the privileged token. First of all, it’s not very robust because a future release of the OS might add new privileges that you didn’t strip away. Second, this “dumbed-down” token is still considered an elevated token by the OS.
But there’s a more serious problem, and that’s the problem of OTS – over-the-shoulder elevation. If the elevation was a result of an administrator typing in his credentials over the user’s shoulder, then the process is running under the credentials of a different user – that’s not the currently logged on user, so stripping this token will not magically make it the current user’s token.
Aaron Margosis tells this story and offers a C++ solution to launch a process as standard user. The general steps are to obtain the user token of the shell process (explorer.exe), make a primary token off of that and then launch the new process with that token.
I’ve taken the liberty of adapting the sample so that it can be used from managed code, and added it to the UAC Helpers project on CodePlex, release v0.1 (last time it was updated was over a year and a half ago, so it’s about time that we stir it up a little bit). The new functionality is available in the UserAccountControl.CreateProcessAsStandardUser method, and it’s very easy to use (if the process is not elevated, it just falls back to using System.Diagnostics.Process.Start).