编写软件动态加载NT式驱动

2024-03-07 00:08

本文主要是介绍编写软件动态加载NT式驱动,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

NT式设备驱动程序的动态加载主要是由服务控制管理程序(Service Control Manager,即SCM)系统组件来完成的。

        Windwos服务可以在系统启动时加载,用户也可以按需在服务控制平台开启或者关闭服务。程序员可以通过Windows提供的相关服务函数进行加载或者卸载该服务等。服务程序更是可以在用户还没有登录系统的时候,就载入系统并且被执行。


加载NT驱动一般分为4个步骤:

1.    调用OpenSCManager打开SCM管理器;

2.    调用CreateService创建服务;如果存在则调用OpenService打开服务(可根据GetLastError判断);

3.    调用StartService开启服务;

4.    关闭句柄。

 

卸载NT驱动一般分为5个步骤:

1.    调用OpenSCManager打开SCM管理器;

2.    调用OpenService打开此项服务;

3.    调用ControlService传递SERVICE_CONTROL_STOP来停止服务

4.    调用DeleteService卸载此项服务;

5.    关闭句柄。

注意:DeleteService只是标记一下该项服务需要删除,只有停止了服务并且关闭了打开服务的句柄,改服务才会被正式卸载。

 

打开SCM管理器函数


SC_HANDLE WINAPI OpenSCManager(__in          LPCTSTR lpMachineName,	//计算机名称__in          LPCTSTR lpDatabaseName,	//SCM数据库名称__in          DWORD dwDesiredAccess	//使用权限
);

说明

函数建立了一个连接到服务控制管理器,并打开指定的数据库。

参数

lpMachineName

指向零终止字符串,命名为目标计算机。如果该指针为NULL ,或者如果它指向一个空字符串,函数连接到服务控制管理器在本地计算机上。

lpDatabaseName

指向零终止字符串,名称的服务控制管理数据库,以开放。此字符串应指定ServicesActive 。如果该指针为NULL ,该ServicesActive数据库默认情况下打开。

dwDesiredAccess

指定服务的访问控制管理。才准予进入的要求,系统会检查访问令牌的调用进程对任意访问控制列表的安全描述符与服务控制管理器对象。访问类型的SC_MANAGER_CONNECT是含蓄地指明调用这个函数。此外,任何或所有下列服务控制管理器对象的访问类型可以指定:

SC_MANAGER_ALL_ACCESS

包括STANDARD_RIGHTS_REQUIRED ,除了所有类型的访问此表中列出。

SC_MANAGER_CONNECT

可以连接到服务控制管理器。

SC_MANAGER_CREATE_SERVICE

使要求的CreateService函数创建一个服务对象,并将其添加到数据库中。

SC_MANAGER_ENUMERATE_SERVICE

使要求的EnumServicesStatus功能清单的服务,这是在数据库中。

SC_MANAGER_LOCK

使要求的LockServiceDatabase功能获得锁定数据库。

SC_MANAGER_QUERY_LOCK_STATUS

使要求的QueryServiceLockStatus检索功能锁定状态信息的数据库。

返回值

如果函数成功,返回值是一个句柄指定的服务控制管理器数据库。如果函数失败,返回值为NULL 。要获得扩展错误信息,请使用GetLastError 获得错误代码。

 

关闭服务句柄


BOOL WINAPI CloseHandle(__in          HANDLE hObject		//要关闭的句柄
);

hObjece

对象句柄,即使用OpenSCManager或者CreateService、OpenService返回的句柄。

 

创建服务

创建一个服务对象并且把它加入到服务管理数据库中。

SC_HANDLE WINAPI CreateService(__in          SC_HANDLE hSCManager,		//SCM管理器的句柄__in          LPCTSTR lpServiceName,		//服务名称__in          LPCTSTR lpDisplayName,		//服务显示名称__in          DWORD dwDesiredAccess,		//访问权限__in          DWORD dwServiceType,		//服务类型__in          DWORD dwStartType,		//启动类型__in          DWORD dwErrorControl,		//关于错误处理的代码__in          LPCTSTR lpBinaryPathName,	//二进制文件的代码__in          LPCTSTR lpLoadOrderGroup,	//在加载顺序此服务所属的组的名称__out         LPDWORD lpdwTagId,		//输出验证标签__in          LPCTSTR lpDependencies,	//所依赖的服务名称__in          LPCTSTR lpServiceStartName,	//用户账号名称__in          LPCTSTR lpPassword		//用户口令
);

参数

hSCManager

服务控制管理器数据库的句柄。 此句柄由OpenSCManager函数返回,并且必须具有SC_MANAGER_CREATE_SERVICE 的访问权限。

lpServiceName

要安装该服务的名称。 最大字符串长度为 256 个字符。 服务控制管理器数据库将保留字符的大小写,但是服务名称比较总是区分大小写。 正斜杠和一个反斜线不是有效的服务名称字符。

lpDisplayName

对被用户界面程序用来识别服务的显示名称。 此字符串具有最大长度为 256 个字符。 服务控制管理器中的情况下保留名称。 显示名称比较总是不区分大小写。

dwDesiredAccess

对服务的访问权限。请求的访问之前,系统将检查调用进程的访问令牌。如果没有特殊要求,一般设置为SERVICE_ALL_ACCESS (0xF01FF)

 dwServiceType服务类型。一般选择以下两种:

Value

Meaning

SERVICE_FILE_SYSTEM_DRIVER
0x00000002

文件系统的驱动

SERVICE_KERNEL_DRIVER
0x00000001

普通程序的驱动,一般使用此项。

dwStartType

服务启动选项,亦即打开服务的时间,有以下几种选择:

Value

Meaning

SERVICE_AUTO_START
0x00000002

系统启动时由服务控制管理器自动启动该服务程序。

SERVICE_BOOT_START
0x00000000

用于由系统加载器创建的设备驱动程序。

只能用于驱动服务程序。

SERVICE_DEMAND_START
0x00000003

由服务控制管理器(SCM)启动的服务,即手动启动。

SERVICE_DISABLED
0x00000004

表示该服务不可启动。

SERVICE_SYSTEM_START
0x00000001

用于由IoInitSystem函数创建的设备驱动程序。

 

dwErrorControl当该启动服务失败时产生错误的严重程度以及采取的保护措施。此参数可以是下列值之一:

Value

Meaning

SERVICE_ERROR_CRITICAL
0x00000003

服务启动程序将把该错误记录到事件日志中

SERVICE_ERROR_IGNORE
0x00000000

服务启动程序将忽略该错误并返回继续执行

SERVICE_ERROR_NORMAL
0x00000001

服务启动程序将把该错误记录到事件日志中并返回继续执行

SERVICE_ERROR_SEVERE
0x00000002

服务启动程序将把该错误记录到事件日志中。

否则将返回继续执行。

lpBinaryPathName

服务所用的二进制文件,也就是编译后的驱动程序。 如果路径中包含空格它必须被引用,以便它正确的解析。

 例如"d:\myshare\myservice.exe"应指定为""d:\myshare\myservice.exe""。该路径也可以包含一个自动启动服务的参数。

例如"d:\myshare\myservice.exearg1 arg2"。 这些参数被传递给服务的入口点通常主要作用。

 

打开服务

此函数针对已经创建过的服务,再次打开此项服务。

SC_HANDLE WINAPI OpenService(__in          SC_HANDLE hSCManager,		//SCM管理器的句柄__in          LPCTSTR lpServiceName,		//服务名称__in          DWORD dwDesiredAccess		//访问权限

hSCManager

SCM管理器的句柄,即OpenSCManager打开的句柄。

lpSeviceName

已经创建的服务名称。

dwDesiredAccess

访问权限。如果没有特殊情况,一般使用SERVICE_ALL_ACCESS(0xF01FF)

 

控制服务

发送一个控制码去指定的服务,根据不同的控制码操作服务。

BOOL WINAPI ControlService(__in          SC_HANDLE hService, 	//服务的句柄__in          DWORD dwControl, 	//发送的控制码__out         LPSERVICE_STATUS lpServiceStatus 	//接收之前的服务状态信息
);

hService

服务的句柄,即用CreateService创建或者使用OpenService打开的句柄。

dwControl

发送给服务的控制码,常用的有以下几种:

Control code

Meaning

SERVICE_CONTROL_CONTINUE
0x00000003

针对暂停的服务发出继续运行的指令。

SERVICE_CONTROL_PAUSE
0x00000002

暂停正在运行中的服务。

SERVICE_CONTROL_STOP
0x00000001

停止正在运行的服务。

lpServiceStatus

用于接收之前的服务状态信息。

 

删除服务

标记删除一个指定的服务。

BOOL WINAPI DeleteService(__in          SC_HANDLE hService	//服务句柄
);

注意:必须停止服务并且关闭服务句柄后,服务才会被删除。



完整代码


// LoadNtDriver.cpp : 定义控制台应用程序的入口点。
//#include "stdafx.h"
#include <Windows.h>
#include "string.h"
#include "locale.h"BOOL LoadNTDriver(TCHAR * lpszDriverName,TCHAR * lpszDriverPath)
{TCHAR szDriverPath[256] = {0};_tprintf(_T("加载驱动...\n"));//获取完整的驱动路径GetFullPathName(lpszDriverPath,sizeof(szDriverPath)/sizeof(szDriverPath[0]),szDriverPath,NULL);
//	_tprintf(szDriverPath);SC_HANDLE hSCM = NULL;SC_HANDLE hServie = NULL;hSCM = OpenSCManager(NULL,NULL,SC_MANAGER_ALL_ACCESS);if (!hSCM){_tprintf(_T("OpenSCManger 失败!,错误代码:%d\n"),GetLastError());return FALSE;}else{_tprintf(_T("OpenSCManger 成功!\n"));hServie = CreateService(hSCM,	lpszDriverName,				//服务的名称lpszDriverName,				//显示的名称DisplayNameSERVICE_ALL_ACCESS,			//访问所有权SERVICE_KERNEL_DRIVER,		//表示加载的服务是驱动程序SERVICE_DEMAND_START,		//启动类型为手动启动SERVICE_ERROR_IGNORE,		//忽略错误szDriverPath,				//驱动文件名(保护路径),注册表中的ImagePath值NULL,NULL,NULL,NULL,NULL);if (!hServie){_tprintf(_T("CreateService 失败!,错误代码:%d,尝试使用OpenService\n"),GetLastError());hServie = OpenService(hSCM,lpszDriverName,SERVICE_ALL_ACCESS);if (!hServie){	_tprintf(_T("OpenService 失败!,错误代码:%d\n"),GetLastError());//清理CloseServiceHandle(hSCM);return FALSE;}else{_tprintf(_T("OpenService 成功!\n"));}}else_tprintf(_T("CreateService 成功!\n"));//打开或创建服务成功后,开启服务BOOL bRet = StartService(hServie,NULL,NULL);if (!bRet){_tprintf(_T("StartService 失败!,错误代码:%d\n"),GetLastError());bRet = FALSE;}else{bRet = TRUE;_tprintf(_T("加载驱动...成功!\n"));}//先关掉服务句柄,再关掉服务管理器句柄if (hServie){CloseServiceHandle(hServie);}if (hSCM){CloseServiceHandle(hSCM);}return bRet;} // hSCM}BOOL UnloadNTDriver(TCHAR * szSvrName)
{SC_HANDLE hSCM = NULL;		//SCMangerSC_HANDLE hService = NULL;_tprintf(_T("卸载驱动...\n"));hSCM = OpenSCManager(NULL,NULL,SC_MANAGER_ALL_ACCESS);if (!hSCM) //打开失败{_tprintf(_T("OpenSCManger 失败!,错误代码:%d\n"),GetLastError());return FALSE;}else{_tprintf(_T("OpenSCManager 成功!\n"));hService = OpenService(hSCM,szSvrName,SERVICE_ALL_ACCESS);if (!hService) //打开服务失败{_tprintf(_T("OpenService 失败,错误代码:%d\n"),GetLastError());CloseServiceHandle(hSCM);return FALSE;}else{_tprintf(_T("OpenService 成功!\n"));SERVICE_STATUS SvrSta = {0};//停止服务。停止服务后,服务才能完成卸载。if (!ControlService(hService,SERVICE_CONTROL_STOP,&SvrSta)){_tprintf(_T("停止服务 失败,错误代码:%d\n"),GetLastError());}else{_tprintf(_T("停止服务 成功!\n"));}BOOL bRet = FALSE;//动态卸载服务bRet = DeleteService(hService);if (!bRet){//卸载失败_tprintf(_T("DeleteService 失败,错误代码:%d\n"),GetLastError());}else{//卸载成功_tprintf(_T("DeleteService 成功!\n"));_tprintf(_T("卸载驱动...成功!\n"));}//清理if (hService){CloseServiceHandle(hService);}if (hSCM){CloseServiceHandle(hSCM);}return bRet;} // hService}
}int _tmain(int argc, _TCHAR* argv[])
{TCHAR szDriverPath[256];TCHAR szDriverName[25];setlocale(LC_ALL, "chs");//需要实现本地化,以实现中文正常输出_tcscpy_s(szDriverPath,sizeof(szDriverPath)/sizeof(szDriverPath[0]),_T("Driver.sys"));_tcscpy_s(szDriverName,sizeof(szDriverPath)/sizeof(szDriverPath[0]),_T("TestDDK"));BOOL bRet = LoadNTDriver(szDriverName,szDriverPath);if (bRet){printf("输入任意键来卸载驱动程序.\n");getchar();UnloadNTDriver(szDriverName);}else_tprintf(_T("加载驱动...失败!\n"));getchar();return 0;
}

【结果】

加载:

   


卸载: 
   

这篇关于编写软件动态加载NT式驱动的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/781811

相关文章

利用Python编写一个简单的聊天机器人

《利用Python编写一个简单的聊天机器人》这篇文章主要为大家详细介绍了如何利用Python编写一个简单的聊天机器人,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 使用 python 编写一个简单的聊天机器人可以从最基础的逻辑开始,然后逐步加入更复杂的功能。这里我们将先实现一个简单的

SpringBoot项目启动后自动加载系统配置的多种实现方式

《SpringBoot项目启动后自动加载系统配置的多种实现方式》:本文主要介绍SpringBoot项目启动后自动加载系统配置的多种实现方式,并通过代码示例讲解的非常详细,对大家的学习或工作有一定的... 目录1. 使用 CommandLineRunner实现方式:2. 使用 ApplicationRunne

VUE动态绑定class类的三种常用方式及适用场景详解

《VUE动态绑定class类的三种常用方式及适用场景详解》文章介绍了在实际开发中动态绑定class的三种常见情况及其解决方案,包括根据不同的返回值渲染不同的class样式、给模块添加基础样式以及根据设... 目录前言1.动态选择class样式(对象添加:情景一)2.动态添加一个class样式(字符串添加:情

使用PyQt5编写一个简单的取色器

《使用PyQt5编写一个简单的取色器》:本文主要介绍PyQt5搭建的一个取色器,一共写了两款应用,一款使用快捷键捕获鼠标附近图像的RGB和16进制颜色编码,一款跟随鼠标刷新图像的RGB和16... 目录取色器1取色器2PyQt5搭建的一个取色器,一共写了两款应用,一款使用快捷键捕获鼠标附近图像的RGB和16

SpringBoot项目删除Bean或者不加载Bean的问题解决

《SpringBoot项目删除Bean或者不加载Bean的问题解决》文章介绍了在SpringBoot项目中如何使用@ComponentScan注解和自定义过滤器实现不加载某些Bean的方法,本文通过实... 使用@ComponentScan注解中的@ComponentScan.Filter标记不加载。@C

springboot 加载本地jar到maven的实现方法

《springboot加载本地jar到maven的实现方法》如何在SpringBoot项目中加载本地jar到Maven本地仓库,使用Maven的install-file目标来实现,本文结合实例代码给... 在Spring Boothttp://www.chinasem.cn项目中,如果你想要加载一个本地的ja

SpringCloud配置动态更新原理解析

《SpringCloud配置动态更新原理解析》在微服务架构的浩瀚星海中,服务配置的动态更新如同魔法一般,能够让应用在不重启的情况下,实时响应配置的变更,SpringCloud作为微服务架构中的佼佼者,... 目录一、SpringBoot、Cloud配置的读取二、SpringCloud配置动态刷新三、更新@R

最好用的WPF加载动画功能

《最好用的WPF加载动画功能》当开发应用程序时,提供良好的用户体验(UX)是至关重要的,加载动画作为一种有效的沟通工具,它不仅能告知用户系统正在工作,还能够通过视觉上的吸引力来增强整体用户体验,本文给... 目录前言需求分析高级用法综合案例总结最后前言当开发应用程序时,提供良好的用户体验(UX)是至关重要

Ubuntu 怎么启用 Universe 和 Multiverse 软件源?

《Ubuntu怎么启用Universe和Multiverse软件源?》在Ubuntu中,软件源是用于获取和安装软件的服务器,通过设置和管理软件源,您可以确保系统能够从可靠的来源获取最新的软件... Ubuntu 是一款广受认可且声誉良好的开源操作系统,允许用户通过其庞大的软件包来定制和增强计算体验。这些软件

如何用Python绘制简易动态圣诞树

《如何用Python绘制简易动态圣诞树》这篇文章主要给大家介绍了关于如何用Python绘制简易动态圣诞树,文中讲解了如何通过编写代码来实现特定的效果,包括代码的编写技巧和效果的展示,需要的朋友可以参考... 目录代码:效果:总结 代码:import randomimport timefrom math