I wanted to make a windows service in c++ to start my programs as administrator every time the user log in without pop up UAC window As it's the first time for me to do it I used the project from here : https://code.msdn.microsoft.com/windowsapps/CppWindowsService-cacf4948/view/SourceCode
I edited line 74 in CppWindowsService.cpp to this :
InstallService(
SERVICE_NAME, // Name of service
SERVICE_DISPLAY_NAME, // Name to display
SERVICE_AUTO_START, // Service start type
SERVICE_DEPENDENCIES, // Dependencies
0, // Service running account
SERVICE_PASSWORD // Password of the account
);
and added some code to the worker thread in SampleService.cpp line 101 to become like this :
void CSampleService::ServiceWorkerThread(void)
{
// Periodically check if the service is stopping.
PSID gpSidMIL_High;
ConvertStringSidToSidW(L"S-1-16-12288", &gpSidMIL_High);
DWORD userSessionID = WTSGetActiveConsoleSessionId();
HANDLE hToken, hToken2;
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &hToken)) WriteEventLogEntry(L"OpenProcessToken failed error", EVENTLOG_ERROR_TYPE);
if (!DuplicateTokenEx(hToken, MAXIMUM_ALLOWED, NULL, SecurityIdentification, TokenPrimary, &hToken2)) WriteEventLogEntry(L"DuplicateTokenEx error", EVENTLOG_ERROR_TYPE);
if (!SetTokenInformation(hToken2, TokenSessionId, &userSessionID, sizeof(userSessionID))) WriteEventLogEntry(L"SetTokenInformation 1 error", EVENTLOG_ERROR_TYPE);
DWORD dwUIAccess = 1;
if (!SetTokenInformation(hToken2, TokenUIAccess, &dwUIAccess, sizeof(dwUIAccess))) WriteEventLogEntry(L"SetTokenInformation 2 error", EVENTLOG_ERROR_TYPE);
//Set "high" mandatory integrity level
TOKEN_MANDATORY_LABEL tml = { 0 };
tml.Label.Attributes = SE_GROUP_INTEGRITY;
tml.Label.Sid = gpSidMIL_High;
if (!SetTokenInformation(hToken2, TokenIntegrityLevel, &tml, sizeof(TOKEN_MANDATORY_LABEL) + ::GetSidLengthRequired(1))) WriteEventLogEntry(L"SetTokenInformation 3 error", EVENTLOG_ERROR_TYPE);
LPVOID pEnv = 0;
if (!CreateEnvironmentBlock(&pEnv, hToken2, FALSE)) WriteEventLogEntry(L"CreateEnvironmentBlock error", EVENTLOG_ERROR_TYPE);
if (!ImpersonateLoggedOnUser(hToken2)) WriteEventLogEntry(L"ImpersonateLoggedOnUser error", EVENTLOG_ERROR_TYPE);
while (!m_fStopping)
{
STARTUPINFO stinfo = { 0 };
PROCESS_INFORMATION pinfo = { 0 };
stinfo.cb = sizeof(stinfo);
stinfo.lpDesktop = L"winsta0\\default";
if (!CreateProcessAsUserW(hToken2, L"path to exe that shows a message box", 0, 0, 0, FALSE, CREATE_UNICODE_ENVIRONMENT|CREATE_BREAKAWAY_FROM_JOB, pEnv, L"cwd of the exe file", &stinfo, &pinfo))
{
// after debugging I found that the error is coming from here
std::wstring error = L"CreateProcessAsUserW failed with error : ";
error += std::to_wstring(GetLastError());
WriteEventLogEntry(wcsdup(error.c_str()), EVENTLOG_ERROR_TYPE);
Sleep(10000);
}
while (!m_fStopping && pinfo.hProcess)
{
if(WaitForSingleObject(pinfo.hProcess, 1000) != WAIT_TIMEOUT) break;
}
// ::Sleep(2000); // Simulate some lengthy operations.
}
The problem is that this service works very well after restarting windows or starting it manually through sc.exe or services control manager, but not after booting from previous shutdown When I shutdown then boot the computer I can see the exe of the service running in task manager so I knew that the service is running and there is an error comes from a function , I used the windows events and logged the errors and I finally found that the error comes from CreateProcessAsUser which return error 5 (Access denied) I don’t know where is the problem here as the service runs well after restart or upon starting it manually
ServiceMain is not called during fast startup. when fast startup is used,session 0 was(including kernel,drivers,all services) not terminated. It hibernated session 0 when you shutdown and continue run like hanging up VirtualMachine with user logout. So your service keeps status instead of starting again.
A simple way to handle this: handle SERVICE_ACCEPT_SESSIONCHANGE control code.
Here is an example.
these are the members of the class going to be initialized :
and in the protected methods I made this method :
and this is the function :
finally in the worker thread :