Windows内核编程(四)-服务的基本操作

4 篇文章 0 订阅

服务的基本操作

驱动以Windows服务的方式存在,服务有不同的类型,驱动只是其中一种类型的服务。本小节把驱动等同于服务。

服务的基本操作有注册(创建)、启动、暂停、停止操作。但内核驱动类型的服务不支持暂停操作。

服务管理器 的主要工作是管理操作系统上的所有服务,其中包括跟踪、维护服务的各种状态,以及对服务发起具体的操作。开发者可以通过服务管理器来查询服务状态、修改服务配置、注册(创建)新服务、启动服务等。开发者通过API操作服务,API内部首先会通过一个称为"LPC(本地方法调用)"的方式,把请求发送给服务管理器,服务管理器再处理具体的请求。

打开服务管理器

OpenSCManager

系统提供了一个API用来打开服务管理器。
打开服务管理器的函数为OpenSCManager,原型如下:
函数原型

SC_HANDLE OpenSCManager(
  LPCSTR lpMachineName,
  LPCSTR lpDatabaseName,
  DWORD  dwDesiredAccess
);

参数详解
lpMachineName - 一个字符串常量,表示机器的名字,可以简单传一个NULL,表示打开的是本机器的服务管理器。
lpDatabaseName - 一个字符串常量,表示数据库的名字,可以传一个NULL,表示打开的是一个活动(Active) 数据库。
dwDesiredAccess - 权限。开发者通过服务管理器去操作服务时,不同的操作需要不同的权限。常用的服务管理器权限有:

  • SC_MANAGER_CREATE_SERVICE - 表示拥有注册(创建)服务的权限。
  • SC_MANAGER_ENUMERATE_SERVICE - 表示拥有枚举系统服务的权限。
  • SC_MANAGER_ALL_ACCESS - 表示拥有一切权限。

返回值
OpenSCManager 函数返回一个类型为SC_HANDLE的句柄,表示服务管理器的句柄,开发者可以通过这个句柄,结合其他API来操作服务。当这个服务管理器句柄不在需要使用,开发者需要调用CloseServiceHandle函数来关闭句柄。CloseServiceHandle函数只有一个参数,使用非常简单。

BOOL CloseServiceHandle(
  SC_HANDLE hSCObject
);

服务的注册

CreateService

注册(创建)一个服务使用的函数为 CreateService。

函数原型

SC_HANDLE CreateService(
  SC_HANDLE hSCManager,	
  LPCSTR    lpServiceName,	
  LPCSTR    lpDisplayName,	
  DWORD     dwDesiredAccess,
  DWORD     dwServiceType,
  DWORD     dwStartType,
  DWORD     dwErrorControl,
  LPCSTR    lpBinaryPathName,
  LPCSTR    lpLoadOrderGroup,
  LPDWORD   lpdwTagId,
  LPCSTR    lpDependencies,
  LPCSTR    lpServiceStartName,
  LPCSTR    lpPassword
);

参数详解
hSCManager - 表示"服务管理器"句柄由于操作是注册(创建)服务,所以在打开服务管理器时,需要使用SC_MANAGER_CREATE_SERVICE权限

lpServiceName - 表示创建服务的名字,这个名字不能与其他存在服务的名字相同。服务名字时服务的唯一标识。

lpDisplayName - 服务显示名字

dwDesiredAccess - 服务的权限,常见的权限有:
SERVICE_START - 表示启动服务的权限。
SERVICE_STOP - 表示停止服务的权限。
SERVICE_QUERY_STATUS - 拥有查询服务状态的权限。
SERVICE_ALL_ACCESS - 拥有一切权限。

dwServiceType - 表示需要创建何种类型的服务,服务的类型有:
SERVICE_FILE_SYSTEM_DRIVER - 文件系统服务
SERVICE_KERNEL_DRIVER - 内核驱动服务
SERVICE_WIN32_OWN_PROCESS - 应用层服务
SERVICE_WIN32_SHARE_PROCESS - 应用层共享EXE服务
其他服务类型请查阅WDK文档。

dwStartType - 表示服务的启动方式,启动选项参数可选值:
SERVICE_BOOT_START - 操作系统引导阶段启动的服务,一般由 Winload模块负责加载服务对应的可执行文件到内存
SERVICE_SYSTEM_START - 操作系统启动阶段启动的服务,由系统NT模块负责加载服务对应的可执行文件到内存。
SERVICE_AUTO_START - 操作系统启动完毕后启动的服务
SERVICE_DEMAND_START - 需要手动启动的服务

dwErrorControl - 错误控制,具体是指服务启动失败的情况下,操作系统需要执行何种操作,常见的错误控制可选参数:
SERVICE_ERROR_CRITICAL、SERVICE_ERROR_IGNORE、SERVICE_ERROR_NORMAL及SERVICE_ERROR_SEVERE,
对于驱动程序来说,简单指定SERVICE_ERROR_IGNORE即可,表示系统忽略这个驱动启动失败信息。

lpBinaryPathName - 该服务对应可执行文件的全路径,对于驱动类型的服务来说,这里指定的就是sys文件所在的路径。

lpLoadOrderGroup - 服务所在分组的名字。操作系统内置了一系列服务的分组,开发者也可以创建新的分组。一个分组里面可以有多个服务,但是一个服务最多只能关联一个分组;不同分组的启动顺序不同。如果开发者关心服务的启动顺序,可以通过这个参数来设置分组。如果不关心启动顺序,可以简单把该参数设置成NULL,表示不关联任何分组。分组信息在注册表中的位置为HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\ ServiceGroupOrder,名字为list的值保存了所有分组的信息

lpdwTagId - 表示服务在分组内的一个标识,针对SERVICE_BOOT_START,以及SERVICE_SYSTEM_STAR类型的服务。服务的启动顺序由所属的分组决定,但同一分组内的服务启动顺序怎么决定呢?答案是通过lpdwTagId参数来指定。同样地,如果开发者不关心服务启动顺序,可以把该参数设置为0。该标识对应注册表的位置为HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\ GroupOrderList。

lpDependencies - 表示当前所注册的服务,需要依赖其他服务名的列表。
lpServiceStartName - 服务将在其下运行的帐户的名称。
lpPassword - lpServiceStartName参数指定的帐户名的密码

返回值
如果函数成功,则返回值是服务的句柄。
如果函数失败,则返回值为NULL。
开发者可以通过CreateService返回服务的服务句柄来操作服务,使用完毕后需要调用CloseServiceHandle函数关闭句柄。

开发者需要操作服务,但服务已经存在,开发者不需要重新注册(创建)服务,在这种情况下,就需要OpenService函数。

OpenService

开发者需要操作服务,但服务已经存在,开发者不需要重新注册(创建)服务,在这种情况下,开发者需要“打开”已经存在的服务,通过OpenService函数打开服务。

函数原型

SC_HANDLE WINAPI OpenService(
	SC_HANDLE hSCManager,
	LPCTSTR lpServiceName,
	DWORD dwDesiredAccess
);

参数详解
hSCManager - 标识服务管理器句柄
lpServiceName - 表示需要打开的服务的名字
dwDesiredAccess - 表示需要以何种权限打开服务

返回值
OpenService成功打开服务后返回服务的句柄,开发者可以通过这个句柄操作服务,使用完毕后需要调用CloseServiceHandle函数关闭句柄。

服务的启动与停止

StartService

启动服务
函数原型

BOOL WINAPI StartService(
	SC_HANDLE hService,
	DWORD dwNumServiceArgs,
	LPCTSTR *lpServiceArgVectors
);

参数详解

hService - 服务的句柄,表示需要启动的服务
dwNumServiceArgs - 服务启动时所需要传递的参数
lpServiceArgVectors - - 服务启动时所需要传递的参数

对于内核驱动类型的服务,可以忽略dwNumServiceArgslpServiceArgVectors 参数,设置为NULL即可。

说明
对于内核驱动服务来说,StartService操作意味着把磁盘的sys文件加载到内核中,具体过程为:StartService函数内部通过服务管理器,让系统SYSTEM进程加载驱动并调用内核驱动的DriverEntry入口函数,这一系列操作是同步的。此外,StartService函数内部还会等待DriverEntry入口函数执行返回,获取其返回值,如果DriverEntry函数返回成功,StartService函数相应的也返回成功,否则返回失败。

虽然说DriverEntry的返回值会影响该服务启动的成败,但是这并不是唯一的影响因素,StartService函数返回失败的情况很多,如服务已经被删除、hService参数没有相应地启动服务权限、服务已经在运行等。

作为一个完整生命周期的服务来说,启动后也会有相应的停止操作。停止一个内核驱动类型的服务意味着驱动模块从内存中删除,站在开发者的角度来看,当内核类型服务停止时,必须清理掉所使用的资源,避免造成资源泄露或系统异常。对于驱动来说,如何感知自身要被停止呢?答案是驱动对象的DriverUnload函数。

ControlService

停止服务、暂停服务、恢复服务等,大部分操作都是针对用户态服务。

函数原型

BOOL WINAPI ControlService(
	SC_HANDLE hService,
	DWORD dwControl,
	LPSERVICE_STATUS lpServiceStatus
);

参数详解
hService - 需要操作的服务的句柄
dwControl - 控制码,表示对服务进行何种操作,系统定义了一些列值,如SERVICE_CONTROL_PAUSE、SERVICE_CONTROL_STOP、SERVICE_CONTROL_CONTINUE等
lpServiceStatus - 返回参数,表示服务当前最新的状态,这些状态保存在SERVICE_STATUS结构体中。

服务的删除

DeleteService

函数原型

BOOL WINAPI DeleteService(SC_HANDLE hService);

参数详解
hService - 表示需要删除的服务。
常见的操作是:开发者调用OpenService函数(dwDesiredAccess为DELETE权限)打开一个需要删除的服务,成功打开后获取到需要删除的服务句柄,然后把服务句柄传递给DeleteService函数。

服务的例子

假设前面介绍的驱动MyDriver.sys文件放在C盘下,例子代码中需要把这个驱动注册成服务,并且运行,具体代码:

#include "windows.h"
#include <tchar.h>
#include <stdio.h>

#define SER_NAME _T("MyDriver")

int main()
{
	SC_HANDLE hSCM = NULL;
	SC_HANDLE hSer = NULL;

	do
	{
		hSCM = OpenSCManager(NULL, NULL, SC_MANAGER_CREATE_SERVICE | SC_MANAGER_CONNECT);

		if (hSCM == NULL)
		{
			break;
		}

		hSer = CreateService(
			hSCM,					//句柄
			SER_NAME,				//服务名称
			SER_NAME,				//服务显示名字
			SERVICE_ALL_ACCESS,		//所有权限打开
			SERVICE_KERNEL_DRIVER,	//内核类型的服务
			SERVICE_DEMAND_START,	//服务启动类型。这里是手动启动
			SERVICE_ERROR_IGNORE,	//错误类型
			_T("C:\\MyDriver.sys"),	//sys文件所在的磁盘目录
			NULL,					//服务所在的组,不关心顺序
			NULL,					//服务的Tag,这里不关心
			NULL,					//服务的依赖,没有依赖
			NULL,					//服务的启动用户名
			NULL					//服务启动用户名对应的密码
			);

		if (hSer == NULL)
		{
			DWORD dwErrorCode = GetLastError();
			if (dwErrorCode == ERROR_SERVICE_EXISTS)
			{
				//ERROR_SERVICE_EXITS 表示服务已经存在,不能重复注册,属于正常的情况
				hSer = OpenService(hSCM, SER_NAME, SERVICE_ALL_ACCESS);
				if (hSer == NULL)
				{
					//打开失败
					break;
				}
			}
			else
			{
				break;
			}
		}
		printf("CreateService or openService success.\n");
		getchar();

		// 准备启动服务
		BOOL bSucc = StartService(hSer, NULL, NULL);
		printf("StartService: %u\n", bSucc);

		getchar();

		//停止服务
		SERVICE_STATUS SerStatus = { 0 };
		bSucc = ControlService(hSer, SERVICE_CONTROL_STOP,&SerStatus);
		printf("ControlService: %u\n", bSucc);
		getchar();
		//删除服务
		DeleteService(hSer);
	} while (FALSE);

	if (hSCM != NULL)
	{
		CloseServiceHandle(hSCM);
		hSCM = NULL;
	}

	if (hSer != NULL)
	{
		CloseServiceHandle(hSer);
		hSer = NULL;
	}
	return 0;
}

运行程序注意事项
首先在管理员模式下运行或者以管理员模式打开Visual Studio。
然后计算机必须在"禁用驱动程序强制签名"状态下才可以启动驱动成功。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值