Service Executable Template Code
To avoid any issues with runtime libraries that may not be installed on the host (such as vcruntime), consider static linking. If code is compiled using Microsoft Visual Studio, navigate to project properties and then Configuration Properties -> C/C++ -> Code Generation
and select Multi-threaded (/MT)
.
#include <windows.h>
#include <stdio.h>
#include <winsvc.h>
#define SERVICE_NAME L"" // service name
SERVICE_STATUS ServiceStatus;
SERVICE_STATUS_HANDLE hStatus;
HANDLE hStopEvent = NULL;
// debug purposes
int LogWrite(LPCWSTR data)
{
HANDLE hFile = CreateFileW(
L"", // path
FILE_APPEND_DATA,
0,
NULL,
OPEN_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL
);
if (hFile == INVALID_HANDLE_VALUE)
{
return 1;
}
DWORD written;
WriteFile(hFile, data, wcslen(data) * sizeof(WCHAR), &written, NULL);
CloseHandle(hFile);
return 0;
}
VOID ChangeServiceStatus(DWORD dwCurrentState, DWORD dwWin32ExitCode, DWORD dwWaitHint)
{
/*
DWORD dwServiceType;
DWORD dwCurrentState;
DWORD dwControlsAccepted;
DWORD dwWin32ExitCode;
DWORD dwServiceSpecificExitCode;
DWORD dwCheckPoint;
DWORD dwWaitHint;
*/
static DWORD dwCheckPoint = 1;
ServiceStatus.dwCurrentState = dwCurrentState;
ServiceStatus.dwWin32ExitCode = dwWin32ExitCode;
ServiceStatus.dwWaitHint = dwWaitHint;
if (dwCurrentState == SERVICE_START_PENDING)
ServiceStatus.dwControlsAccepted = 0;
else ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
if ((dwCurrentState == SERVICE_RUNNING) ||
(dwCurrentState == SERVICE_STOPPED))
ServiceStatus.dwCheckPoint = 0;
else ServiceStatus.dwCheckPoint = dwCheckPoint++;
SetServiceStatus(hStatus, &ServiceStatus);
LogWrite(L"[*] Service status change\n");
}
void WINAPI ServiceCtrlHandler(DWORD ctrlCode) {
LogWrite(L"[*] In ServiceCtrlHandler\n");
switch (ctrlCode)
{
case SERVICE_CONTROL_STOP:
ServiceStatus.dwCurrentState = SERVICE_STOP_PENDING;
ChangeServiceStatus(ServiceStatus.dwCurrentState, NO_ERROR, 3000);
LogWrite(L"[!] Service stopped by control request\n");
ServiceStatus.dwCurrentState = SERVICE_STOPPED;
ChangeServiceStatus(ServiceStatus.dwCurrentState, NO_ERROR, 0);
break;
default:
break;
}
}
int WINAPI InitService(DWORD argc, LPTSTR* argv)
{
hStopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (hStopEvent == NULL)
{
ChangeServiceStatus(SERVICE_STOPPED, GetLastError(), 0);
return 1;
}
// Report running status when initialization is complete.
ChangeServiceStatus(SERVICE_RUNNING, NO_ERROR, 0);
// custom functionality
while (1)
{
WaitForSingleObject(hStopEvent, INFINITE);
ChangeServiceStatus(SERVICE_STOPPED, NO_ERROR, 0);
return 0;
}
return 0;
}
int WINAPI ServiceMain(DWORD argc, LPWSTR* argv)
{
// debug
LogWrite(L"[+] In ServiceMain\n");
hStatus = RegisterServiceCtrlHandler(SERVICE_NAME, ServiceCtrlHandler);
if (hStatus == NULL)
{
ServiceStatus.dwCurrentState = SERVICE_STOPPED;
ChangeServiceStatus(ServiceStatus.dwCurrentState, NO_ERROR, 0);
LogWrite(L"[-] RegisterServiceCtrlHandler failed\n");
return 1;
}
ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
ServiceStatus.dwServiceSpecificExitCode = NO_ERROR;
LogWrite(L"[*] Service is starting...\n");
ServiceStatus.dwCurrentState = SERVICE_START_PENDING;
ChangeServiceStatus(ServiceStatus.dwCurrentState, NO_ERROR, 3000);
InitService(argc, argv);
}
// main runs regardless of service structures
int main(int argc, CHAR* argv[])
{
SERVICE_TABLE_ENTRYW ServiceTable[] = {
(LPWSTR)SERVICE_NAME,
(LPSERVICE_MAIN_FUNCTION)ServiceMain
};
if (!StartServiceCtrlDispatcher(ServiceTable)) {
LogWrite(L"[-] StartServiceCtrlDispatcher failed\n");
}
return 0;
}
References
[1] https://learn.microsoft.com/en-us/windows/win32/services/writing-a-service-program-s-main-function
[2] https://learn.microsoft.com/en-us/windows/win32/services/writing-a-servicemain-function
[3] https://learn.microsoft.com/en-us/windows/win32/services/writing-a-control-handler-function
tags: #Windows API