在Windows下,创建服务EXE需要特殊格式,这里分享记录一下,方便后面复制调试。
服务约定格式
一个最小的服务至少需要三个函数:
- A Main Entry point (like any application),StartServiceCtrlDispatcher启动一个服务的线程,用ServiceTable维护一个类似的结构,提供关于这个服务的详细信息
int main(int argc, TCHAR* argv[])
{
SERVICE_TABLE_ENTRY ServiceTable[] =
{
{ const_cast<LPWSTR>(SERVICE_NAME), (LPSERVICE_MAIN_FUNCTION)ServiceMain },
{ NULL, NULL }
};
if (StartServiceCtrlDispatcher(ServiceTable) == FALSE)
{
DWORD dwError = GetLastError();
std::cerr << "StartServiceCtrlDispatcher error: " << dwError << std::endl;
return dwError;
}
return 0;
}
- A Service Entry point 服务入口,不难看出服务实际上是可以接受参数的
VOID WINAPI ServiceMain(DWORD argc, LPTSTR* argv)
{
//注册服务
g_StatusHandle = RegisterServiceCtrlHandler(SERVICE_NAME, ServiceCtrlHandler);
if (g_StatusHandle == NULL)
{
exit(GetLastError());
}
ZeroMemory(&g_ServiceStatus, sizeof(g_ServiceStatus));
g_ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
g_ServiceStatus.dwControlsAccepted = 0;
g_ServiceStatus.dwCurrentState = SERVICE_START_PENDING;
g_ServiceStatus.dwWin32ExitCode = 0;
g_ServiceStatus.dwServiceSpecificExitCode = 0;
g_ServiceStatus.dwCheckPoint = 0;
//设置服务状态,目前是SERVICE_START_PENDING
if (SetServiceStatus(g_StatusHandle, &g_ServiceStatus) == FALSE)
{
OutputDebugStringW(L"My Sample Service: ServiceMain: SetServiceStatus returned error");
}
g_ServiceStopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
//如果事件创建失败,就直接退出程序
if (g_ServiceStopEvent == NULL)
{
g_ServiceStatus.dwControlsAccepted = 0;
g_ServiceStatus.dwCurrentState = SERVICE_STOPPED;
g_ServiceStatus.dwWin32ExitCode = GetLastError();
g_ServiceStatus.dwCheckPoint = 1;
if (SetServiceStatus(g_StatusHandle, &g_ServiceStatus) == FALSE)
{
OutputDebugStringW(L"My Sample Service: ServiceMain: SetServiceStatus returned error");
}
exit(0);
}
g_ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
g_ServiceStatus.dwCurrentState = SERVICE_RUNNING;
g_ServiceStatus.dwWin32ExitCode = 0;
g_ServiceStatus.dwCheckPoint = 0;
//事件成功的话,就代表服务正在运行了
if (SetServiceStatus(g_StatusHandle, &g_ServiceStatus) == FALSE)
{
OutputDebugStringW(L"My Sample Service: ServiceMain: SetServiceStatus returned error");
}
//创建一个线程,等待这个线程完成,ServiceWorkerThread函数写我们的恶意代码
HANDLE hThread = CreateThread(NULL, 0, ServiceWorkerThread, NULL, 0, NULL);
WaitForSingleObject(hThread, INFINITE);
CloseHandle(g_ServiceStopEvent);
g_ServiceStatus.dwControlsAccepted = 0;
g_ServiceStatus.dwCurrentState = SERVICE_STOPPED;
g_ServiceStatus.dwWin32ExitCode = 0;
g_ServiceStatus.dwCheckPoint = 3;
if (SetServiceStatus(g_StatusHandle, &g_ServiceStatus) == FALSE)
{
OutputDebugStringW(L"My Sample Service: ServiceMain: SetServiceStatus returned error");
}
EXIT:
return;
}
- A Service Control Handler 服务控制器,根据CtrlCode来接受SCM的控制请求,一旦CtrlCode等于SERVICE_CONTROL_STOP,就调用SetServiceStatus API设置服务状态为SERVICE_STOP_PENDING
VOID WINAPI ServiceCtrlHandler(DWORD CtrlCode)
{
switch (CtrlCode)
{
case SERVICE_CONTROL_STOP:
if (g_ServiceStatus.dwCurrentState != SERVICE_RUNNING)
break;
g_ServiceStatus.dwControlsAccepted = 0;
g_ServiceStatus.dwCurrentState = SERVICE_STOP_PENDING;
g_ServiceStatus.dwWin32ExitCode = 0;
g_ServiceStatus.dwCheckPoint = 4;
if (SetServiceStatus(g_StatusHandle, &g_ServiceStatus) == FALSE)
{
OutputDebugStringW(L"My Sample Service: ServiceCtrlHandler: SetServiceStatus returned error");
}
SetEvent(g_ServiceStopEvent);
break;
default:
break;
}
}
测试代码
#include <windows.h>
#include <string>
#include <iostream>
SERVICE_STATUS g_ServiceStatus = { 0 };
SERVICE_STATUS_HANDLE g_StatusHandle = NULL;
HANDLE g_ServiceStopEvent = INVALID_HANDLE_VALUE;
VOID WINAPI ServiceMain(DWORD argc, LPTSTR* argv);
VOID WINAPI ServiceCtrlHandler(DWORD);
DWORD WINAPI ServiceWorkerThread(LPVOID lpParam);
const wchar_t SERVICE_NAME[] = L"My Sample Service";
bool CreateAndWriteFile(const std::wstring& filePath, const std::string& data);
int main(int argc, TCHAR* argv[])
{
SERVICE_TABLE_ENTRY ServiceTable[] =
{
{ const_cast<LPWSTR>(SERVICE_NAME), (LPSERVICE_MAIN_FUNCTION)ServiceMain },
{ NULL, NULL }
};
if (StartServiceCtrlDispatcher(ServiceTable) == FALSE)
{
DWORD dwError = GetLastError();
std::cerr << "StartServiceCtrlDispatcher error: " << dwError << std::endl;
return dwError;
}
return 0;
}
VOID WINAPI ServiceMain(DWORD argc, LPTSTR* argv)
{
g_StatusHandle = RegisterServiceCtrlHandler(SERVICE_NAME, ServiceCtrlHandler);
if (g_StatusHandle == NULL)
{
exit(GetLastError());
}
ZeroMemory(&g_ServiceStatus, sizeof(g_ServiceStatus));
g_ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
g_ServiceStatus.dwControlsAccepted = 0;
g_ServiceStatus.dwCurrentState = SERVICE_START_PENDING;
g_ServiceStatus.dwWin32ExitCode = 0;
g_ServiceStatus.dwServiceSpecificExitCode = 0;
g_ServiceStatus.dwCheckPoint = 0;
if (SetServiceStatus(g_StatusHandle, &g_ServiceStatus) == FALSE)
{
OutputDebugStringW(L"My Sample Service: ServiceMain: SetServiceStatus returned error");
}
g_ServiceStopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (g_ServiceStopEvent == NULL)
{
g_ServiceStatus.dwControlsAccepted = 0;
g_ServiceStatus.dwCurrentState = SERVICE_STOPPED;
g_ServiceStatus.dwWin32ExitCode = GetLastError();
g_ServiceStatus.dwCheckPoint = 1;
if (SetServiceStatus(g_StatusHandle, &g_ServiceStatus) == FALSE)
{
OutputDebugStringW(L"My Sample Service: ServiceMain: SetServiceStatus returned error");
}
exit(0);
}
g_ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
g_ServiceStatus.dwCurrentState = SERVICE_RUNNING;
g_ServiceStatus.dwWin32ExitCode = 0;
g_ServiceStatus.dwCheckPoint = 0;
if (SetServiceStatus(g_StatusHandle, &g_ServiceStatus) == FALSE)
{
OutputDebugStringW(L"My Sample Service: ServiceMain: SetServiceStatus returned error");
}
HANDLE hThread = CreateThread(NULL, 0, ServiceWorkerThread, NULL, 0, NULL);
WaitForSingleObject(hThread, INFINITE);
CloseHandle(g_ServiceStopEvent);
g_ServiceStatus.dwControlsAccepted = 0;
g_ServiceStatus.dwCurrentState = SERVICE_STOPPED;
g_ServiceStatus.dwWin32ExitCode = 0;
g_ServiceStatus.dwCheckPoint = 3;
if (SetServiceStatus(g_StatusHandle, &g_ServiceStatus) == FALSE)
{
OutputDebugStringW(L"My Sample Service: ServiceMain: SetServiceStatus returned error");
}
EXIT:
return;
}
VOID WINAPI ServiceCtrlHandler(DWORD CtrlCode)
{
switch (CtrlCode)
{
case SERVICE_CONTROL_STOP:
if (g_ServiceStatus.dwCurrentState != SERVICE_RUNNING)
break;
g_ServiceStatus.dwControlsAccepted = 0;
g_ServiceStatus.dwCurrentState = SERVICE_STOP_PENDING;
g_ServiceStatus.dwWin32ExitCode = 0;
g_ServiceStatus.dwCheckPoint = 4;
if (SetServiceStatus(g_StatusHandle, &g_ServiceStatus) == FALSE)
{
OutputDebugStringW(L"My Sample Service: ServiceCtrlHandler: SetServiceStatus returned error");
}
SetEvent(g_ServiceStopEvent);
break;
default:
break;
}
}
bool CreateAndWriteFile(const std::wstring& filePath, const std::string& data) {
HANDLE hFile = CreateFile(
filePath.c_str(),
GENERIC_WRITE,
0,
NULL,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL
);
if (hFile == INVALID_HANDLE_VALUE) {
return false;
}
DWORD bytesWritten;
if (!WriteFile(hFile, data.c_str(), data.size(), &bytesWritten, NULL)) {
CloseHandle(hFile);
return false;
}
CloseHandle(hFile);
return true;
}
DWORD WINAPI ServiceWorkerThread(LPVOID lpParam)
{
std::wstring filePath = L"1.txt";
std::string data = "111";
//使用相对路径,保存在C:\Windows\System32目录下,推荐使用temp目录
//C:\\Windows\\Temp\\1.txt,测试是否工作,重启之后不知道还有没有,得测试分析一下
if (CreateAndWriteFile(filePath, data)) {
}
else {
}
while (WaitForSingleObject(g_ServiceStopEvent, 0) != WAIT_OBJECT_0)
{
Sleep(3000);
}
return ERROR_SUCCESS;
}
链接到静态库
编译服务需要链接 Kernel32.lib and Advapi32.lib 否则无法找到外部解析
位置在这里:
编译运行
创建服务,并开启开机启动:
sc create "endlessparadox" binPath= C:\SampleService.exe start= auto
“Specifies a service that automatically starts each time the computer is restarted and runs even if no one logs on to the computer.” 微软原话,适合无登录的情况,以System权限运行。如果是用户登录就以低权限运行,具体情况得具体分析,不过服务有模拟权限,直接getsystem就行了。
启动服务:
sc start "endlessparadox"
停止服务:
sc stop "endlessparadox"
重启,一切工作正常。
最后
被windows的数据类型搞的有点烦了,后面得重新复习一下。补一个最近推的美少女:有村路美,贫乳萝莉+天才少女,真的太香了:
应该是今年推的TOP3的萝莉美少女了
参考:
https://www.codeproject.com/Articles/499465/Simple-Windows-Service-in-Cplusplus https://learn.microsoft.com/en-us/windows/win32/services/the-complete-service-sample