编写软件动态加载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

相关文章

第10章 中断和动态时钟显示

第10章 中断和动态时钟显示 从本章开始,按照书籍的划分,第10章开始就进入保护模式(Protected Mode)部分了,感觉从这里开始难度突然就增加了。 书中介绍了为什么有中断(Interrupt)的设计,中断的几种方式:外部硬件中断、内部中断和软中断。通过中断做了一个会走的时钟和屏幕上输入字符的程序。 我自己理解中断的一些作用: 为了更好的利用处理器的性能。协同快速和慢速设备一起工作

动态规划---打家劫舍

题目: 你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。 给定一个代表每个房屋存放金额的非负整数数组,计算你 不触动警报装置的情况下 ,一夜之内能够偷窃到的最高金额。 思路: 动态规划五部曲: 1.确定dp数组及含义 dp数组是一维数组,dp[i]代表

软件设计师备考——计算机系统

学习内容源自「软件设计师」 上午题 #1 计算机系统_哔哩哔哩_bilibili 目录 1.1.1 计算机系统硬件基本组成 1.1.2 中央处理单元 1.CPU 的功能 1)运算器 2)控制器 RISC && CISC 流水线控制 存储器  Cache 中断 输入输出IO控制方式 程序查询方式 中断驱动方式 直接存储器方式(DMA)  ​编辑 总线 ​编辑

Linux_kernel驱动开发11

一、改回nfs方式挂载根文件系统         在产品将要上线之前,需要制作不同类型格式的根文件系统         在产品研发阶段,我们还是需要使用nfs的方式挂载根文件系统         优点:可以直接在上位机中修改文件系统内容,延长EMMC的寿命         【1】重启上位机nfs服务         sudo service nfs-kernel-server resta

Flutter 进阶:绘制加载动画

绘制加载动画:由小圆组成的大圆 1. 定义 LoadingScreen 类2. 实现 _LoadingScreenState 类3. 定义 LoadingPainter 类4. 总结 实现加载动画 我们需要定义两个类:LoadingScreen 和 LoadingPainter。LoadingScreen 负责控制动画的状态,而 LoadingPainter 则负责绘制动画。

【STM32】SPI通信-软件与硬件读写SPI

SPI通信-软件与硬件读写SPI 软件SPI一、SPI通信协议1、SPI通信2、硬件电路3、移位示意图4、SPI时序基本单元(1)开始通信和结束通信(2)模式0---用的最多(3)模式1(4)模式2(5)模式3 5、SPI时序(1)写使能(2)指定地址写(3)指定地址读 二、W25Q64模块介绍1、W25Q64简介2、硬件电路3、W25Q64框图4、Flash操作注意事项软件SPI读写W2

代码随想录冲冲冲 Day39 动态规划Part7

198. 打家劫舍 dp数组的意义是在第i位的时候偷的最大钱数是多少 如果nums的size为0 总价值当然就是0 如果nums的size为1 总价值是nums[0] 遍历顺序就是从小到大遍历 之后是递推公式 对于dp[i]的最大价值来说有两种可能 1.偷第i个 那么最大价值就是dp[i-2]+nums[i] 2.不偷第i个 那么价值就是dp[i-1] 之后取这两个的最大值就是d

如何编写Linux PCIe设备驱动器 之二

如何编写Linux PCIe设备驱动器 之二 功能(capability)集功能(capability)APIs通过pci_bus_read_config完成功能存取功能APIs参数pos常量值PCI功能结构 PCI功能IDMSI功能电源功率管理功能 功能(capability)集 功能(capability)APIs int pcie_capability_read_wo

免费也能高质量!2024年免费录屏软件深度对比评测

我公司因为客户覆盖面广的原因经常会开远程会议,有时候说的内容比较广需要引用多份的数据,我记录起来有一定难度,所以一般都用录屏工具来记录会议内容。这次我们来一起探索有什么免费录屏工具可以提高我们的工作效率吧。 1.福晰录屏大师 链接直达:https://www.foxitsoftware.cn/REC/  录屏软件录屏功能就是本职,这款录屏工具在录屏模式上提供了多种选项,可以选择屏幕录制、窗口

HomeBank:开源免费的个人财务管理软件

在个人财务管理领域,找到一个既免费又开源的解决方案并非易事。HomeBank&nbsp;正是这样一个项目,它不仅提供了强大的功能,还拥有一个活跃的社区,不断推动其发展和完善。 开源免费:HomeBank 是一个完全开源的项目,用户可以自由地使用、修改和分发。用户友好的界面:提供直观的图形用户界面,使得非技术用户也能轻松上手。数据导入支持:支持从 Quicken、Microsoft Money