You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
527 lines
14 KiB
527 lines
14 KiB
/*
|
|
* Copyright 2002-2019 Intel Corporation.
|
|
*
|
|
* This software is provided to you as Sample Source Code as defined in the accompanying
|
|
* End User License Agreement for the Intel(R) Software Development Products ("Agreement")
|
|
* section 1.L.
|
|
*
|
|
* This software and the related documents are provided as is, with no express or implied
|
|
* warranties, other than those that are expressly stated in the License.
|
|
*/
|
|
|
|
#define UNICODE
|
|
#define _CRT_SECURE_NO_WARNINGS
|
|
#define _CRT_SECURE_NO_DEPRECATE
|
|
|
|
#include <Windows.h>
|
|
#include <Winsvc.h>
|
|
#include <string>
|
|
#include <iostream>
|
|
#include <fstream>
|
|
|
|
using std::string;
|
|
using std::endl;
|
|
using std::cout;
|
|
using std::wstring;
|
|
using std::ofstream;
|
|
using std::cerr;
|
|
|
|
static wchar_t * ServiceNameW = L"ServiceAppForPinTesting";
|
|
static wchar_t * ServiceDisplayNameW = L"Service App For Pin Testing";
|
|
static wchar_t * BinaryNameW = L"w_service_app1.exe";
|
|
|
|
// perform administrative actions, this class is used
|
|
// when the process runs as regular process (not as service)
|
|
class SERVICE_ADMIN
|
|
{
|
|
public:
|
|
static void Main(int argc, wchar_t * argv[]);
|
|
|
|
private:
|
|
BOOL Create();
|
|
BOOL Delete();
|
|
DWORD Start(DWORD argc, LPCTSTR * argv);
|
|
BOOL Stop();
|
|
|
|
VOID Usage();
|
|
};
|
|
|
|
// class to be used when the process runs as service
|
|
class SERVICE_MANAGER
|
|
{
|
|
public:
|
|
static void WINAPI Main(DWORD argc, LPTSTR * argv);
|
|
static void WINAPI ControlHandler(DWORD opcode);
|
|
static void StartServiceTimer(DWORD milliSec);
|
|
static void StopService(); //never returns
|
|
static void OpenFile();
|
|
|
|
private:
|
|
static DWORD WINAPI ServiceTimerProc(VOID * p);
|
|
static void LaunchProcess(wstring cmdLine);
|
|
|
|
static SERVICE_STATUS status;
|
|
static SERVICE_STATUS_HANDLE statusHandle;
|
|
static ofstream outFile;
|
|
};
|
|
|
|
SERVICE_STATUS SERVICE_MANAGER::status;
|
|
SERVICE_STATUS_HANDLE SERVICE_MANAGER::statusHandle;
|
|
ofstream SERVICE_MANAGER::outFile;
|
|
|
|
// main function
|
|
|
|
int wmain(int argc, wchar_t * argv[])
|
|
{
|
|
if((argc >= 2) && ((wcscmp(argv[1], L"-admin") == 0) || (wcscmp(argv[1], L"-help") == 0)))
|
|
{
|
|
SERVICE_ADMIN::Main(argc, argv);
|
|
}
|
|
else
|
|
{
|
|
SERVICE_MANAGER::OpenFile();
|
|
SERVICE_TABLE_ENTRY dispatchData[]={{ServiceNameW, SERVICE_MANAGER::Main},{NULL, NULL}};
|
|
StartServiceCtrlDispatcher(dispatchData);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
//manager impl
|
|
|
|
void SERVICE_MANAGER::LaunchProcess(wstring cmdLine)
|
|
{
|
|
STARTUPINFO si;
|
|
PROCESS_INFORMATION pi;
|
|
|
|
memset(&si, 0, sizeof(si));
|
|
si.cb = sizeof(STARTUPINFO);
|
|
memset(&pi, 0, sizeof(pi));
|
|
|
|
if (!CreateProcess(NULL, (LPWSTR)cmdLine.c_str(), NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi))
|
|
{
|
|
outFile << "Failed to CreateProcess, " << GetLastError() << endl;
|
|
}
|
|
return;
|
|
}
|
|
|
|
__declspec(dllexport) int DoLoop()
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
__declspec(dllexport) void ShortFunction1(DWORD h)
|
|
{
|
|
volatile DWORD i = h;
|
|
Sleep(1);
|
|
if(i != 1)
|
|
{
|
|
exit(-1);
|
|
}
|
|
}
|
|
|
|
__declspec(dllexport) void ShortFunction2(DWORD h)
|
|
{
|
|
volatile DWORD i = h;
|
|
Sleep(1);
|
|
if(i != 2)
|
|
{
|
|
exit(-1);
|
|
}
|
|
}
|
|
|
|
void WINAPI SERVICE_MANAGER::Main(DWORD argc, LPTSTR *argv)
|
|
{
|
|
status.dwServiceType = SERVICE_WIN32;
|
|
status.dwCurrentState = SERVICE_START_PENDING;
|
|
status.dwControlsAccepted = SERVICE_ACCEPT_STOP;
|
|
status.dwWin32ExitCode = 0;
|
|
status.dwServiceSpecificExitCode = 0;
|
|
status.dwCheckPoint = 0;
|
|
status.dwWaitHint = 0;
|
|
|
|
statusHandle = RegisterServiceCtrlHandler(ServiceNameW, SERVICE_MANAGER::ControlHandler);
|
|
if (statusHandle == (SERVICE_STATUS_HANDLE)NULL)
|
|
{
|
|
outFile << "Failed to RegisterServiceCtrlHandler, " << GetLastError() << endl;
|
|
return;
|
|
}
|
|
|
|
status.dwCurrentState = SERVICE_RUNNING;
|
|
status.dwCheckPoint = 0;
|
|
status.dwWaitHint = 0;
|
|
|
|
if (!SetServiceStatus (statusHandle, &status))
|
|
{
|
|
outFile << "Failed to SetServiceStatus, " << GetLastError() << endl;
|
|
return;
|
|
}
|
|
|
|
//Will stop the service after 300 sec.
|
|
StartServiceTimer(300*1000);
|
|
|
|
while(DoLoop())
|
|
{
|
|
ShortFunction1(1);
|
|
ShortFunction2(2);
|
|
|
|
static int i = 0;
|
|
i++;
|
|
i = i % 0x10;
|
|
LPVOID aaa = VirtualAlloc(0, i * 0x1000000, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
|
|
VirtualFree(aaa, 0, MEM_RELEASE);
|
|
}
|
|
|
|
outFile << "Success! someone changed DoLoop on time" << endl;
|
|
outFile.flush();
|
|
StopService();
|
|
return;
|
|
}
|
|
|
|
void WINAPI SERVICE_MANAGER::ControlHandler(DWORD opcode)
|
|
{
|
|
switch(opcode)
|
|
{
|
|
case SERVICE_CONTROL_PAUSE:
|
|
status.dwCurrentState = SERVICE_PAUSED;
|
|
break;
|
|
case SERVICE_CONTROL_CONTINUE:
|
|
status.dwCurrentState = SERVICE_RUNNING;
|
|
break;
|
|
case SERVICE_CONTROL_STOP:
|
|
status.dwWin32ExitCode = 0;
|
|
status.dwCurrentState = SERVICE_STOPPED;
|
|
status.dwCheckPoint = 0;
|
|
status.dwWaitHint = 0;
|
|
outFile.flush();
|
|
outFile.close();
|
|
SetServiceStatus (statusHandle,&status);
|
|
break;
|
|
case SERVICE_CONTROL_INTERROGATE:
|
|
break;
|
|
}
|
|
return;
|
|
}
|
|
|
|
DWORD WINAPI SERVICE_MANAGER::ServiceTimerProc(VOID * p)
|
|
{
|
|
DWORD * pMilliSec = (DWORD *)p;
|
|
Sleep(*pMilliSec);
|
|
delete pMilliSec;
|
|
//never returns
|
|
outFile << "Failure! DoLoop was not changed on time" << endl;
|
|
SERVICE_MANAGER::StopService();
|
|
return 0;
|
|
}
|
|
|
|
void SERVICE_MANAGER::StartServiceTimer(DWORD milliSec)
|
|
{
|
|
DWORD * pMilliSec = new DWORD(milliSec);
|
|
HANDLE threadHandle = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ServiceTimerProc, pMilliSec, 0, NULL);
|
|
if(threadHandle == NULL)
|
|
{
|
|
outFile << "Failed to CreateThread, " << GetLastError() << endl;
|
|
}
|
|
return;
|
|
}
|
|
|
|
void SERVICE_MANAGER::StopService()
|
|
{
|
|
wchar_t binPathArr[2048];
|
|
GetModuleFileName(NULL, binPathArr, 2048);
|
|
LPCTSTR binPath = binPathArr;
|
|
wstring cmdLine = wstring(L"\"") + binPath + L"\"";
|
|
cmdLine += L" -admin -stop";
|
|
LaunchProcess(cmdLine);
|
|
}
|
|
|
|
void SERVICE_MANAGER::OpenFile()
|
|
{
|
|
wchar_t binPathArr[2048];
|
|
GetModuleFileName(NULL, binPathArr, 2048);
|
|
|
|
size_t serviceExeNameLen = wcslen(BinaryNameW);
|
|
size_t servicePathNameLen = wcslen(binPathArr) - serviceExeNameLen;
|
|
binPathArr[servicePathNameLen] = L'\0';
|
|
|
|
SetCurrentDirectory(binPathArr);
|
|
|
|
wstring fileName = binPathArr;
|
|
fileName += BinaryNameW;
|
|
fileName += L".service.log";
|
|
outFile.open(fileName.c_str());
|
|
}
|
|
|
|
|
|
//admin impl
|
|
|
|
void SERVICE_ADMIN::Main(int argc, wchar_t * argv[])
|
|
{
|
|
SERVICE_ADMIN admin;
|
|
|
|
if((argc == 1) ||
|
|
((argc == 2) && ((wcscmp(argv[1], L"-admin") == 0) || (wcscmp(argv[1], L"-help") == 0))))
|
|
{
|
|
return admin.Usage();
|
|
}
|
|
|
|
if(wcscmp(argv[2], L"-create") == 0)
|
|
{
|
|
if(admin.Create())
|
|
{
|
|
cerr << "Created service sucessfully!" << endl;
|
|
}
|
|
else
|
|
{
|
|
cerr << "Failed to Create service" << endl;
|
|
}
|
|
}
|
|
else if (wcscmp(argv[2], L"-start") == 0)
|
|
{
|
|
DWORD pid = admin.Start((DWORD)(argc - 3), (LPCWSTR *)&argv[3]);
|
|
if(pid != 0)
|
|
{
|
|
cerr << "Started service sucessfully!" << endl;
|
|
}
|
|
else
|
|
{
|
|
cerr << "Failed to start service" << endl;
|
|
}
|
|
|
|
char digitBuffer[64];
|
|
cout << _itoa(pid, digitBuffer, 10);
|
|
}
|
|
else if (wcscmp(argv[2],L"-stop") == 0)
|
|
{
|
|
if(admin.Stop())
|
|
{
|
|
cerr << "Stopped service sucessfully!" << endl;
|
|
}
|
|
else
|
|
{
|
|
cerr << "Failed to stop service" << endl;
|
|
}
|
|
}
|
|
else if (wcscmp(argv[2],L"-delete") == 0)
|
|
{
|
|
if(admin.Delete())
|
|
{
|
|
cerr << "Deleted service sucessfully!" << endl;
|
|
}
|
|
else
|
|
{
|
|
cerr << "Failed to delete service" << endl;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
admin.Usage();
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
BOOL SERVICE_ADMIN::Create()
|
|
{
|
|
SC_HANDLE manager;
|
|
manager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
|
|
if (manager == NULL)
|
|
{
|
|
cerr << "Failed to OpenSCManager, " << GetLastError() << endl;
|
|
return false;
|
|
}
|
|
|
|
wchar_t binPathArr[2048];
|
|
GetModuleFileName(NULL, binPathArr, 2048);
|
|
wstring path = binPathArr;
|
|
path = L"\"" + path + L"\"";
|
|
|
|
#if 0 // This code is intended for symbolic link substitution
|
|
size_t slashLocation = path.find(L"\\");
|
|
wstring drive = path.substr(0, slashLocation);
|
|
path = path.substr(slashLocation);
|
|
|
|
wchar_t targetPath[2048];
|
|
QueryDosDevice(drive.c_str(), targetPath, 2048);
|
|
path = wstring(targetPath) + path;
|
|
if(path.find(L"\\??\\") == 0)
|
|
{
|
|
/* Remove \??\ */
|
|
path = path.substr(4);
|
|
}
|
|
else if(path.find(L"\\DosDevices\\") == 0)
|
|
{
|
|
/* Remove \DosDevices\ */
|
|
path = path.substr(12);
|
|
}
|
|
#endif
|
|
|
|
LPCTSTR binPath = path.c_str();
|
|
|
|
SC_HANDLE service;
|
|
service = CreateService(manager,
|
|
ServiceNameW,
|
|
ServiceDisplayNameW,
|
|
SERVICE_ALL_ACCESS,
|
|
SERVICE_WIN32_OWN_PROCESS,
|
|
SERVICE_DEMAND_START,
|
|
SERVICE_ERROR_NORMAL,
|
|
binPath,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL, // log on as Local System, other options L"NT AUTHORITY\\LocalService" L"NT AUTHORITY\\NetworkService"
|
|
NULL); // no password
|
|
if (service == NULL && (GetLastError() != ERROR_SERVICE_EXISTS))
|
|
{
|
|
cerr << "Failed to CreateService, " << GetLastError() << endl;
|
|
CloseServiceHandle(manager);
|
|
return false;
|
|
}
|
|
|
|
if(manager != NULL) {CloseServiceHandle(manager);}
|
|
if(service != NULL) {CloseServiceHandle(service);}
|
|
return true;
|
|
}
|
|
|
|
DWORD SERVICE_ADMIN::Start(DWORD argc, LPCWSTR * argv)
|
|
{
|
|
SC_HANDLE manager;
|
|
manager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
|
|
if (manager == NULL)
|
|
{
|
|
cerr << "Failed to OpenSCManager, " << GetLastError() << endl;
|
|
return 0;
|
|
}
|
|
|
|
SC_HANDLE service;
|
|
service = OpenService(manager, ServiceNameW, SERVICE_ALL_ACCESS);
|
|
if (service == NULL)
|
|
{
|
|
cerr << "Failed to OpenService, " << GetLastError() << endl;
|
|
CloseServiceHandle(manager);
|
|
return 0;
|
|
}
|
|
|
|
if(!StartService(service, argc, argv))
|
|
{
|
|
cerr << "Failed to StartService, " << GetLastError() << endl;
|
|
CloseServiceHandle(manager);
|
|
CloseServiceHandle(service);
|
|
return 0;
|
|
}
|
|
|
|
//maximum 8k
|
|
SERVICE_STATUS_PROCESS * pServiceStatusProcess = (SERVICE_STATUS_PROCESS *)malloc(0x2000);
|
|
pServiceStatusProcess->dwCurrentState = SERVICE_START_PENDING;
|
|
|
|
int timer = 60;
|
|
while((timer != 0) && (pServiceStatusProcess->dwCurrentState != SERVICE_RUNNING))
|
|
{
|
|
timer--;
|
|
DWORD bytesNeeded = 0;
|
|
if(!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO, (LPBYTE)pServiceStatusProcess, 0x2000, &bytesNeeded))
|
|
{
|
|
cout << "Failed to QueryServiceStatusEx, " << GetLastError() << endl;
|
|
CloseServiceHandle(manager);
|
|
CloseServiceHandle(service);
|
|
free(pServiceStatusProcess);
|
|
return 0;
|
|
}
|
|
//Let the service start
|
|
Sleep(1000);
|
|
}
|
|
|
|
if(pServiceStatusProcess->dwCurrentState != SERVICE_RUNNING)
|
|
{
|
|
cerr << "Failed, Service haven't started after 60 seconds" << endl;
|
|
CloseServiceHandle(manager);
|
|
CloseServiceHandle(service);
|
|
free(pServiceStatusProcess);
|
|
return 0;
|
|
}
|
|
|
|
|
|
CloseServiceHandle(manager);
|
|
CloseServiceHandle(service);
|
|
|
|
DWORD pid = pServiceStatusProcess->dwProcessId;
|
|
free(pServiceStatusProcess);
|
|
return pid;
|
|
}
|
|
|
|
|
|
BOOL SERVICE_ADMIN::Stop()
|
|
{
|
|
SC_HANDLE manager;
|
|
manager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
|
|
if (manager == NULL)
|
|
{
|
|
cerr << "Failed to OpenSCManager, " << GetLastError() << endl;
|
|
return false;
|
|
}
|
|
|
|
SC_HANDLE service;
|
|
service = OpenService(manager, ServiceNameW, SERVICE_ALL_ACCESS);
|
|
if (service == NULL)
|
|
{
|
|
cerr << "Failed to OpenService, " << GetLastError() << endl;
|
|
CloseServiceHandle(manager);
|
|
return false;
|
|
}
|
|
|
|
SERVICE_STATUS status;
|
|
BOOL res = ControlService(service, SERVICE_CONTROL_STOP, &status);
|
|
if(!res && (GetLastError() != ERROR_SERVICE_NOT_ACTIVE))
|
|
{
|
|
cerr << "Failed to ControlService, " << GetLastError() << endl;
|
|
CloseServiceHandle(manager);
|
|
CloseServiceHandle(service);
|
|
return false;
|
|
}
|
|
|
|
CloseServiceHandle(manager);
|
|
CloseServiceHandle(service);
|
|
return true;
|
|
}
|
|
|
|
BOOL SERVICE_ADMIN::Delete()
|
|
{
|
|
SC_HANDLE manager;
|
|
manager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
|
|
if (manager == NULL)
|
|
{
|
|
cout << "Failed to OpenSCManager, " << GetLastError() << endl;
|
|
return false;
|
|
}
|
|
|
|
SC_HANDLE service;
|
|
service = OpenService(manager, ServiceNameW, SERVICE_ALL_ACCESS);
|
|
if (service == NULL)
|
|
{
|
|
cerr << "Failed to OpenService, " << GetLastError() << endl;
|
|
CloseServiceHandle(manager);
|
|
return false;
|
|
}
|
|
|
|
if(!DeleteService(service))
|
|
{
|
|
cerr << "Failed to DeleteService, " << GetLastError() << endl;
|
|
CloseServiceHandle(manager);
|
|
CloseServiceHandle(service);
|
|
return false;
|
|
}
|
|
|
|
CloseServiceHandle(manager);
|
|
CloseServiceHandle(service);
|
|
return true;
|
|
}
|
|
|
|
void SERVICE_ADMIN::Usage()
|
|
{
|
|
cerr << "Usage:" << endl;
|
|
cerr << "To create the service: -admin -create" << endl;
|
|
cerr << "To start the service: -admin -start <service arguments>" << endl;
|
|
cerr << "To start the service: -admin -stop" << endl;
|
|
cerr << "To delete the service: -admin -delete" << endl;
|
|
}
|