Click here to Skip to main content
11,812,712 members (71,183 online)
Click here to Skip to main content

Launch your application in Vista under the local system account without the UAC popup

, 17 Apr 2007 CPOL 335.2K 8K 150
Rate this:
Please Sign up or sign in to vote.
This article describes how to launch an application from session 0 to session 1 under the local system account using a service helper application


In Vista, I came across a problem where I wanted to launch an exe under an administrator account to perform certain tasks. I could not do that because the UAC elevation dialog box would appear for which the user would have to respond. To work around that problem, I came up with the solution of launching the required application from a service into the current user session with local system account privileges.This would not require us to respond to the UAC dialog box. This way I could run my application with the highest privilege possible, avoiding the UAC dialog box. In my case this was necessary since I needed to control/communicate with applications running with administrative rights without user intervention and perform some administrative tasks in the current user session on system startup.


The concept which I use is very straightforward. I have a normal user mode application which communicates with a service through custom messages. On receiving the custom message, the service will launch the requested application (that I want) under the system account. To get hold of a local system account I used the winlogon's token in the required session since winlogon.exe runs under the local system account. (In Vista, services are present in session 0 and the first user logs on in session 1 and so on, unlike in XP)

Using the code

First let us review the file CustomMessageSender.cpp. This is the usermode application which communicates with the service.This application can be any normal application without any special privileges.

#define SERVICE_NAME _T("CustomSvc")

int _tmain(int argc, _TCHAR* argv[])
    SC_HANDLE hMyService,hSCM;
    BOOL bSuccess;
    SERVICE_STATUS status;
    hSCM = OpenSCManager(0,0,SC_MANAGER_CONNECT);
        printf("Open SCM failed with error %u",GetLastError());
        printf("Open SCM failed with error %u",GetLastError());
    bSuccess = ControlService(hMyService,SERVICE_CONTROL_CUSTOM_MESSAGE,&status);
        printf("Control Service failed with error %u",GetLastError());
    return 0;

The code above is very simple and straightforward. I use SERVICE_USER_DEFINED_CONTROL and SC_MANAGER_CONNECT access permission because any user mode applications can connect to our service to send customize messages to it. No admin privileges are required. So this application sends the SERVICE_CONTROL_CUSTOM_MESSAGE to the service. The service part of the code which receives the messages and launches the application is below. I have used a sample service posted by Anish in Code Project and added my features into it.


//Method to launch an application into session 1 under 
//the local system account

BOOL LaunchAppIntoDifferentSession();
void WINAPI ServiceCtrlHandler(DWORD Opcode)
//Added By Jaisvar on 04/11/07 to receive a custom message from a user app


In the above code snippet, I have declared the custom message and the prototype of the method which I will be executing on receiving the custom message. Let me describe the LaunchAppIntoDifferentSession Method before I display the code snippet. To launch a process under the local system account I perform the following steps:

  1. Get the Active Console SessionId using WTSGetActiveConsoleSessionId
  2. Since I need to launch the application under a system account, I use the token from Winlogon, since Winlogon runs under the system account. So I obtain the process ID of Winlogon and Duplicate the token.
  3. Then I make sure I sent the startupinfo parameter lpDesktop to winsta0\Default since I need to launch my process there.
  4. Then I use CreateProcessAsUser with Winlogon's duplicate token to launch my process into session 1.
  5. That's all. I am done.
BOOL LaunchAppIntoDifferentSession()
   BOOL bResult = FALSE;
   DWORD dwSessionId,winlogonPid;
   HANDLE hUserToken,hUserTokenDup,hPToken,hProcess;
   DWORD dwCreationFlags;

// Log the client on to the local computer.

   dwSessionId = WTSGetActiveConsoleSessionId();

   // Find the winlogon process

   PROCESSENTRY32 procEntry;

    HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    if (hSnap == INVALID_HANDLE_VALUE)
        return 1 ;

    procEntry.dwSize = sizeof(PROCESSENTRY32);

    if (!Process32First(hSnap, &procEntry))
        return 1 ;

        if (_stricmp(procEntry.szExeFile, "winlogon.exe") == 0)
            // We found a winlogon process...
        // make sure it's running in the console session
            DWORD winlogonSessId = 0;
            if (ProcessIdToSessionId(procEntry.th32ProcessID, &winlogonSessId) 
                    && winlogonSessId == dwSessionId)
                winlogonPid = procEntry.th32ProcessID;

    } while (Process32Next(hSnap, &procEntry));


   ZeroMemory(&si, sizeof(STARTUPINFO));
   si.cb= sizeof(STARTUPINFO);
   si.lpDesktop = "winsta0\\default";
   ZeroMemory(&pi, sizeof(pi));
   LUID luid;
   hProcess = OpenProcess(MAXIMUM_ALLOWED,FALSE,winlogonPid);

               int abcd = GetLastError();
               printf("Process token open Error: %u\n",GetLastError());

   if (!LookupPrivilegeValue(NULL,SE_DEBUG_NAME,&luid))
       printf("Lookup Privilege value Error: %u\n",GetLastError());
   tp.PrivilegeCount =1;
   tp.Privileges[0].Luid =luid;
   tp.Privileges[0].Attributes =SE_PRIVILEGE_ENABLED;

   int dup = GetLastError();

   //Adjust Token privilege

   if (!AdjustTokenPrivileges(hUserTokenDup,FALSE,&tp,sizeof(TOKEN_PRIVILEGES),
       int abc =GetLastError();
       printf("Adjust Privilege value Error: %u\n",GetLastError());

   if (GetLastError()== ERROR_NOT_ALL_ASSIGNED)
     printf("Token does not have the provilege\n");



// Launch the process in the client's logon session.

  bResult = CreateProcessAsUser(
      hUserTokenDup,                     // client's access token
      _T("C:\\SessionLauncher\\a.exe"),    // file to execute
      NULL,                 // command line
      NULL,            // pointer to process SECURITY_ATTRIBUTES
      NULL,               // pointer to thread SECURITY_ATTRIBUTES
      FALSE,              // handles are not inheritable
      dwCreationFlags,     // creation flags
      pEnv,               // pointer to new environment block
      NULL,               // name of current directory
      &si,               // pointer to STARTUPINFO structure
      &pi                // receives information about new process
// End impersonation of client.

//GetLastError Shud be 0

   int iResultOfCreateProcessAsUser = GetLastError();

//Perform All the Close Handles tasks


 return 0;

This way a normal user mode application can send a custom message to a service to launch itself under the local system account without the UAC dialog box popping up.

Some readers wanted to know how to:

  1. Get GetUserName() API to return the current logged on user
  2. Access the HKCU under the system account

Well, it is virtually impossible from the userland to surpass the UAC dialog when we launch a process which requires elevation, since it is designed that way by Microsoft. Although it may be possible to effect these changes through writing some kernel mode code (DKOM concepts). But still from the userland, the best I could think about was to impersonate the system account to act as the logged on user to access the HKCU. I use the Explorer process for this purpose since it runs under the user account.

Impersonating the user token will cause the current worker thread to run under the user context. Note that if you use CreateProcess() it will still spawn a process under the System Account since our overall process is still running under the local system account.

The code to do that is listed in the snippet below. This code needs to be written into the application which will be launched by the service. I have not included this piece of code in the ""

DWORD dwSessionId,dwExplorerLogonPid,dwSize,dwRegDataSize;
HANDLE hProcess,hPToken;
char szUserName[MAX_PATH];
char szRegData[MAX_PATH];
char szRegPath[500] = "Software\\Microsoft\\Windows\\CurrentVersion\\Run";
HKEY hKey; //Handle to registry Key
long lRegResult; //Registry operation result

//Get the active desktop session id
dwSessionId = WTSGetActiveConsoleSessionId();

//We find the explorer process since it will have the user token

   // Find the explorer process

   PROCESSENTRY32 procEntry;

    HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    if (hSnap == INVALID_HANDLE_VALUE)
        return 1 ;

    procEntry.dwSize = sizeof(PROCESSENTRY32);

    if (!Process32First(hSnap, &procEntry))
        return 1 ;

        if (_stricmp(procEntry.szExeFile, "explorer.exe") == 0)
          DWORD dwExplorerSessId = 0;
          if (ProcessIdToSessionId(procEntry.th32ProcessID, &dwExplorerSessId) 
                    && dwExplorerSessId == dwSessionId)
                dwExplorerLogonPid = procEntry.th32ProcessID;

    } while (Process32Next(hSnap, &procEntry));

hProcess = OpenProcess(MAXIMUM_ALLOWED,FALSE,dwExplorerLogonPid);

               int abcd = GetLastError();
               printf("Process token open Error: %u\n",GetLastError());

We need to impersonate the service token to run as a user to access the Registry. This will cause our worker thread to run in the users token's context.

//Impersonate the explorer token which runs under the user account

int iImpersonateResult = GetLastError();

if(iImpersonateResult == ERROR_SUCCESS)
  //GetUserName will now return the username

 //Since the thread is running as the user we can access the HKCU now
  dwRegDataSize = sizeof(szRegData);
  lRegResult = RegOpenKeyEx(HKEY_CURRENT_USER,
  if (lRegResult == ERROR_SUCCESS)
//Once the operation is over revert back to system account.

I have taken a simple service posted by V.Anish to add my code to obtain the Winlogon's token and launch the application. It can be installed up typing service.exe -i. Then you need to start the service to get it running.

If you have any doubts, you can contact me at

In my next article, I will discuss some more concepts about tweaking the UAC.


This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


About the Author

Singapore Singapore
I graduated from Nanyang Technological University, Singapore in May 2004.Currently I am working as a Technical Consultant. I am also doing my Masters of Computing in IT project management from NUS, Singapore.My interests include reading technical articles,watching movies and traveling.My main areas of work include Project Management, Software Analysis and Design,Building Enterprise Applications using Microsoft .NET technologies,smart phone application development (Windows Mobile 5.0 and Blackberry) and System Programing on Windows Platform & WinCE

You may also be interested in...

Comments and Discussions

GeneralMy vote of 5 Pin
N3KK12-Apr-15 20:55
memberN3KK12-Apr-15 20:55 
GeneralGREAT!! Pin
willis_pear18-May-13 22:37
memberwillis_pear18-May-13 22:37 
QuestionHow to Run Pin
isaprgmr16-Oct-12 19:42
memberisaprgmr16-Oct-12 19:42 
GeneralMy vote of 5 Pin
xiejienet27-Jun-12 3:53
memberxiejienet27-Jun-12 3:53 
QuestionAccessing HKEY_CURRENT_USER fails with access denied Pin
Member 880775410-Apr-12 8:43
memberMember 880775410-Apr-12 8:43 
QuestionMerging custommessagesender and the worker thread Pin
Member 18894522-Apr-12 0:07
memberMember 18894522-Apr-12 0:07 
GeneralWhat for do you call WTSQueryUserToken? Pin
MadBuzz6-Jun-11 0:39
memberMadBuzz6-Jun-11 0:39 
GeneralNeed to give admin rights to session 1 exe so that this exe can create new files and registry. Pin
samikhan8427-May-11 0:22
membersamikhan8427-May-11 0:22 
GeneralMy vote for 5. Pin
spinoza18-Sep-10 1:12
memberspinoza18-Sep-10 1:12 
GeneralMy vote of 5 Pin
spinoza18-Sep-10 1:09
memberspinoza18-Sep-10 1:09 Pin
Member 6198038-Aug-10 18:39
memberMember 6198038-Aug-10 18:39 
GeneralService requires administrator Pin
vinodraut21-Apr-10 19:40
membervinodraut21-Apr-10 19:40 
GeneralAccess Denied Error!! Pin
TheBlackArrow12-Apr-10 6:15
memberTheBlackArrow12-Apr-10 6:15 
General"runas" ordinary user Pin
Elmue24-Feb-10 13:48
mvpElmue24-Feb-10 13:48 
GeneralDoes not work in Windows 7 Pin
ignac14-Jan-10 4:05
memberignac14-Jan-10 4:05 
GeneralRe: Does not work in Windows 7 Pin
Rythm7731-Jan-10 12:12
memberRythm7731-Jan-10 12:12 
does anyone know how to make it work in win7 64-bit?
GeneralRe: Does not work in Windows 7 Pin
Member 319183813-Jan-11 22:29
memberMember 319183813-Jan-11 22:29 
GeneralWTSQueryUserToken fails with ERROR_PRIVILEGE_NOT_HELD Pin
Ahamad Alisha20-Jul-09 1:23
memberAhamad Alisha20-Jul-09 1:23 
GeneralRe: WTSQueryUserToken fails with ERROR_PRIVILEGE_NOT_HELD Pin
ma-kai15-Sep-09 4:40
memberma-kai15-Sep-09 4:40 
QuestionHow can I do the same thing, but anyone user count? Pin
Member 426463823-Apr-09 19:45
memberMember 426463823-Apr-09 19:45 
GeneralThis is wonderful Pin
brunildo.st5-Feb-09 4:22
memberbrunildo.st5-Feb-09 4:22 
QuestionWhy explicitly enable SeDebugPrivilege? Pin
Don Schmitt22-Dec-08 12:43
memberDon Schmitt22-Dec-08 12:43 
AnswerRe: Why explicitly enable SeDebugPrivilege? Pin
ma-kai15-Sep-09 4:50
memberma-kai15-Sep-09 4:50 
Generalcode in C# Pin
Ariadne7-Dec-08 9:51
memberAriadne7-Dec-08 9:51 
QuestionWTSGetActiveConsoleSessionID identifier not found when i compile the a.cpp ? Pin
Shashank K Danej5-Dec-08 21:32
memberShashank K Danej5-Dec-08 21:32 
AnswerRe: WTSGetActiveConsoleSessionID identifier not found when i compile the a.cpp ? Pin
Garo16-Jun-09 0:19
memberGaro16-Jun-09 0:19 
GeneralImplementation failed on Microsoft Application verifier Pin
reimidap21-Oct-08 22:29
memberreimidap21-Oct-08 22:29 
NewsYeeahhh, brilliant! (+ delphi translation) [modified] Pin
Member 13723393-Oct-08 12:14
memberMember 13723393-Oct-08 12:14 
QuestionDo I have to be logged in as administrator? Pin
Khanh David To Tuan23-Jul-08 4:56
memberKhanh David To Tuan23-Jul-08 4:56 
AnswerRe: Do I have to be logged in as administrator? Pin
Jaisvar28-Jul-08 5:57
memberJaisvar28-Jul-08 5:57 
QuestionHow to run the Service under user account Pin
Member 352333523-Jul-08 0:36
memberMember 352333523-Jul-08 0:36 
GeneralProject testing failed Pin
Member 419070910-Jun-08 4:33
memberMember 419070910-Jun-08 4:33 
GeneralRe: Project testing failed Pin
Jaisvar13-Jun-08 19:55
memberJaisvar13-Jun-08 19:55 
GeneralRe: Project testing failed Pin
Dmitry Oleshko16-Jun-08 23:30
memberDmitry Oleshko16-Jun-08 23:30 
GeneralRe: Project testing failed Pin
Jaisvar17-Jun-08 1:15
memberJaisvar17-Jun-08 1:15 
GeneralRe: Project testing failed Pin
Dmitry Oleshko17-Jun-08 4:41
memberDmitry Oleshko17-Jun-08 4:41 
GeneralRe: Project testing failed Pin
Jaisvar17-Jun-08 4:55
memberJaisvar17-Jun-08 4:55 
GeneralRe: Project testing failed Pin
Dmitry Oleshko17-Jun-08 5:34
memberDmitry Oleshko17-Jun-08 5:34 
GeneralRe: Project testing failed Pin
Jaisvar17-Jun-08 21:56
memberJaisvar17-Jun-08 21:56 
GeneralRe: Project testing failed Pin
Dmitry Oleshko18-Jun-08 3:55
memberDmitry Oleshko18-Jun-08 3:55 
GeneralRe: Project testing failed Pin
Jaisvar18-Jun-08 5:34
memberJaisvar18-Jun-08 5:34 
GeneralAccessing to registry and filesystem with UAC on Pin
piermario21-May-08 5:10
memberpiermario21-May-08 5:10 
GeneralRe: Accessing to registry and filesystem with UAC on Pin
Jaisvar22-May-08 5:43
memberJaisvar22-May-08 5:43 
GeneralError installing service Pin
SMR10-May-08 1:09
memberSMR10-May-08 1:09 
GeneralRe: Error installing service Pin
anushreesongra12-May-08 23:18
memberanushreesongra12-May-08 23:18 
GeneralRe: Error installing service Pin
Dmitry Oleshko22-Jun-08 22:44
memberDmitry Oleshko22-Jun-08 22:44 
GeneralRe: Error installing service Pin
Keedom Hau20-Apr-09 6:31
memberKeedom Hau20-Apr-09 6:31 
GeneralThanks!!! Pin
Vaibhav Deshpande30-Apr-08 2:58
memberVaibhav Deshpande30-Apr-08 2:58 
GeneralRe: Thanks!!! Pin
Jaisvar17-Jun-08 4:57
memberJaisvar17-Jun-08 4:57 
QuestionCan you access HKLM without UAC popup? Pin
Member 44891825-Mar-08 1:21
memberMember 44891825-Mar-08 1:21 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web02 | 2.8.151002.1 | Last Updated 17 Apr 2007
Article Copyright 2007 by Jaisvar
Everything else Copyright © CodeProject, 1999-2015
Layout: fixed | fluid