1. 簡介
Windows系統服務是一個不需要用戶登入就可以一直在后台運行的服務程序,
通過服務管理控制器(Service Control Manager, SCM)可以操作系統服務啟動、停止、自動運行等。
服務管理控制器(Service Control Manager, SCM) 維護着操作系統所有已安裝的服務,
里面有關於服務是如何啟動等信息,具有以下功能。
(1)在服務數據庫中維護系統已安裝的所有服務
(2)以自啟動或手動的方式啟動系統服務
(3)枚舉所有已安裝的服務
(4)維護服務的狀態
(5)向運行的服務傳輸控制請求信息
(6)加鎖或解鎖服務數據庫
2. 服務管理控制器數據庫
在注冊表中點擊以下路徑查看所有服務
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services
2.1 OpenSCManager 打開SCM數據庫
在操作服務管理數據庫時,必須使用函數 OpenSCManager 打開數據庫,獲得句柄。
SC_HANDLE WINAPI OpenSCManager(
_In_opt_ LPCTSTR lpMachineName, /* 目標機器名稱,NULL為本地機器 */
_In_opt_ LPCTSTR lpDatabaseName, /* 值一般為 SERVICES_ACTIVE_DATABASE */
_In_ DWORD dwDesiredAccess /* 特定權限訪問服務數據庫 */
);
API 參考鏈接 https://msdn.microsoft.com/en-us/library/windows/desktop/ms684323(v=vs.85).aspx
2.2 CreateService 創建服務
系統服務的名字由 CreateService 函數定義,原型如下
此函數功能: 創建一個名為 lpServiceName 的服務對象,並且安裝到服務控制管理器數據庫中。
返回特定的已安裝的服務對象句柄。
/* 成功返回SC_HANDLE類型的句柄,失敗返回NULL */
SC_HANDLE WINAPI CreateService(
_In_ SC_HANDLE hSCManager, /* SCM數據庫句柄對象,由 OpenSCManager函數返回 */ _In_ LPCTSTR lpServiceName, /* 安裝服務的名稱 */ _In_opt_ LPCTSTR lpDisplayName, /* 對用戶顯示的名稱 */ _In_ DWORD dwDesiredAccess, /* 訪問進程 */ _In_ DWORD dwServiceType, /* 服務類型 */ _In_ DWORD dwStartType, /* 服務啟動選項 */ _In_ DWORD dwErrorControl, /* 錯誤等級 */ _In_opt_ LPCTSTR lpBinaryPathName, /* exe文件路徑 */ _In_opt_ LPCTSTR lpLoadOrderGroup, /* 加載順序 */ _Out_opt_ LPDWORD lpdwTagId, /* */ _In_opt_ LPCTSTR lpDependencies, _In_opt_ LPCTSTR lpServiceStartName, /* 服務應該在哪個用戶下運行 DomainName/UserName */ _In_opt_ LPCTSTR lpPassword /* 用戶密碼 */ );
CreateService 接口示例代碼 參考鏈接
https://msdn.microsoft.com/en-us/library/windows/desktop/ms682450(v=vs.85).aspx
2.3 StartService 啟動服務
服務配置管理器對服務的啟動步驟如下
(1) 在 ServiceGroupOrder 列表中的系統將先啟動。
(2) 在ServiceOrderList列表中的值也會啟動
(3) 啟動對於依賴的服務
當服務啟動后,SCM執行以下步驟
(1)在數據庫中獲取用戶賬戶信息
(2)登錄服務賬戶
(3)加載用戶信息
(4)創建一個掛起的服務
(5)分配登錄口令給進程
(6)允許進程運行
開啟服務由 StartService 函數定義
StartService 函數參考文檔
https://msdn.microsoft.com/en-us/library/windows/desktop/ms686321(v=vs.85).aspx
每個服務項都會記錄相關信息 (ChangeServiceConfig 函數來修改記錄)
* 服務名稱
* 啟動類型
* 服務狀態 (SetServiceStatus 函數更新狀態)
* 指向依賴服務的列表
CloseServiceHandle 函數關閉服務對象句柄
3. 服務程序
服務程是運行一個或多個系統服務的可執行代碼。
3.1 服務程序入口
主函數的服務程序會調用 StartServiceDispatcher 函數連接SCM數據庫並且啟動dispatcher純程。
dispacher線程循環等待 dispach 表中的請求控制。
當所有服務都結束時,SCM會發送一個控制請求通知dispacher線程退出。
然后 StartServiceDispacher 函數會退出
StartServiceCtrlDispatcher 使用 SERVICE_TABLE_ENTRY 結構來作為參數。
每個結構都指明了服務名稱與服務入口函數
3.2 服務入口函數
服務入口函數會做以下事情
1. 初始化全局變量
2. 調用 RegisterServiceCtrlHandler 函數注冊一個句柄來控制服務。
3. 執行初始化。
3.3 服務主函數
3.3 服務控制接收函數
每一個服務都有控制接收函數,一個服務調用 RegisterServiceCrtlHandler 函數注冊服務控制器接收函數。
當服務控制器接收函數調用后,服務必須調用 SetServiceStatus 函數通知 SCM 服務狀態是否改變。
服務器控制函數必須在30s內返回,否則SCM返回Error錯誤信息。
如果一個服務收到 SERVICE_CONTROL_STOP 控制代碼,必須停止接收控制請求,進入 SERVICE_STOP_PENDING 或 SERVICE_STOPPED 狀態。
如果用戶關閉系統,則狀態碼會是 SERVICE_ACCEPT_PRESHUTDOWN, 則調用 SetServiceStatus進入 SERVICE_CONTROL_PRESHUTDOWN 狀態。
