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

相关文章

前端 CSS 动态设置样式::class、:style 等技巧(推荐)

《前端CSS动态设置样式::class、:style等技巧(推荐)》:本文主要介绍了Vue.js中动态绑定类名和内联样式的两种方法:对象语法和数组语法,通过对象语法,可以根据条件动态切换类名或样式;通过数组语法,可以同时绑定多个类名或样式,此外,还可以结合计算属性来生成复杂的类名或样式对象,详细内容请阅读本文,希望能对你有所帮助...

Nginx实现动态封禁IP的步骤指南

《Nginx实现动态封禁IP的步骤指南》在日常的生产环境中,网站可能会遭遇恶意请求、DDoS攻击或其他有害的访问行为,为了应对这些情况,动态封禁IP是一项十分重要的安全策略,本篇博客将介绍如何通过NG... 目录1、简述2、实现方式3、使用 fail2ban 动态封禁3.1 安装 fail2ban3.2 配

Vue3中的动态组件详解

《Vue3中的动态组件详解》本文介绍了Vue3中的动态组件,通过`component:is=动态组件名或组件对象/component`来实现根据条件动态渲染不同的组件,此外,还提到了使用`markRa... 目录vue3动态组件动态组件的基本使用第一种写法第二种写法性能优化解决方法总结Vue3动态组件动态

spring-boot-starter-thymeleaf加载外部html文件方式

《spring-boot-starter-thymeleaf加载外部html文件方式》本文介绍了在SpringMVC中使用Thymeleaf模板引擎加载外部HTML文件的方法,以及在SpringBoo... 目录1.Thymeleaf介绍2.springboot使用thymeleaf2.1.引入spring

Android 悬浮窗开发示例((动态权限请求 | 前台服务和通知 | 悬浮窗创建 )

《Android悬浮窗开发示例((动态权限请求|前台服务和通知|悬浮窗创建)》本文介绍了Android悬浮窗的实现效果,包括动态权限请求、前台服务和通知的使用,悬浮窗权限需要动态申请并引导... 目录一、悬浮窗 动态权限请求1、动态请求权限2、悬浮窗权限说明3、检查动态权限4、申请动态权限5、权限设置完毕后

关于Spring @Bean 相同加载顺序不同结果不同的问题记录

《关于Spring@Bean相同加载顺序不同结果不同的问题记录》本文主要探讨了在Spring5.1.3.RELEASE版本下,当有两个全注解类定义相同类型的Bean时,由于加载顺序不同,最终生成的... 目录问题说明测试输出1测试输出2@Bean注解的BeanDefiChina编程nition加入时机总结问题说明

Java使用POI-TL和JFreeChart动态生成Word报告

《Java使用POI-TL和JFreeChart动态生成Word报告》本文介绍了使用POI-TL和JFreeChart生成包含动态数据和图表的Word报告的方法,并分享了实际开发中的踩坑经验,通过代码... 目录前言一、需求背景二、方案分析三、 POI-TL + JFreeChart 实现3.1 Maven

Java导出Excel动态表头的示例详解

《Java导出Excel动态表头的示例详解》这篇文章主要为大家详细介绍了Java导出Excel动态表头的相关知识,文中的示例代码简洁易懂,具有一定的借鉴价值,有需要的小伙伴可以了解下... 目录前言一、效果展示二、代码实现1.固定头实体类2.动态头实现3.导出动态头前言本文只记录大致思路以及做法,代码不进

vue基于ElementUI动态设置表格高度的3种方法

《vue基于ElementUI动态设置表格高度的3种方法》ElementUI+vue动态设置表格高度的几种方法,抛砖引玉,还有其它方法动态设置表格高度,大家可以开动脑筋... 方法一、css + js的形式这个方法需要在表格外层设置一个div,原理是将表格的高度设置成外层div的高度,所以外层的div需要

SpringBoot实现动态插拔的AOP的完整案例

《SpringBoot实现动态插拔的AOP的完整案例》在现代软件开发中,面向切面编程(AOP)是一种非常重要的技术,能够有效实现日志记录、安全控制、性能监控等横切关注点的分离,在传统的AOP实现中,切... 目录引言一、AOP 概述1.1 什么是 AOP1.2 AOP 的典型应用场景1.3 为什么需要动态插