本文實現一個安裝為 Windows 服務、開機自動執行關機的「惡搞程序」,旨在演示 Windows 服務編程核心流程:服務安裝、啟動、控制處理、關機權限提升、服務註冊與刪除。僅供技術學習,請勿用於惡意用途。
SERVICE_TABLE_ENTRY st[] = {
{TEXT("ShutdownService"), ServiceMain},
{NULL, NULL}
};
StartServiceCtrlDispatcher(st);
ServiceMain 註冊控制處理函數 HandlerEx,設置服務狀態為 SERVICE_RUNNING,並調用核心邏輯 DoShutdown()。
BOOL DoShutdown() {
HANDLE hToken;
TOKEN_PRIVILEGES tkp;
// 1. 獲取進程令牌
OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken);
// 2. 查找 SE_SHUTDOWN_NAME 特權 LUID
LookupPrivilegeValue(NULL, SE_SHUTDOWN_NAME, &tkp.Privileges[0].Luid);
tkp.PrivilegeCount = 1;
tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
// 3. 啟用關機特權
AdjustTokenPrivileges(hToken, FALSE, &tkp, 0, NULL, NULL);
// 4. 執行關機
return ExitWindowsEx(EWX_SHUTDOWN | EWX_FORCE, SHTDN_REASON_MAJOR_OTHER);
}
關鍵點:服務運行於 SYSTEM 權限,但默認未啟用 SE_SHUTDOWN_PRIVILEGE,必須通過 AdjustTokenPrivileges 顯式啟用,否則 ExitWindowsEx 會失敗返回 ERROR_PRIVILEGE_NOT_HELD。
VOID WINAPI HandlerEx(DWORD dwControl, DWORD dwEventType, LPVOID lpEventData, LPVOID lpContext) {
switch (dwControl) {
case SERVICE_CONTROL_STOP:
g_Status.dwCurrentState = SERVICE_STOP_PENDING;
SetServiceStatus(g_hStatus, &g_Status);
// 執行清理工作
break;
case SERVICE_CONTROL_SHUTDOWN:
// 系統關機通知
break;
}
}
// 安裝:創建服務,設置為 SERVICE_AUTO_START(開機自啟)
SC_HANDLE schSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
SC_HANDLE schService = CreateService(schSCManager, "ShutdownService", "Auto Shutdown",
SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS, SERVICE_AUTO_START, SERVICE_ERROR_NORMAL,
szFilePath, NULL, NULL, NULL, NULL, NULL);
// 刪除:sc delete ShutdownService
SC_HANDLE schService = OpenService(schSCManager, "ShutdownService", DELETE);
DeleteService(schService);
main.c,鏈接 Advapi32.lib。ShutdownService.exe。ShutdownService.exe install (安裝服務)ShutdownService.exe start (啟動服務,驗證關機邏輯)若需移除該服務,可採取以下任一方式:
sc delete ShutdownService。sc delete ShutdownService 或手動刪除註冊表 HKLM\SYSTEM\CurrentControlSet\Services\ShutdownService。C:\Windows\System32\ShutdownService.exe(或自定義路徑)。ServiceMain、HandlerEx、SetServiceStatus 服務核心三元組。OpenProcessToken → LookupPrivilegeValue → AdjustTokenPrivileges 標準流程。DebugBreak() + 調試器附加,或寫日誌文件追蹤。完整項目源碼:百度網盤(提取碼見原文)