好啦,現(xiàn)在開始干活
取得配置權(quán)限
在對(duì)服務(wù)進(jìn)行管理設(shè)置前,需要以相應(yīng)的權(quán)限打開服務(wù),可通過下面兩個(gè)API實(shí)現(xiàn)
SC_HANDLE OpenSCManager(
LPCTSTR lpMachineName, // pointer to machine name string
LPCTSTR lpDatabaseName, // pointer to database name string
DWORD dwDesiredAccess // type of access
);
SC_HANDLE OpenService(
SC_HANDLE hSCManager, // handle to service control manager
// database
LPCTSTR lpServiceName, // pointer to name of service to start
DWORD dwDesiredAccess // type of access to service
);
通常我們以完全權(quán)限打開,示例代碼如下:
SC_HANDLE scm;
SC_HANDLE service;
if((scm=OpenSCManager(NULL,NULL,SC_MANAGER_ALL_ACCESS))==NULL)
{
Printf("OpenSCManager Error\n");
}
service=OpenService(scm,ServerName,SERVICE_ALL_ACCESS);
if(!service)
{
Printf("OpenService error!\n");
}
這樣就可以通過service句柄對(duì)服務(wù)進(jìn)行各種操作了
枚舉基本服務(wù)信息
想要對(duì)服務(wù)進(jìn)行設(shè)置就需要知道服務(wù)的當(dāng)前信息,對(duì)我們有用的通常是以下幾項(xiàng)
服務(wù)名稱,顯示名稱,啟動(dòng)狀態(tài),啟動(dòng)方式,程序路徑等。
這些信息我們可以通過API函數(shù)EnumServicesStatus來實(shí)現(xiàn),它的原形如下:
BOOL EnumServicesStatus(
SC_HANDLE hSCManager, // handle to service control manager database
DWORD dwServiceType, // type of services to enumerate
DWORD dwServiceState, // state of services to enumerate
LPENUM_SERVICE_STATUS lpServices,
// pointer to service status buffer
DWORD cbBufSize, // size of service status buffer
LPDWORD pcbBytesNeeded, // pointer to variable for bytes needed
LPDWORD lpServicesReturned,
// pointer to variable for number returned
LPDWORD lpResumeHandle // pointer to variable for next entry
);
其中 LPENUM_SERVICE_STATUS lpServices是一個(gè)結(jié)構(gòu),它的原形如下:
typedef struct _ENUM_SERVICE_STATUS { // ess
LPTSTR lpServiceName;
LPTSTR lpDisplayName;
SERVICE_STATUS ServiceStatus;
} ENUM_SERVICE_STATUS, *LPENUM_SERVICE_STATUS;
結(jié)構(gòu)中包含服務(wù)名稱,顯示名稱,啟動(dòng)狀態(tài)。雖然它所返回的信息是及為有限的,但它是一次枚舉所有服務(wù)信息
在要求不高的情況下,用它還是相當(dāng)方便的,下面的示例代碼可以枚舉系統(tǒng)中所有服務(wù)的基本信息,代碼如下:
LPENUM_SERVICE_STATUS lpServices = NULL;
DWORD nSize = 0;
DWORD n;
DWORD nResumeHandle = 0;
lpServices = (LPENUM_SERVICE_STATUS) LocalAlloc(LPTR, 64 * 1024); //注意分配足夠的空間
EnumServicesStatus(scm,SERVICE_WIN32,
SERVICE_STATE_ALL,
(LPENUM_SERVICE_STATUS)lpServices,
64 * 1024,
&nSize,
&n,
&nResumeHandle);
for ( i = 0; i < n; i++)
{
Printf("服務(wù)名稱: %s",lpServices[i].lpServiceName);
Printf("顯示名稱: %s",lpServices[i].lpDisplayName);
if ( lpServices[i].ServiceStatus.dwCurrentState!=SERVICE_STOPPED)
{
Printf("啟動(dòng)狀態(tài): 已啟動(dòng)\n");
}
}
枚舉詳細(xì)服務(wù)信息
如果想得到更詳細(xì)的服務(wù)信息,我們可以使用另一個(gè)API函數(shù)QueryServiceConfig
它的原形如下:
BOOL QueryServiceConfig(
SC_HANDLE hService, // handle of service
LPQUERY_SERVICE_CONFIG lpServiceConfig,
// address of service config. structure
DWORD cbBufSize, // size of service configuration buffer
LPDWORD pcbBytesNeeded // address of variable for bytes needed
);
LPQUERY_SERVICE_CONFIG lpServiceConfig是一個(gè)結(jié)構(gòu),它包含指定服務(wù)的詳細(xì)資料,它的原形如下
typedef struct _QUERY_SERVICE_CONFIG { // qsc
DWORD dwServiceType;
DWORD dwStartType;
DWORD dwErrorControl;
LPTSTR lpBinaryPathName;
LPTSTR lpLoadOrderGroup;
DWORD dwTagId;
LPTSTR lpDependencies;
LPTSTR lpServiceStartName;
LPTSTR lpDisplayName;
} QUERY_SERVICE_CONFIG, LPQUERY_SERVICE_CONFIG;
很清楚了吧,服務(wù)類型,啟動(dòng)類型,程序路徑,服務(wù)名稱,顯示名稱盡在其中。
下面的示例代碼可以得到程序路徑,啟動(dòng)方式,其代碼如下:
LPQUERY_SERVICE_CONFIG ServicesInfo = NULL;
for ( i = 0; i < n; i++)
{
SC_HANDLE service = NULL;
DWORD nResumeHandle = 0;
service=OpenService(scm,lpServices[i].lpServiceName,SERVICE_ALL_ACCESS);
ServicesInfo = (LPQUERY_SERVICE_CONFIG) LocalAlloc(LPTR, 64 * 1024); //注意分配足夠的空間
QueryServiceConfig(service,ServicesInfo,64 * 1024,&nResumeHandle); //枚舉各個(gè)服務(wù)信息
Printf("程序路徑: %s",ServicesInfo->lpBinaryPathName);
if(2==ServicesInfo->dwStartType) //啟動(dòng)方式
{
Printf("自動(dòng)\n");
}
if(3==ServicesInfo->dwStartType)
{
Printf("手動(dòng)\n");
}
if(4==ServicesInfo->dwStartType)
{
Printf("禁止\n");
}
}
上面的代碼稍加修改就可以用到你的程序中,現(xiàn)在對(duì)于服務(wù)信息的顯示就完成了。
啟動(dòng)/停止服務(wù)
啟動(dòng)一個(gè)服務(wù)可以用StartService函數(shù)實(shí)現(xiàn),不過在啟動(dòng)前先用QueryServiceStatus檢查一下服務(wù)的運(yùn)行狀態(tài),如下代碼
SERVICE_STATUS status;
BOOL isSuccess=QueryServiceStatus(service,&status);
if (!isSuccess)
{
Printf("QueryServiceStatus error!\n");
}
if ( status.dwCurrentState==SERVICE_STOPPED )
{
isSuccess=StartService(service,NULL,NULL);
if (!isSuccess)
{
Printf("啟動(dòng)服務(wù)失??!");
}
}
下面是停止服務(wù)的實(shí)現(xiàn)代碼:
if ( status.dwCurrentState!=SERVICE_STOPPED )
{
isSuccess=ControlService(service,SERVICE_CONTROL_STOP,&status);
if (!isSuccess )
{
Printf("停止服務(wù)失??!");
}
}
創(chuàng)建/刪除服務(wù)
創(chuàng)建服務(wù)使用的API為CreateService,它的原形為:
SC_HANDLE CreateService(
SC_HANDLE hSCManager, // handle to service control manager
// database
LPCTSTR lpServiceName, // pointer to name of service to start
LPCTSTR lpDisplayName, // pointer to display name
DWORD dwDesiredAccess, // type of access to service
DWORD dwServiceType, // type of service
DWORD dwStartType, // when to start service
DWORD dwErrorControl, // severity if service fails to start
LPCTSTR lpBinaryPathName, // pointer to name of binary file
LPCTSTR lpLoadOrderGroup, // pointer to name of load ordering
// group
LPDWORD lpdwTagId, // pointer to variable to get tag identifier
LPCTSTR lpDependencies, // pointer to array of dependency names
LPCTSTR lpServiceStartName,
// pointer to account name of service
LPCTSTR lpPassword // pointer to password for service account
);
其中 DWORD dwStartType是指動(dòng)方式,有三種方式
SERVICE_AUTO_START //自動(dòng)
SERVICE_DEMAND_START //手動(dòng)
SERVICE_DISABLED //禁用
此函數(shù)的參比較多但我們通常只用其中的一部分,如
SC_HANDLE hSCManager, //用OpenSCManager打開的句柄
LPCTSTR lpServiceName, // 服務(wù)名稱
LPCTSTR lpDisplayName, // 顯示名稱
DWORD dwStartType, // 啟動(dòng)方式
LPCTSTR lpBinaryPathName, // 程序路徑
其它直接賦0或NULL就可以了
例如下面的代碼可以創(chuàng)建一個(gè)名為 LengFeng 路徑為C:\LengFeng.EXE的自啟動(dòng)服務(wù)
void CreateServer()
{
SC_HANDLE scm=NULL;
SC_HANDLE service=NULL;
if((scm=OpenSCManager(NULL,NULL,SC_MANAGER_CREATE_SERVICE))==NULL)
{
Printf("OpenSCManager Error");
}
service=CreateService(
scm,"LengFeng" ,"LengFeng" ,
SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS,
SERVICE_AUTO_START, SERVICE_ERROR_NORMAL,
"C:\LengFeng.EXE", 0, 0, 0, 0, 0 );
if(!service)
Printf("服務(wù)創(chuàng)建失敗");
CloseServiceHandle(service);
CloseServiceHandle(scm);
}
刪除服務(wù)更容易些,可以用DeleteService來實(shí)現(xiàn)
BOOL DeleteService( SC_HANDLE hService);
SC_HANDLE hService是我們以前用OpenService打開的服務(wù)句柄,在刪除前注意先用,啟動(dòng)/停止服務(wù)中介紹的方法
停止正在運(yùn)行的服務(wù)。
配置啟動(dòng)方式
有時(shí)候我們需要對(duì)服務(wù)的啟動(dòng)方式進(jìn)行更改,比如TELNET改為自動(dòng)運(yùn)行,對(duì)以存在的服務(wù)進(jìn)行配置
可以用ChangeServiceConfig來實(shí)現(xiàn),它的原形如下:
BOOL ChangeServiceConfig(
SC_HANDLE hService // handle to service
DWORD dwServiceType, // type of service
DWORD dwStartType, // when to start service
DWORD dwErrorControl, // severity if service fails to start
LPCTSTR lpBinaryPathName, // pointer to service binary file name
LPCTSTR lpLoadOrderGroup, // pointer to load ordering group name
LPDWORD lpdwTagId, // pointer to variable to get tag identifier
LPCTSTR lpDependencies, // pointer to array of dependency names
LPCTSTR lpServiceStartName,
// pointer to account name of service
LPCTSTR lpPassword, // pointer to password for service account
LPCTSTR lpDisplayName // pointer to display name
);
揉揉眼睛仔細(xì)看一下,是不是有點(diǎn)面熟?嘿它的參數(shù)跟創(chuàng)建服務(wù)的CreateService就是一樣的嘛!這樣就好辦了
我們把需要的地方改掉,不需要的就放個(gè)NULL或SERVICE_NO_CHANGE就行了。
為了安全更新配置信息,微軟要求在執(zhí)行ChangeServiceConfig之前需要用LockServiceDatabase來鎖定服務(wù)數(shù)據(jù)
偶測試了一下,有時(shí)候會(huì)鎖定失敗,但仍然可以實(shí)現(xiàn)對(duì)服務(wù)配置的更改。
下面的示例代碼,可以把上面創(chuàng)建的LengFeng服務(wù)的啟動(dòng)方式改為 禁止
其代碼如下:
SC_LOCK sclLock;
sclLock = LockServiceDatabase(scm);
if (sclLock == NULL)
{
if (GetLastError() != ERROR_SERVICE_DATABASE_LOCKED)
Printf("LockServiceDatabase error\n");
}
if (! ChangeServiceConfig(
service, // handle of service
SERVICE_NO_CHANGE, // service type: no change
SERVICE_DISABLED, // 這里做了更改
SERVICE_NO_CHANGE, // error control: no change
NULL, // binary path: no change
NULL, // load order group: no change
NULL, // tag ID: no change
NULL, // dependencies: no change
NULL, // account name: no change
NULL, // password: no change
NULL)) //displayname
{
Printf("ChangeServiceConfig error!\n");
}
UnlockServiceDatabase(sclLock);
伸個(gè)懶腰,與服務(wù)相關(guān)的操作,我們也搞個(gè)六七八九不離十啦,想把它加到自己的木馬中時(shí),只要設(shè)計(jì)一個(gè)便于網(wǎng)絡(luò)傳輸?shù)慕Y(jié)構(gòu),然后把代碼拷進(jìn)去就差不多了。在寫這個(gè)小程序時(shí)遇到的相關(guān)問題寫在了blog.csdn.net/chinafe有興趣可以跟我討論。