在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 否则无法找到外部解析
...