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

相关文章

springboot加载不到nacos配置中心的配置问题处理

《springboot加载不到nacos配置中心的配置问题处理》:本文主要介绍springboot加载不到nacos配置中心的配置问题处理,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑... 目录springboot加载不到nacos配置中心的配置两种可能Spring Boot 版本Nacos

安装centos8设置基础软件仓库时出错的解决方案

《安装centos8设置基础软件仓库时出错的解决方案》:本文主要介绍安装centos8设置基础软件仓库时出错的解决方案,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐... 目录安装Centos8设置基础软件仓库时出错版本 8版本 8.2.200android4版本 javas

python编写朋克风格的天气查询程序

《python编写朋克风格的天气查询程序》这篇文章主要为大家详细介绍了一个基于Python的桌面应用程序,使用了tkinter库来创建图形用户界面并通过requests库调用Open-MeteoAPI... 目录工具介绍工具使用说明python脚本内容如何运行脚本工具介绍这个天气查询工具是一个基于 Pyt

Java调用C#动态库的三种方法详解

《Java调用C#动态库的三种方法详解》在这个多语言编程的时代,Java和C#就像两位才华横溢的舞者,各自在不同的舞台上展现着独特的魅力,然而,当它们携手合作时,又会碰撞出怎样绚丽的火花呢?今天,我们... 目录方法1:C++/CLI搭建桥梁——Java ↔ C# 的“翻译官”步骤1:创建C#类库(.NET

MyBatis编写嵌套子查询的动态SQL实践详解

《MyBatis编写嵌套子查询的动态SQL实践详解》在Java生态中,MyBatis作为一款优秀的ORM框架,广泛应用于数据库操作,本文将深入探讨如何在MyBatis中编写嵌套子查询的动态SQL,并结... 目录一、Myhttp://www.chinasem.cnBATis动态SQL的核心优势1. 灵活性与可

如何确定哪些软件是Mac系统自带的? Mac系统内置应用查看技巧

《如何确定哪些软件是Mac系统自带的?Mac系统内置应用查看技巧》如何确定哪些软件是Mac系统自带的?mac系统中有很多自带的应用,想要看看哪些是系统自带,该怎么查看呢?下面我们就来看看Mac系统内... 在MAC电脑上,可以使用以下方法来确定哪些软件是系统自带的:1.应用程序文件夹打开应用程序文件夹

Mybatis嵌套子查询动态SQL编写实践

《Mybatis嵌套子查询动态SQL编写实践》:本文主要介绍Mybatis嵌套子查询动态SQL编写方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录前言一、实体类1、主类2、子类二、Mapper三、XML四、详解总结前言MyBATis的xml文件编写动态SQL

使用Python获取JS加载的数据的多种实现方法

《使用Python获取JS加载的数据的多种实现方法》在当今的互联网时代,网页数据的动态加载已经成为一种常见的技术手段,许多现代网站通过JavaScript(JS)动态加载内容,这使得传统的静态网页爬取... 目录引言一、动态 网页与js加载数据的原理二、python爬取JS加载数据的方法(一)分析网络请求1

SpringBoot实现Kafka动态反序列化的完整代码

《SpringBoot实现Kafka动态反序列化的完整代码》在分布式系统中,Kafka作为高吞吐量的消息队列,常常需要处理来自不同主题(Topic)的异构数据,不同的业务场景可能要求对同一消费者组内的... 目录引言一、问题背景1.1 动态反序列化的需求1.2 常见问题二、动态反序列化的核心方案2.1 ht

golang实现动态路由的项目实践

《golang实现动态路由的项目实践》本文主要介绍了golang实现动态路由项目实践,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习... 目录一、动态路由1.结构体(数据库的定义)2.预加载preload3.添加关联的方法一、动态路由1