这个课题主要是讲如何动态加载驱动,虽然现在已经存在很多的动态驱动加载器,但是使用自己编写的东西,还是有不同的感觉的。当是科普吧。
在这里,主要使用SCM来进行驱动的动态加载和卸载。
先介绍下SCM,服务控制管理器(Service Control Manager , SCM )。服务(Service)是在后台运行配套的程序,并且不需要用户交互(也就是说没有常见的用户界面或者控制台)。换句话说,一个服务就是一个始终运行于系统中的 Win32 进程,即使没有用户登陆进来也如此。SC 管理器(即服务控制管理器)可以控制服务和驱动程序。
主要涉及的函数如下:
名 称 描 述
CloseServiceHandle 关闭来自 OpenSCManager() 、 CreateService() 或 OpenService() 的句柄
ControlService 停止、暂停、继续、查询或通知已加载的服务 / 驱动程序
CreateService 加载一个服务 / 驱动程序
DeleteService 卸载一个服务 / 驱动程序
OpenSCManager 获取 SC 管理器的句柄
OpenService 获取一个已加载的服务 / 驱动程序的句柄
QueryServiceStatus 查询一个服务 / 驱动程序的属性和当前状态
StartService 启动一个已加载的服务 / 驱动程序
加载和运行一个服务需要执行的典型操作步骤:
1. 调用 OpenSCManager() 以获取一个管理器句柄
2. 调用 CreateService() 来向系统中添加一个服务
3. 调用 StartService() 来运行一个服务
4. 调用 CloseServiceHandle() 来释放管理器或服务句柄
不过我这里决定把加载驱动和启动驱动的过程分开,这样容易看明白,如果想整合也很容易,直接调用两个函数就可以了。
一 打开SCM
第一步需要做的是和SCM交互,则要使用OpenSCManager函数。原型如下:
SC_HANDLE OpenSCManager(LPCTSTR lpMachineName,
LPCTSTR lpDatabaseName,
DWORD dwDesiredAccess);
lpMachineName:电脑名。如果为NULL,则为本机。
lpDatabaseName:SCM数据库标识,应该为SERVICES_ACTIVE_DATABASE或者如果为NULL,则SEVICES_ACTIVE_DATABASE数据库作为默认数据库被打开。
dwDesiredAccess:以何种权限打开。
本函数返回一个SC_HANDLE的句柄以便作为其他函数的参数来操作SCM数据库。
当完成对SCM数据库的访问后,在退出前必须使用CloseServiceHandle关闭它。原型为:
BOOL CloseServiceHandle(SC_HANDLE hSCManger);
二 创建服务
增加一个Service,需要用到CreateService函数,原型如下:
SC_HANDLE CreateService(SC_HANDLE hSCManager,
LPCTSTR lpServiceName,
LPCTSTR lpDisplayName,
DWORD dwDesireAccess,
DWORD dwServiceType,
DWORD dwStartType,
DWORD dwErrorControl,
LPCTSTR lpBinaryPathName,
LPCTSTR lpLoadOrderGroup,
LPDWORD lpdwTagId,
LPCTSTR lpDependencies,
LPCTSTR lpServiceStartName,
LPCTSTR lpPassword);
这个函数有十三个参数:
hSCManager:是OpenSCManager得到的返回值,即服务管理器的句柄。
lpServiceName:Service的名字,,同时注册表也使用这个名字,这个Service的相应信息存放在HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Service\lpServiceName子键下;
lpDisplayName:Service在服务控制面板中显示的名字;
dwDesireAccess:访问Service的权限类型;
dwServiceType:Service的类型,可以是SERVICE_FILE_SYSTEM_DRIVER、SERVICE_KERNEL_DRIVER、SERVICE_WIN32_OWN_PROCESSS、SERVICE_WIN32_SHARE_PROCESS之一;
dwStartType:Service启动类型,可以是自动(SERVICE_ATUO_START)、手动(SERVICE_DEMAND_START)、禁止(SERVICE_DISABLED);
dwErrorControl:出错控制,SERVICE_ERROR_IGNORE和SERVICE_ERROR_NORMAL表示出错时在日志中纪录并继续。两个参数的区别是SERVICE_ERROR_NORMAL将会在出错时向用户显示一条出错信息,SERVICE_ERROR_SERVER和SERVICE_ERROR_CRITICAL告诉系统在失败时重启;
lpBinaryPathName:驱动的路径,也是服务的路径;
lpLoadOrderGroup:如果这个服务是加载服务组中的一个,这个指针指向这者字符串数组,一般为NULL;
lpdwTagId:指针,指向的变量,接收的值用於区别lpLoadOrderGroup服务组中的不同服务,一般为NULL;
lpDependencies:这个Service所依赖的其他服务,在启动本Service之前需要先启动这些服务;
lpServiceStartName:帐号;
lpPassword:密码。
需要注意的是,如果要增加一个Service,那么OpenSCManager函数中的dwDesiredAccess参数至少需要为SC_MANAGER_CREATE_SERVICE。
三 启动服务
启动Service,相应函数如下:
BOOL StartService(SC_HANDLE hService,
DWORD dwNumServiceArgs,
LPCTSTR *lpServiceArgVectors);
hService:Service的句柄;
dwNumServiceArgs:指定在lpServiceArgVectors指向的数组中参数的个数,如果lpServiceArgVectors为NULL,这个值为0;
lpServiceArgVectors:指向传递给Service的参数字符串数组的指针,可以为NULL;
Service运行之后,ControlService函数用于的控制,函数原型如下:
BOOL ControlService(SC_HANDLE hService,
DWORD dwControl,
LPSERVICE_STATUS lpServiceStatus);
hService:Service句柄;
dwControl:SERVICE_CONTROL_STOP,SERVICE_CONTROL_PAUSE,SERVICE_CONTROL_CONTINUE,SERVICE_CONTROL_INTERROGATE之一,也可以自定义(128~255);
lpServiceStatus:一个LPSERVICE_STATUS的结构指针。
如果想停止服务,也需要使用该函数来进行控制。
BOOL QueryServiceStatus(SC_HANDLE hService,
LPSERVICE_STATUS lpServiceStatus);
调用QueryServiceStatus函数和调用带SERVICE_CONTROL_INTERROGATE参数的ControlService相差无几。
使用该函数进行服务状态的查询,比如判断服务是否已经启动,服务是否停止了。
好,下面就是代码了,我使用的是delphi7,把这些功能写在一个类中,代码很容易明白。也就不多说了。
unit untServiceMan; interface uses windows, WinSvc; type TServiceMan = class private function ServiceConnect:SC_HANDLE; function ServiceDisconn(hService:SC_HANDLE):SC_HANDLE; function ServiceOpen(hService:SC_HANDLE; AServName:PChar):SC_HANDLE; function ServiceClose(hService:SC_HANDLE):Boolean; function ServiceGetStatus(hService:SC_HANDLE; AServName:PChar ):DWord; function ServiceUninstalled(hService:SC_HANDLE; AServName:PChar):Boolean; function ServiceRunning(hService:SC_HANDLE; AServName:PChar):Boolean; function ServiceStopped(hService:SC_HANDLE; AServName:PChar):Boolean; public function ServiceInstall(AServName, ADispName, AServPath:PChar):SC_HANDLE; function ServiceUnInstall(AServName:PChar):DWORD; function ServiceStart(AServName:PChar):DWORD; function ServiceStop(AServName:PChar):DWORD; end; implementation { TServiceMan } {********************************************************** **功能:装载服务 * **参数1:服务名 * **参数2:服务描述 * **参数3:服务文件的地址 * ***********************************************************} function TServiceMan.ServiceInstall(AServName, ADispName, AServPath: PChar): SC_HANDLE; var hManager:SC_HANDLE; begin result := 0; hManager := ServiceConnect; try if ServiceUninstalled(hManager, AServName) then begin result := CreateService(hManager, AServName, ADispName, SERVICE_ALL_ACCESS, SERVICE_KERNEL_DRIVER, SERVICE_DEMAND_START, SERVICE_ERROR_NORMAL, AServPath, nil, nil, nil, nil, nil); ServiceClose(result); //记住关闭句柄,否则会无法卸载服务 end; finally ServiceDisconn(hManager); end; end; {********************************************************** **功能:关闭打开的服务句柄 * **参数1:服务句柄 * ***********************************************************} function TServiceMan.ServiceClose(hService: SC_HANDLE): Boolean; begin if (hService <> 0) then result := CloseServiceHandle(hService) else result := True; end; {********************************************************** **功能:打开服务管理器 * **返回值为其句柄 * ***********************************************************} function TServiceMan.ServiceConnect: SC_HANDLE; begin result := OpenSCManager(nil, nil, SC_MANAGER_ALL_ACCESS); end; {********************************************************** **功能:关闭管理器句柄 * **参数1:服务句柄 * ***********************************************************} function TServiceMan.ServiceDisconn(hService: SC_HANDLE): SC_HANDLE; begin if (hService <> 0) then CloseServiceHandle(hService); result := 0; end; {********************************************************** **功能:获得一个已经加载的服务的句柄 * **参数1:管理器句柄 * **参数2:服务的名称 * ***********************************************************} function TServiceMan.ServiceOpen(hService:SC_HANDLE; AServName: PChar): SC_HANDLE; begin result := OpenService(hService, AServName, SERVICE_ALL_ACCESS); end; {********************************************************** **功能:卸载服务 * **参数1:服务的名称 * ***********************************************************} function TServiceMan.ServiceUnInstall(AServName:PChar): DWORD; var hService, hManager:SC_HANDLE; ServiceStatus:TServiceStatus; begin result := 0; hManager := ServiceConnect; try if not ServiceUninstalled(hManager, AServName) then begin hService := ServiceOpen(hManager, AServName); if (hService <> 0) then begin ControlService(hService, SERVICE_CONTROL_STOP, ServiceStatus); //在卸载前停止服务,否则需要停止服务才能正常卸载 if DeleteService(hService) then result := 2 else result := 1; end; ServiceClose(hService); end; finally ServiceDisconn(hManager); end; end; {********************************************************** **功能:启动服务 * **参数1:服务的名称 * **返回值: 0:驱动还未安装 * 1:驱动已启动 * 2:驱动启动成功 * 3:驱动启动失败 * ***********************************************************} function TServiceMan.ServiceStart(AServName: PChar): DWORD; var hService, hManager:SC_HANDLE; begin result := 0; hManager := ServiceConnect; try if not ServiceUninstalled(hManager, AServName) then begin if not ServiceRunning(hManager, AServName) then begin hService := ServiceOpen(hManager, AServName); if (hService <> 0) then if StartService(hService, 1, AServName) then //启动服务 result := 2 else result := 3; ServiceClose(hService); end else result := 1; end; finally ServiceDisconn(hManager); end; end; {********************************************************** **功能:停止服务 * **参数1:服务的名称 * **返回值: 0:驱动还未安装 * 1:驱动已停止 * 2:驱动停止成功 * 3:驱动停止失败 * ***********************************************************} function TServiceMan.ServiceStop(AServName: PChar): DWORD; var hService, hManager:SC_HANDLE; ServiceStatus:TServiceStatus; begin result := 0; hManager := ServiceConnect; try if not ServiceUninstalled(hManager, AServName) then begin if not ServiceStopped(hManager, AServName) then begin hService := ServiceOpen(hManager, AServName); if (hService <> 0) then if ControlService(hService, SERVICE_CONTROL_STOP, ServiceStatus) then result := 2 else result := 3; ServiceClose(hService); end else result := 1; end; finally ServiceDisconn(hManager); end; end; {********************************************************** **功能:获得服务的状态 * **参数1:管理器的句柄 * **参数2:服务的名称 * ***********************************************************} function TServiceMan.ServiceGetStatus(hService:SC_HANDLE; AServName:PChar ):DWORD; var hService2:SC_HANDLE; queryStatus:TServiceStatus; dwStat:DWORD; begin dwStat := 0; if(hService > 0)then begin hService2 := ServiceOpen(hService, AServName); if(QueryServiceStatus(hService2, queryStatus))then begin dwStat := queryStatus.dwCurrentState; end; ServiceClose(hService2); end; Result := dwStat; end; {判断某服务是否安装,未安装返回true,已安装返回false} function TServiceMan.ServiceUninstalled(hService:SC_HANDLE; AServName:PChar):Boolean; begin Result := 0 = ServiceGetStatus(hService, AServName); end; {判断某服务是否启动,启动返回true,未启动返回false} function TServiceMan.ServiceRunning(hService:SC_HANDLE; AServName:PChar):Boolean; begin Result := SERVICE_RUNNING = ServiceGetStatus(hService, AServName); end; {判断某服务是否停止,停止返回true,未停止返回false} function TServiceMan.ServiceStopped(hService:SC_HANDLE; AServName:PChar):Boolean; begin Result := SERVICE_STOPPED = ServiceGetStatus(hService, AServName); end; end.