Tutorial :CreateProcessAsUser vs ShellExecute


I need to ShellExecute something as another user, currently I start a helper process with CreateProcessAsUser that calls ShellExecute, but that seems like too much of a hack (Wrong parent process etc.) Is there a better way to do this?

@PabloG: ImpersonateLoggedOnUser does not work:

  HANDLE hTok;  VERIFY(LogonUser("otheruser",0,"password",LOGON32_LOGON_INTERACTIVE,LOGON32_PROVIDER_DEFAULT,&hTok));  VERIFY(ImpersonateLoggedOnUser(hTok));  ShellExecute(0,0,"calc.exe",0,0,SW_SHOW);  RevertToSelf();  CloseHandle(hTok);  

will just start calc as the logged in user, not "otheruser"

@1800 INFORMATION: CreateProcess/CreateProcessAsUser is not the same as ShellExecute, with UAC on Vista, CreateProcess is useless when you don't have control over what program the user is executing (CreateProcess will return with a error if you give it a exe file with a manifest marked as requireAdmin)

@Brian R. Bondy: I already know this info (And don't get me wrong, its good stuff), but it is off topic (IMHO) I am asking for a ShellExecuteAsUser, not about starting processes as another user, I already know how to do that.


The solution really depends on what your needs are, and can be pretty complex (Thanks fully to Windows Vista). This is probably going to be beyond your need, but this will help others that find this page via search.

  1. If you do not need the process to run with a GUI and you do not require elevation
  2. If the user you want to run as is already logged into a session
  3. If you need to run the process with a GUI, and the user may, or may not be logged in
  4. If you need to run the process with elevation

Regarding 1: In windows Vista there exists something called session 0 isolation. All services run as session 0 and you are not supposed to have a GUI in session 0. The first logged on user is logged into session 1. In previous versions of windows (pre Vista), the first logged on user was also ran fully in session 0.

You can run several different processes with different usernames in the same session. You can find a good document about session 0 isolation here.

Since we're dealing with option 1), you don't need a GUI. Therefore you can start your process in session 0.

You'll want a call sequence something like this: LogonUser, ExpandEnvironmentStringsForUser, GetLogonSID, LoadUserProfile, CreateEnvironmentBlock, CreateProcessAsUser.

Example code for this can be found via any search engine, or via Google code search

Regarding 2: If the user you'd like to run the process as is already logged in, you can simply use: WTSEnumerateSessions, and WTSQuerySessionInformation to get the session ID, and then WTSQueryUserToken to get the user token. From there you can just use the user token in the CreateProcessAsUser Win32 API.

This is a great method because you don't even need to login as the user nor know the user's username/password. I believe this is only possible via a service though running as local system account.

You can get the current session via WTSGetActiveConsoleSessionId.

Regarding 3: You would follow the same steps as #1, but in addition you would use the STARTUPINFO's lpDesktop field. Set this to winsta0\Default. You will also need to try to use the OpenDesktop Win32 API and if this fails you can CreateDesktop. Before using the station and desktop handles you should use SetSecurityInfo on each of them with SE_WINDOW_OBJECT, and GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION.

If the user in question later tries to login, he will actually see the running process.

Regarding 4: This can be done as well, but it requires you to already be running an elevated process. A service running as local system account does run as elevated. I could also only get it to work by having an authenticode signed process that I wanted to start. The process you want to start also must have a manifest file associated with it with the requestedExecutionLevel level="requireAdministrator"

Other notes:

  • You can set a token's session via SetTokenInformation and TokenSessionId
  • You cannot change the session ID of an already running process.
  • This whole process would be drastically more simple if Vista was not in the equation.


If you need ShellExecute semantics you can feed following:

C:\windwos\system32\cmd.exe /k" start <your_target_to_be_ShellExecuted>" to CreateProcessAsUser and you are done.


You can wrap the ShellExecute between ImpersonateLoggedOnUser / RevertToSelf

links: ImpersonateLoggedOnUser: http://msdn.microsoft.com/en-us/library/aa378612(VS.85).aspx RevertToSelf: http://msdn.microsoft.com/en-us/library/aa379317.aspx

sorry, cannot hyperlink URLs with "()"


Why don't you just do CreateProcessAsUser specifying the process you want to run?

You may also be able to use SHCreateProcessAsUserW.

Note:If u also have question or solution just comment us below or mail us on toontricks1994@gmail.com
Next Post »