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