新聞中心
幾乎每一種操作系統(tǒng)都有一種在系統(tǒng)啟動時啟動的進程機制,這種機制不會依賴于用戶的交互。在Windows下,類似的機制被稱為服務(wù)或Windows服務(wù)。服務(wù)是一種程序類型,它在后臺運行,服務(wù)程序通??梢栽诒镜睾屯ㄟ^網(wǎng)絡(luò)為用戶提供一些功能,服務(wù)在操作系統(tǒng)啟動時就會隨之啟動的程序。服務(wù)程序可能是EXE程序,具有其單獨的進程,也有可能是DLL文件依附于某個進程(比如svchost.exe),更有可能是SYS文件而處于系統(tǒng)的內(nèi)核之中。由于服務(wù)所處的核心地位、啟動方式等因素,它也是反病毒軟件與惡意軟件的“兵家必爭之地”。對于研究系統(tǒng)安全來說則非常重要。

01 如何查看系統(tǒng)服務(wù)
在Windows下,有很多服務(wù)是跟隨操作系統(tǒng)一起啟動的,具體有哪些服務(wù)是跟隨操作系統(tǒng)一起啟動的呢?如何查看呢?其實非常簡單。在“我的電腦”上單擊鼠標右鍵,然后在彈出的菜單上選擇“管理”,打開“計算機管理”工具,單擊左面樹形列表的“服務(wù)和應(yīng)用程序”會打開子列表,選擇“服務(wù)”,則在右側(cè)出現(xiàn)服務(wù)項列表。較為簡單的方法是直接在“運行”窗口中輸入“services.msc”,打開服務(wù)管理器。服務(wù)管理器主要用于顯示系統(tǒng)中已經(jīng)存在的應(yīng)用程序服務(wù),顯示對服務(wù)的描述,還可以控制服務(wù)的啟動狀態(tài)和啟動方式。服務(wù)管理器如圖1所示。
圖1 Windows下的服務(wù)管理程序
在圖1顯示的服務(wù)列表中,只能查看Win32應(yīng)用程序的服務(wù),無法查看關(guān)于驅(qū)動程序的服務(wù)??梢越柚谄渌恍┕ぞ邅聿榭打?qū)動程序級別的服務(wù),圖2使用SREng來查看驅(qū)動程序相關(guān)的服務(wù)列表。
圖2 使用SREng查看驅(qū)動程序服務(wù)列表
接下來會編寫一個類似的程序,既可以查看應(yīng)用程序服務(wù)列表,也可以查看驅(qū)動程序服務(wù)列表。編寫完成后的程序界面如圖3所示。
圖3 服務(wù)管理程序界面
編寫的服務(wù)管理程序既可以查看“Win32服務(wù)應(yīng)用程序”,也可以查看“驅(qū)動服務(wù)程序”,并且可以對它們的運行狀態(tài)進行簡單的控制。這里開發(fā)的服務(wù)控制管理器使用MFC的對話框,其中用到了CListCtrl控件。現(xiàn)在就開始打造一個屬于自己的服務(wù)控制管理器。
02 服務(wù)控制管理器的實現(xiàn)
服務(wù)控制管理器的開發(fā)過程與注冊表啟動管理器的開發(fā)過程比較類似,主要也是枚舉服務(wù)并顯示到列表控件中。對服務(wù)狀態(tài)的控制,是通過服務(wù)相關(guān)的API函數(shù)來完成的。首先來編寫代碼,希望大家能夠掌握服務(wù)相關(guān)的API函數(shù)。在代碼的后面,會對開發(fā)服務(wù)管理器涉及的API進行相應(yīng)的解釋。
學習API函數(shù)的使用,MSDN是最好的老師,詳細、透徹、權(quán)威。在編程的道路上,要不斷通過閱讀別人的代碼來提高自己的編程能力,就需要自己來掌握陌生的API函數(shù),那時一定要想起查閱MSDN。
1. 服務(wù)的類型
服務(wù)控制管理器的界面都已經(jīng)熟悉了,界面的布局可以按照自己的方式進行調(diào)整。在枚舉服務(wù)的時候,將“Win32應(yīng)用程序服務(wù)”和“驅(qū)動程序服務(wù)”分開枚舉,這樣有助于對各種服務(wù)的了解。
枚舉這兩類服務(wù)的主要差別在于調(diào)用EnumServicesStatus()函數(shù)時為其傳遞的第二個參數(shù)。如果枚舉“Win32應(yīng)用程序服務(wù)”,那么傳遞的參數(shù)為SERVICE_WIN32;如果枚舉“驅(qū)動程序服務(wù)”,那么傳遞的參數(shù)為SERVICE_DRIVER。這兩個參數(shù)其實是系統(tǒng)定義的宏,該宏定義在WinNt.h頭文件中,具體定義如下:
- #define SERVICE_DRIVER (SERVICE_KERNEL_DRIVER | \
- SERVICE_FILE_SYSTEM_DRIVER | \
- SERVICE_RECOGNIZER_DRIVER)
- #define SERVICE_WIN32 (SERVICE_WIN32_OWN_PROCESS | \
- SERVICE_WIN32_SHARE_PROCESS)
SERVICE_DRIVER 和 SERVICE_WIN32 是其他宏的組合,而那些宏又有具體的值。下面解釋一下其他宏的含義。
SERVICE_DRIVER 宏由 3 個宏組成,具體如下:
- #define SERVICE_KERNEL_DRIVER 0x00000001 // 設(shè)備驅(qū)動程序
- #define SERVICE_FILE_SYSTEM_DRIVER 0x00000002 // 內(nèi)核模式文件系統(tǒng)驅(qū)動程序
- #define SERVICE_RECOGNIZER_DRIVER 0x00000008 // 文件系統(tǒng)識別器驅(qū)動程序
SERVICE_WIN32 宏由兩個宏組成,具體如下:
- #define SERVICE_WIN32_OWN_PROCESS 0x00000010 // 獨占一個進程的服務(wù)
- #define SERVICE_WIN32_SHARE_PROCESS 0x00000020 // 與其他服務(wù)共享一個進程的服務(wù)
如果想要枚舉全部類型的服務(wù),那么使用SERVICE_TYPE_ALL宏即可,該宏的定義如下:
- #define SERVICE_TYPE_ALL (SERVICE_WIN32 | \
- SERVICE_ADAPTER | \
- SERVICE_DRIVER | \
- SERVICE_INTERACTIVE_PROCESS)
2. 服務(wù)的枚舉函數(shù)
服務(wù)的枚舉所使用的API函數(shù)是EnumServicesStatus(),該函數(shù)中需要指定枚舉的類型分別是SERVICE_DRIVER和SERVICE_WIN32。
具體來看服務(wù)枚舉的函數(shù),代碼如下:
- VOID CManageServicesDlg::ShowServiceList(DWORD dwServiceType)
- {
- m_ServiceList.DeleteAllItems();
- // 打開服務(wù)管理器
- SC_HANDLE hSCM = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
- if ( NULL == hSCM )
- {
- AfxMessageBox("OpenSCManger Error!");
- return ;
- }
- DWORD ServiceCount = 0;
- DWORD dwSize = 0;
- LPENUM_SERVICE_STATUS lpInfo;
- // 第一次調(diào)用
- BOOL bRet = EnumServicesStatus(hSCM,
- dwServiceType, SERVICE_STATE_ALL,
- NULL, 0, &dwSize,
- &ServiceCount, NULL);
- // 由于沒有給定接收服務(wù)列表的緩沖區(qū),這里必定會調(diào)用失敗
- // 失敗的原因是 ERROR_MORE_DATA
- // 說明需要更大的緩沖區(qū)來保存數(shù)據(jù)
- if ( !bRet && GetLastError() == ERROR_MORE_DATA )
- {
- // 分配緩沖區(qū),保存服務(wù)列表
- lpInfo = (LPENUM_SERVICE_STATUS)(new BYTE[dwSize]);
- bRet = EnumServicesStatus(hSCM,
- dwServiceType, SERVICE_STATE_ALL,
- (LPENUM_SERVICE_STATUS)lpInfo,
- dwSize, &dwSize,
- &ServiceCount, NULL);
- if ( !bRet )
- {
- CloseServiceHandle(hSCM);
- return ;
- }
- //逐個獲取數(shù)據(jù),添加至列表控件
- for ( DWORD i = 0; i < ServiceCount; i ++)
- {
- CString str;
- m_ServiceList.InsertItem(i, lpInfo[i].lpServiceName);
- m_ServiceList.SetItemText(i, 1, lpInfo[i].lpDisplayName);
- switch ( lpInfo[i].ServiceStatus.dwCurrentState )
- {
- case SERVICE_PAUSED:
- {
- m_ServiceList.SetItemText(i, 2, "暫停");
- break;
- }
- case SERVICE_STOPPED:
- {
- m_ServiceList.SetItemText(i, 2, "停止");
- break;
- }
- case SERVICE_RUNNING:
- {
- m_ServiceList.SetItemText(i, 2, "運行");
- break;
- }
- default:
- {
- m_ServiceList.SetItemText(i, 2, "其他");
- }
- }
- }
- // 釋放申請的空間
- delete lpInfo;
- }
- // 關(guān)閉服務(wù)管理器句柄
- CloseServiceHandle(hSCM);
- }
該函數(shù)有一個參數(shù),用來指明枚舉類型是“Win32應(yīng)用程序服務(wù)”,還是“驅(qū)動程序服務(wù)”。該函數(shù)的默認參數(shù)為“Win32應(yīng)用程序服務(wù)”,該函數(shù)的定義如下:
- VOID ShowServiceList(DWORD dwServiceType = SERVICE_WIN32);
3. 枚舉服務(wù)相關(guān)API函數(shù)解釋
(1)打開和關(guān)閉服務(wù)管理器
打開服務(wù)管理器的函數(shù)定義如下:
- SC_HANDLE OpenSCManager(
- LPCTSTR lpMachineName, // computer name
- LPCTSTR lpDatabaseName, // SCM database name
- DWORD dwDesiredAccess // access type
- );
參數(shù)說明如下。
lpMachineName:指向欲打開服務(wù)控制管理器數(shù)據(jù)庫的目標主機名,本機則設(shè)置為 NULL。
lpDatabaseName:指向目標主機 SCM 數(shù)據(jù)庫名字的字符串。
dwDesiredAccess:指定對 SCM 數(shù)據(jù)庫的訪問權(quán)限。
該函數(shù)調(diào)用成功,返回一個 SCM 句柄,否則返回 NULL。
SCM是服務(wù)控制管理器的意思,它是系統(tǒng)服務(wù)的一個組成部分,跟開發(fā)的軟件不是一個概念。
關(guān)閉服務(wù)句柄的函數(shù)定義如下:
- BOOL CloseServiceHandle(
- SC_HANDLE hSCObject // handle to service or SCM object
- );
該函數(shù)用來關(guān)閉由OpenSCManager()和OpenService()打開的句柄。
(2)服務(wù)的枚舉函數(shù)
枚舉服務(wù)的函數(shù)定義如下:
- BOOL EnumServicesStatus(
- SC_HANDLE hSCManager, // handle to SCM database
- DWORD dwServiceType, // service type
- DWORD dwServiceState, // service state
- LPENUM_SERVICE_STATUS lpServices, // status buffer
- DWORD cbBufSize, // size of status buffer
- LPDWORD pcbBytesNeeded, // buffer size needed
- LPDWORD lpServicesReturned, // number of entries returned
- LPDWORD lpResumeHandle // next entry
- );
參數(shù)說明如下。
hSCManager:OpenSCManager()函數(shù)返回的句柄。
dwServiceType:指定枚舉的服務(wù)類型,也就是自定義函數(shù)的參數(shù)。
dwServiceState:枚舉指定狀態(tài)的服務(wù)。
lpServices:指向 ENUM_SERVICE_STATUS 類型的指針。
cbBufSize:指定緩沖區(qū)的大小。
pcbBytesNeeded:返回實際使用的內(nèi)存空間大小。
lpServicesReturned:返回枚舉服務(wù)的個數(shù)。
lpResumeHandle:返回枚舉是否成功。
ENUM_SERVICE_STATUS 結(jié)構(gòu)體的定義如下:
- typedef struct _ENUM_SERVICE_STATUS {
- LPTSTR lpServiceName;
- LPTSTR lpDisplayName;
- SERVICE_STATUS ServiceStatus;
- } ENUM_SERVICE_STATUS, *LPENUM_SERVICE_STATUS;
SERVICE_STATUS 結(jié)構(gòu)體的定義如下:
- typedef struct _SERVICE_STATUS {
- DWORD dwServiceType;
- DWORD dwCurrentState;
- DWORD dwControlsAccepted;
- DWORD dwWin32ExitCode;
- DWORD dwServiceSpecificExitCode;
- DWORD dwCheckPoint;
- DWORD dwWaitHint;
- } SERVICE_STATUS, *LPSERVICE_STATUS;
代碼中兩次調(diào)用EnumServicesStatus()函數(shù)。第1次沒有傳遞第4個和第5個參數(shù),使得函數(shù)返回FALSE,用GetLastError()得到錯誤的原因為ERROR_MORE_DATA。這時,第6個參數(shù)pcbBytesNeeded返回實際需要使用的內(nèi)存大小,這樣可以通過new動態(tài)申請所需的堆空間。以這種方式來獲取實際所需緩沖區(qū)大小的情況是比較多的,請大家一定要理解。
4. 服務(wù)的啟動與停止
對服務(wù)的操作只介紹兩種,一種是啟動服務(wù),另一種是停止服務(wù),也就是改變服務(wù)的狀態(tài)。經(jīng)常會用到停止服務(wù)的操作,因為系統(tǒng)中有很多用不到的服務(wù),但是它仍然會隨著系統(tǒng)的啟動而啟動,這樣既會影響到系統(tǒng)的啟動速度,也會占用寶貴的系統(tǒng)資源。因此,沒有用的系統(tǒng)服務(wù)最好將其停止(其實真正停止服務(wù)是改變它的啟動狀態(tài),而不是這里介紹的運行狀態(tài))。
啟動服務(wù)的代碼如下:
- void CManageServicesDlg::OnBtnStart()
- {
- // TODO: Add your control notification handler code here
- // 選中服務(wù)的索引
- POSITION Pos = m_ServiceList.GetFirstSelectedItemPosition();
- int nSelect = -1;
- while ( Pos )
- {
- nSelect = m_ServiceList.GetNextSelectedItem(Pos);
- }
- if ( -1 == nSelect )
- {
- AfxMessageBox("請選擇要啟動的服務(wù)");
- return ;
- }
- // 獲取選中服務(wù)的服務(wù)名
- char szServiceName[MAXBYTE] = { 0 };
- m_ServiceList.GetItemText(nSelect, 0, szServiceName, MAXBYTE);
- SC_HANDLE hSCM = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
- if ( NULL == hSCM )
- {
- AfxMessageBox("OpenSCManager Error");
- return ;
- }
- // 打開指定的服務(wù)
- SC_HANDLE hSCService = OpenService(hSCM, szServiceName, SERVICE_ALL_ACCESS);
- // 啟動服務(wù)
- BOOL bRet = StartService(hSCService, 0, NULL);
- if ( bRet == TRUE )
- {
- m_ServiceList.SetItemText(nSelect, 2, "運行");
- }
- else
- {
- AfxMessageBox("啟動失敗!");
- }
- CloseServiceHandle(hSCService);
- CloseServiceHandle(hSCM);
- }
停止服務(wù)的代碼如下:
- void CManageServicesDlg::OnBtnStop()
- {
- // TODO: Add your control notification handler code here
- // 選中服務(wù)的索引
- // 此部分操作與啟動服務(wù)相同,為節(jié)省篇幅,此處省略
- // ……
- SC_HANDLE hSCM = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
- if ( NULL == hSCM )
- {
- AfxMessageBox("OpenSCManager Error");
- return ;
- }
- // 打開指定的服務(wù)
- SC_HANDLE hSCService = OpenService(hSCM, szServiceName, SERVICE_ALL_ACCESS);
- SERVICE_STATUS ServiceStatus;
- // 停止服務(wù)
- BOOL bRet = ControlService(hSCService, SERVICE_CONTROL_STOP, &ServiceStatus);
- if ( bRet == TRUE )
- {
- m_ServiceList.SetItemText(nSelect, 2, "停止");
- }
- else
- {
- AfxMessageBox("停止失敗!");
- }
- CloseServiceHandle(hSCService);
- CloseServiceHandle(hSCM);
- }
5. 啟動與停止服務(wù)相關(guān)API函數(shù)解釋
打開指定服務(wù)的函數(shù)定義如下:
- SC_HANDLE OpenService(
- SC_HANDLE hSCManager, // handle to SCM database
- LPCTSTR lpServiceName, // service name
- DWORD dwDesiredAccess // access
- );
參數(shù)說明如下。
hSCManager:指定由 OpenSCManager()函數(shù)打開的服務(wù)句柄。
lpServiceName:指定要打開的服務(wù)的名稱。
dwDesiredAccess:對要打開服務(wù)的訪問權(quán)限,這里為了方便,指定為 SC_MANAGER_ALL_ACCESS。
啟動服務(wù)的函數(shù)定義如下:
- BOOL StartService(
- SC_HANDLE hService, // handle to service
- DWORD dwNumServiceArgs, // number of arguments
- LPCTSTR *lpServiceArgVectors // array of arguments
- );
參數(shù)說明如下。
hService:指定要啟動服務(wù)的句柄,該句柄由 OpenService()返回。
dwNumServiceArgs:指向啟動服務(wù)所需的參數(shù)個數(shù)。
lpServiceArgVectors:指向啟動服務(wù)的參數(shù)。
停止服務(wù)的函數(shù)定義如下:
- BOOL ControlService(
- SC_HANDLE hService, // handle to service
- DWORD dwControl, // control code
- LPSERVICE_STATUS lpServiceStatus // status information
- );
參數(shù)說明如下。
hService:指定一個由 OpenService()打開的服務(wù)句柄。
dwControl:指定要發(fā)送的控制碼。
lpServiceStatus:返回服務(wù)的狀態(tài)。
ControlService()可以對服務(wù)進行多種控制操作,每種控制操作對應(yīng)一種控制碼。當要停止服務(wù)時,使用的控制碼為 SERVICE_CONTROL_STOP。一定要注意,停止服務(wù)不要想當然的使用 StopService()這樣的函數(shù),因為沒有這個 API 函數(shù)。
網(wǎng)站欄目:網(wǎng)絡(luò)安全編程:服務(wù)控制管理器實例
當前路徑:http://fisionsoft.com.cn/article/dphipji.html


咨詢
建站咨詢
