今天顺便再解决一下应用层加载卸载驱动的方式。

加载驱动

加载驱动过程

  1. 用OpenSCManager打开服务控制管理器
  2. 用CreateService创建对应服务
  3. 如果驱动服务已经创建过,则用OpenService打开服务
  4. 用StartService加载启动驱动服务
  5. 清理工作,用CloseServiceHandle关闭释放句柄

一个一个介绍一下每一步的详细步骤吧

打开服务控制管理器

使用如下代码获得一个SCM管理器的句柄。

1
SC_HANDLE hServiceMgr = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
  • 第一个参数是目标计算机的名称。 如果指针为 NULL 或指向空字符串,则该函数将连接到本地计算机上的服务控制管理器。
  • 第二个参数是服务控制管理器数据库的名称。 此参数应设置为SERVICES_ACTIVE_DATABASE。 如果为 NULL,则默认打开SERVICES_ACTIVE_DATABASE数据库。
  • 第三个参数是我们获得句柄的权限,SC_MANAGER_ALL_ACCESS 表示获得所有权限。

创建服务

使用如下代码去创建服务,获得该服务的管理句柄:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
hServiceDDK = CreateServiceA(
hServiceMgr,//manager管理句柄
DriverName,//驱动程序的在注册表中的名字
DriverName,//注册表驱动程序的DisplayName值
SERVICE_START,//加载驱动程序的访问权限 SERVICE_START 或者 SERVICE_ALL-ACCESS
SERVICE_KERNEL_DRIVER,//表示加载的服务是驱动程序
SERVICE_DEMAND_START,//注册表驱动程序的Start值
SERVICE_ERROR_NORMAL,//SERVICE_ERROR_IGNORE,//注册表驱动程序的ErrorControl值//指定当进程调用StartService函数时由服务控制管理器启动的服务。
FullPath,//sys完整路径
NULL,
NULL,
NULL,
NULL,
NULL
);

具体参数表示的意思已经标明。

如果已经存在,则打开服务

我们需要判断此服务是否被创建过了,如果创建过了则 GetLastError 会返回一个 ERROR_SERVICE_EXISTS。

1
2
3
4
if (GetLastError() == ERROR_SERVICE_EXISTS) {
printf("Service Already Exists\n");
hServiceDDK = OpenServiceA(hServiceMgr, DriverName, SERVICE_START);
}

用StartService加载启动驱动服务

直接启动:

1
int bRet = StartService(hServiceDDK, NULL, NULL);

如果返回 1,则成功,如果为 0 则表示失败。

完整代码形式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
#include <iostream>
#include <winsvc.h>
void LoadDriver(const char * DriverName, const char * DriverPath) {
char FullPath[256] = { 0 };
GetFullPathNameA(DriverPath, 256, FullPath, NULL);
SC_HANDLE hServiceMgr = NULL;//SCM管理器的句柄
SC_HANDLE hServiceDDK = NULL;//NT驱动程序的服务句柄
hServiceMgr = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
printf("Open SCM handle=%p,GetLastError=%p\n", hServiceMgr, GetLastError());
hServiceDDK = CreateServiceA(
hServiceMgr,
DriverName,//驱动程序的在注册表中的名字
DriverName,//注册表驱动程序的DisplayName值
SERVICE_START,//加载驱动程序的访问权限 SERVICE_START 或者 SERVICE_ALL-ACCESS
SERVICE_KERNEL_DRIVER,//表示加载的服务是驱动程序
SERVICE_DEMAND_START,//注册表驱动程序的Start值
SERVICE_ERROR_NORMAL,//SERVICE_ERROR_IGNORE,//注册表驱动程序的ErrorControl值//指定当进程调用StartService函数时由服务控制管理器启动的服务。
FullPath,//szDriverImagePath注册表驱动程序的路径如:C:\\222\1.sys
NULL,//GroupOrder HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\GroupOrderList
NULL,
NULL,
NULL,
NULL
);

if (GetLastError() == ERROR_SERVICE_EXISTS) {
printf("Service Already Exists\n");
hServiceDDK = OpenServiceA(hServiceMgr, DriverName, SERVICE_START);
}
printf("hServiceDDK=%p\n", hServiceDDK);
int bRet = StartService(hServiceDDK, NULL, NULL);
if (GetLastError() == ERROR_SERVICE_ALREADY_RUNNING) {
printf("Service Already Running\n");
}
else {
if (bRet == 0) {
printf("Service Running Failed\n");
}
else {
printf("Service Start Success\n");
}
}
}

int main()
{
LoadDriver("xia0ji233", ".\\KMDFDriver2.sys");
}

卸载驱动

大概步骤是这样的:

  1. 获取服务控制管理器句柄
  2. OpenService 打开加载中的服务获取服务句柄
  3. ControlService 停止服务
  4. DeleteService 删除服务

同样也是一步步讲解——

获取服务控制管理器句柄

一样的。

打开服务句柄

跟上面那个,如果服务存在,则打开服务,一样的操作,但是这里需要获取 ALL_ACCESS 的权限

1
hServiceDDK = OpenServiceA(hServiceMgr, ServeName, SERVICE_ALL_ACCESS);

停止服务

用 ControlService API 去先去停止服务。

1
2
3
int bRet = 0;
SERVICE_STATUS status;
bRet = ControlService(hServiceDDK, SERVICE_CONTROL_STOP, &status);

删除服务

最后调用 DeleteService 去删除服务。

1
bRet=DeleteService(hServiceDDK);

大概就是这样的一个过程还挺简单的,加载驱动和卸载驱动都没有特别难。

代码汇总

以下是一个加载驱动和卸载驱动一体的代码,中间相隔 System pause,这里输入一个回车可以直接卸载驱动,用于快速加载驱动,然后再处理一下报错信息就可以了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
#include <iostream>
#include <winsvc.h>
void LoadDriver(const char * ServeName, const char * DriverPath) {
char FullPath[256] = { 0 };
GetFullPathNameA(DriverPath, 256, FullPath, NULL);
SC_HANDLE hServiceMgr = NULL;//SCM管理器的句柄
SC_HANDLE hServiceDDK = NULL;//NT驱动程序的服务句柄
hServiceMgr = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
printf("Open SCM handle=%p,GetLastError=%p\n", hServiceMgr, GetLastError());
hServiceDDK = CreateServiceA(
hServiceMgr,
ServeName,//驱动程序的在注册表中的名字
ServeName,//注册表驱动程序的DisplayName值
SERVICE_START,//加载驱动程序的访问权限 SERVICE_START 或者 SERVICE_ALL-ACCESS
SERVICE_KERNEL_DRIVER,//表示加载的服务是驱动程序
SERVICE_DEMAND_START,//注册表驱动程序的Start值
SERVICE_ERROR_NORMAL,//SERVICE_ERROR_IGNORE,//注册表驱动程序的ErrorControl值//指定当进程调用StartService函数时由服务控制管理器启动的服务。
FullPath,//szDriverImagePath注册表驱动程序的路径如:C:\\222\1.sys
NULL,//GroupOrder HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\GroupOrderList
NULL,
NULL,
NULL,
NULL
);



if (GetLastError() == ERROR_SERVICE_EXISTS) {
printf("Service Already Exists\n");
hServiceDDK = OpenServiceA(hServiceMgr, ServeName, SERVICE_START);
}
else if (GetLastError() != 0) {
printf("GetLastError=%p\n", GetLastError());

return;
}
printf("hServiceDDK=%p\n", hServiceDDK);
int bRet = StartService(hServiceDDK, NULL, NULL);
if (GetLastError() == ERROR_SERVICE_ALREADY_RUNNING) {
printf("Service Already Running\n");
}
else {
if (bRet == 0) {
printf("Service Running Failed\n");
printf("GetLastError=%p\n", GetLastError());
}
else {
printf("Service Start Success\n");
}
}
}
void UnloadDriver(const char *ServeName) {
SC_HANDLE hServiceMgr = NULL;//SCM管理器的句柄
SC_HANDLE hServiceDDK = NULL;//NT驱动程序的服务句柄
hServiceMgr = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
printf("Open SCM handle=%p,GetLastError=%p\n", hServiceMgr, GetLastError());
hServiceDDK = OpenServiceA(hServiceMgr, ServeName, SERVICE_ALL_ACCESS);
if (hServiceDDK) {
int bRet = 0;
SERVICE_STATUS status;
bRet = ControlService(hServiceDDK, SERVICE_CONTROL_STOP, &status);
if (bRet) {
puts("Stop Service Success");
}
else {
puts("Can't Stop Service");
goto GETLASTERROR;
}
bRet=DeleteService(hServiceDDK);
if (bRet) {
puts("Unload Success");
}
else {
puts("Unload Fail");
}
GETLASTERROR:
printf("GetLastError=%p\n", GetLastError());
}
else {
printf("OpenServe Failed\n");
}
}
int main()
{
LoadDriver("xia0ji233", ".\\KMDFDriver2.sys");
system("pause");
UnloadDriver("xia0ji233");
}

运行结果: