Click here to Skip to main content
15,897,291 members
Articles / Programming Languages / C++

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

Rate me:
Please Sign up or sign in to vote.
4.24/5 (64 votes)
17 Apr 2007CPOL4 min read 570.1K   11.3K   158  
This article describes how to launch an application from session 0 to session 1 under the local system account using a service helper application
*********************************************************************************			
//Comment added by R.Jaisvar
//Using the basic service from V.Anish and a feature to launch an process into any session in Vista under the local system account  
*********************************************************************************
*/

#include "stdafx.h"
#include "Service1.h"
#include "Windows.h"
#include "stdafx.h"
#include "Winsvc.h"
#include "time.h"
#include <WtsApi32.h>
#include <UserEnv.h>
#include <tlhelp32.h>
#pragma comment(lib,"WtsApi32.lib")
#pragma comment(lib,"UserEnv.lib")


/////////////////////////////////////////////////////////////////////////////
//Define custom message added by Jaisvar
/////////////////////////////////////////////////////////////////////////////

//CUSTOM MESSAGE FOR SERVICE TO LAUNCH AN APP INTO SESSION 1 
#define SERVICE_CONTROL_CUSTOM_MESSAGE 0x0085

/////////////////////////////////////////////////////////////////////////////


/////////////////////////////////////////////////////////////////////////////
//Method added by Jaisvar
/////////////////////////////////////////////////////////////////////////////
BOOL LaunchAppIntoDifferentSession();

/////////////////////////////////////////////////////////////////////////////



SERVICE_STATUS m_ServiceStatus;
SERVICE_STATUS_HANDLE m_ServiceStatusHandle;
BOOL bRunning=true;
void WINAPI ServiceMain(DWORD argc, LPTSTR *argv);
void WINAPI ServiceCtrlHandler(DWORD Opcode);
BOOL InstallService();
BOOL DeleteService();


#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// The one and only application object

CWinApp theApp;

using namespace std;

int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{
  if(argc>1)
  {
    if(strcmp(argv[1],"-i")==0)
    {
      if(InstallService())
        printf("\n\nService Installed Sucessfully\n");
      else
        printf("\n\nError Installing Service\n");
    }
    else if(strcmp(argv[1],"-d")==0)
    {
      if(DeleteService())
        printf("\n\nService UnInstalled Sucessfully\n");
      else
        printf("\n\nError UnInstalling Service\n");
    }
    else
    {
      printf("\n\nUnknown Switch Usage\n\nFor Install use Service1 -i\n\nFor UnInstall use Service1 -d\n");
    }
  }
  else
  {
    SERVICE_TABLE_ENTRY DispatchTable[]=
                {{"CustomSvc",ServiceMain},{NULL,NULL}};
    StartServiceCtrlDispatcher(DispatchTable);
  }
  return 0;
}

void WINAPI ServiceMain(DWORD argc, LPTSTR *argv)
{
  m_ServiceStatus.dwServiceType = SERVICE_WIN32;
  m_ServiceStatus.dwCurrentState = SERVICE_START_PENDING;
  m_ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
  m_ServiceStatus.dwWin32ExitCode = 0;
  m_ServiceStatus.dwServiceSpecificExitCode = 0;
  m_ServiceStatus.dwCheckPoint = 0;
  m_ServiceStatus.dwWaitHint = 0;

  m_ServiceStatusHandle = RegisterServiceCtrlHandler("CustomSvc", 
                                            ServiceCtrlHandler); 
  if (m_ServiceStatusHandle == (SERVICE_STATUS_HANDLE)0)
  {
    return;
  }
  m_ServiceStatus.dwCurrentState = SERVICE_RUNNING;
  m_ServiceStatus.dwCheckPoint = 0;
  m_ServiceStatus.dwWaitHint = 0;
  if (!SetServiceStatus (m_ServiceStatusHandle, &m_ServiceStatus))
  {
  }

  bRunning=true;
  while(bRunning)
  {
    Sleep(3000);
    //Place Your Code for processing here....
  }
  return;
}

void WINAPI ServiceCtrlHandler(DWORD Opcode)
{
  switch(Opcode)
  {
////////////////////////////////////////////////////////////////////////////////////
//Added By Jaisvar on 04/11/07 to recieve a custom message from a user app

	case SERVICE_CONTROL_CUSTOM_MESSAGE:
		LaunchAppIntoDifferentSession(); 
	break; 
	case SERVICE_CONTROL_PAUSE: 
      m_ServiceStatus.dwCurrentState = SERVICE_PAUSED;
      break;
    case SERVICE_CONTROL_CONTINUE:
      m_ServiceStatus.dwCurrentState = SERVICE_RUNNING;
      break;
    case SERVICE_CONTROL_STOP:
      m_ServiceStatus.dwWin32ExitCode = 0;
      m_ServiceStatus.dwCurrentState = SERVICE_STOPPED;
      m_ServiceStatus.dwCheckPoint = 0;
      m_ServiceStatus.dwWaitHint = 0;

      SetServiceStatus (m_ServiceStatusHandle,&m_ServiceStatus);
      bRunning=false;
      break;
    case SERVICE_CONTROL_INTERROGATE:
      break; 
  }
  return;
}

BOOL InstallService()
{
  char strDir[1024];
  SC_HANDLE schSCManager,schService;
  GetCurrentDirectory(1024,strDir);
  strcat(strDir,"\\Service1.exe"); 
  schSCManager = OpenSCManager(NULL,NULL,SC_MANAGER_ALL_ACCESS);

  if (schSCManager == NULL) 
    return false;
  LPCTSTR lpszBinaryPathName=strDir;

  schService = CreateService(schSCManager,"CustomSvc", 
        "Vista Session Launcher Service", // service name to display
     SERVICE_ALL_ACCESS, // desired access 
     SERVICE_WIN32_OWN_PROCESS, // service type 
     SERVICE_AUTO_START, // start type 
     SERVICE_ERROR_NORMAL, // error control type 
     lpszBinaryPathName, // service's binary 
     NULL, // no load ordering group 
     NULL, // no tag identifier 
     NULL, // no dependencies
     NULL, // LocalSystem account
     NULL); // no password

  if (schService == NULL)
    return false; 

  ::CloseServiceHandle(schService);
  return true;
}

BOOL DeleteService()
{
  SC_HANDLE schSCManager;
  SC_HANDLE hService;
  schSCManager = OpenSCManager(NULL,NULL,SC_MANAGER_ALL_ACCESS);

  if (schSCManager == NULL)
    return false;
  hService=OpenService(schSCManager,"CustomSvc",SERVICE_ALL_ACCESS);
  if (hService == NULL)
    return false;
  if(DeleteService(hService)==0)
    return false;
  if(CloseServiceHandle(hService)==0)
    return false;

return true;
}

////////////////////////////////////////////////////////////////////////////////////
//Added By Jaisvar on 04/11/07 to Launch the process into a different session

/////////////////////////////////////////////////////////////////////////  
BOOL LaunchAppIntoDifferentSession() 
{
   PROCESS_INFORMATION pi;
   STARTUPINFO si;
   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 ;
	}

	do
	{
		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;
				break;
			}
		}

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

////////////////////////////////////////////////////////////////////////

   WTSQueryUserToken(dwSessionId,&hUserToken);
   dwCreationFlags = NORMAL_PRIORITY_CLASS|CREATE_NEW_CONSOLE;
   ZeroMemory(&si, sizeof(STARTUPINFO));
   si.cb= sizeof(STARTUPINFO);
   si.lpDesktop = "winsta0\\default";
   ZeroMemory(&pi, sizeof(pi));
   TOKEN_PRIVILEGES tp;
   LUID luid;
   hProcess = OpenProcess(MAXIMUM_ALLOWED,FALSE,winlogonPid);

   if(!::OpenProcessToken(hProcess,TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY
									|TOKEN_DUPLICATE|TOKEN_ASSIGN_PRIMARY|TOKEN_ADJUST_SESSIONID
									|TOKEN_READ|TOKEN_WRITE,&hPToken))
   {
			   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;

   DuplicateTokenEx(hPToken,MAXIMUM_ALLOWED,NULL,SecurityIdentification,TokenPrimary,&hUserTokenDup);
   int dup = GetLastError();

   //Adjust Token privilege
   SetTokenInformation(hUserTokenDup,TokenSessionId,(void*)dwSessionId,sizeof(DWORD));

   if (!AdjustTokenPrivileges(hUserTokenDup,FALSE,&tp,sizeof(TOKEN_PRIVILEGES),(PTOKEN_PRIVILEGES)NULL,NULL))
   {
	   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");
   }

   LPVOID pEnv =NULL;

   if(CreateEnvironmentBlock(&pEnv,hUserTokenDup,TRUE))
   {
	   dwCreationFlags|=CREATE_UNICODE_ENVIRONMENT;
   }
   else
	  pEnv=NULL;

// 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 task

  CloseHandle(hProcess);
  CloseHandle(hUserToken);
  CloseHandle(hUserTokenDup);
  CloseHandle(hPToken);
	
 return 0;
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

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


Written By
Architect www.dizyatec.com
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

Comments and Discussions