当前位置: 首页 > news >正文

Windows驱动开发(二)

1. NT和WDM式驱动

1. NT式驱动

传统的Windows系统驱动类型。NT式驱动的启动/停止/安装/卸载只能由 服务控制管理程序组件(SCM) 来完成的。
包括最简单的hello world,以及目前常用的文件过滤框架 minifilter 都是基于NT式实现的。
NT式驱动的最大特点即完全不依赖硬件支持即可工作在内核模式中。

VOID FilterUnload(PDRIVER_OBJECT DriverObject) {UNREFERENCED_PARAMETER(DriverObject);
}VOID Initialize(PDRIVER_OBJECT pDriverObject) {pDriverObject->DriverUnload = FilterUnload;for (int i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++) {pDriverObject->MajorFunction[i] = DispatchAny;}
}//
// DriverEntry
//
_Function_class_(DRIVER_INITIALIZE)_IRQL_requires_same__IRQL_requires_(PASSIVE_LEVEL)
EXTERN_C NTSTATUS DriverEntry(_In_ PDRIVER_OBJECT pDriverObject,_In_ PUNICODE_STRING pusRegistryPath) {// Enable POOL_NX_OPTIN// Set NonPagedPoolExInitializeDriverRuntime(DrvRtPoolNxOptIn);//// Init global data//BOOLEAN fSuccess = FALSE;__try {Initialize(pDriverObject);LOGINFO3("Driver Load\n");fSuccess = true;} __finally {if (!fSuccess) {FilterUnload(pDriverObject);}}return STATUS_SUCCESS;
}

但是NT式驱动的缺点也正因如此,当需要用NT式驱动实现设备过滤时需要枚举每个需要的设备再附加到设备堆栈,例如早期的SFilter框架。

2.WDM驱动

支持即插即用(PNP)和电源管理功能的驱动类型,也是最常见的驱动类型,通常与硬件关联的驱动都是由WDM实现。
WDM驱动与NT式驱动的最大区别在于WDM驱动不支持SCM管理。虽然WDM驱动不支持SCM管理,但依然支持通过SCM启动,只是无法通过SCM停止。
在具体实现上,相比NT式驱动,WDM驱动必须额外注册AddDevice回调函数,此回调函数的作用是创建设备对象并由PNP管理器调用。
同时在IRP_MJ_POWERIRP_MJ_PNP中处理设备插拔和电源的IRP请求。

VOID FilterUnload(PDRIVER_OBJECT DriverObject) {UNREFERENCED_PARAMETER(DriverObject);
}NTSTATUS DispatchPower(PDEVICE_OBJECT DeviceObject, PIRP Irp) {NTSTATUS Status = STATUS_INVALID_DEVICE_OBJECT_PARAMETER;PDEVICE_EXTENSION DevExt = NULL;do {DevExt = (PDEVICE_EXTENSION)(DeviceObject->DeviceExtension);IoAcquireRemoveLock(&DevExt->RemoveLock, Irp);
#if (NTDDI_VERSION < NTDDI_VISTA)PoStartNextPowerIrp(Irp);IoSkipCurrentIrpStackLocation(Irp);Status = PoCallDriver(DevExt->TargetDevice, Irp);
#elseIoSkipCurrentIrpStackLocation(Irp);Status = IoCallDriver(DevExt->TargetDevice, Irp);
#endifIoReleaseRemoveLock(&DevExt->RemoveLock, Irp);} while (false);return Status;
}NTSTATUS DispatchPnp(PDEVICE_OBJECT DeviceObject, PIRP Irp) {NTSTATUS Status = STATUS_INVALID_DEVICE_OBJECT_PARAMETER;PDEVICE_EXTENSION DevExt = NULL;PDEVICE_OBJECT TargetDevice = NULL;PIO_STACK_LOCATION IrpStack = NULL;bool LockState = true;do {DevExt = (PDEVICE_EXTENSION)(DeviceObject->DeviceExtension);IoAcquireRemoveLock(&DevExt->RemoveLock, Irp);TargetDevice = DevExt->TargetDevice;  //IrpStack = IoGetCurrentIrpStackLocation(Irp);switch (IrpStack->MinorFunction) {case IRP_MN_START_DEVICE:  // 处理设备启动请求break;// case IRP_MN_QUERY_REMOVE_DEVICE: // 安全移除// case IRP_MN_SURPRISE_REMOVAL: // 强制移除case IRP_MN_REMOVE_DEVICE:  // 处理设备移除请求IoReleaseRemoveLockAndWait(&DevExt->RemoveLock, Irp);IoDetachDevice(DevExt->TargetDevice);  //IoDeleteDevice(DeviceObject);          //LockState = false;break;}//IoSkipCurrentIrpStackLocation(Irp);Status = IoCallDriver(DevExt->TargetDevice, Irp);if (LockState) {IoReleaseRemoveLock(&DevExt->RemoveLock, Irp);}} while (false);return Status;
}NTSTATUS AddDevice(PDRIVER_OBJECT DriverObject, PDEVICE_OBJECT PDO) {NTSTATUS Status = STATUS_SUCCESS;PDEVICE_EXTENSION DevExt = NULL;PDEVICE_OBJECT FilterDevice = NULL;Status = IoCreateDevice(DriverObject, sizeof(DEVICE_EXTENSION),NULL, PDO->DeviceType,PDO->Characteristics, FALSE, &FilterDevice);if (!NT_SUCCESS(Status)) {LOGERROR(Status, "IoCreateDevice failed\n");return Status;}FilterDevice->Flags |= PDO->Flags;DevExt = (PDEVICE_EXTENSION)(FilterDevice->DeviceExtension);RtlZeroMemory(DevExt, sizeof(DEVICE_EXTENSION));IoInitializeRemoveLock(&DevExt->RemoveLock, c_nRmLockTag, 60, 0);DevExt->PDO = PDO;Status = IoAttachDeviceToDeviceStackSafe(FilterDevice,            //PDO,                     //&DevExt->TargetDevice);  //if (!NT_SUCCESS(Status)) {LOGERROR(Status, "IoAttachDeviceToDeviceStackSafe failed\n");IoDeleteDevice(FilterDevice);return Status;}FilterDevice->Flags |= DevExt->TargetDevice->Flags & (DO_DIRECT_IO | DO_BUFFERED_IO);FilterDevice->Flags &= ~DO_DEVICE_INITIALIZING;return STATUS_SUCCESS;
}VOID Initialize(PDRIVER_OBJECT pDriverObject) {pDriverObject->DriverUnload = FilterUnload;for (int i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++) {pDriverObject->MajorFunction[i] = DispatchAny;}pDriverObject->MajorFunction[IRP_MJ_POWER] = DispatchPower;pDriverObject->MajorFunction[IRP_MJ_PNP] = DispatchPnp;pDriverObject->DriverExtension->AddDevice = AddDevice;
}//
// DriverEntry
//
_Function_class_(DRIVER_INITIALIZE)_IRQL_requires_same__IRQL_requires_(PASSIVE_LEVEL)
EXTERN_C NTSTATUS DriverEntry(_In_ PDRIVER_OBJECT pDriverObject,_In_ PUNICODE_STRING pusRegistryPath) {// Enable POOL_NX_OPTIN// Set NonPagedPoolExInitializeDriverRuntime(DrvRtPoolNxOptIn);//// Init global data//BOOLEAN fSuccess = FALSE;__try {Initialize(pDriverObject);LOGINFO3("Driver Load\n");fSuccess = true;} __finally {if (!fSuccess) {FilterUnload(pDriverObject);}}return STATUS_SUCCESS;
}

从上述的示例代码中可以看出,WDM驱动与NT式驱动的区。

2. 设备堆栈和IRP派遣

上图是USB存储设备的设备堆栈示例图,我们从下往上来看。
最下层是USB控制控制总线,由pci驱动创建设备的PDO(Physical Device Object)。
上一层是USB根控制器,由usbuhci驱动创建PDO,同时附加到下层的控制总线上。
更上层则是USB存储设备,由usbhub驱动创建PDO,附加到USB控制器。
最上层即实际的USB磁盘设备,由usbstor驱动创建PDO,附加到下一层的存储设备。
继续向上追溯的话,还有由disk驱动创建的磁盘分区,这里就不一一赘述了。
而所有的IRP请求都是由系统分发给最顶层的驱动程序,然后调用IoCallDriver向下分发,等待下层的执行的结果。
当然,实际的IO请求实际上是从卷设备开始分发的,而具体如何由卷设备派遣给磁盘设备的逻辑下次再说了。

  • 如何由卷设备追溯顶级的USB设备

1)通过IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS请求获取物理磁盘的编号。

bool GetPhysicalDrive(PDEVICE_OBJECT DeviceObject, PWCH pPhysicalDrive, ULONG size) {VOLUME_DISK_EXTENTS vde;NTSTATUS status = IoControl(DeviceObject, IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS, NULL, 0, &vde, sizeof(vde));swprintf_s(pPhysicalDrive, size, L"\\??\\PhysicalDrive%lu", vde.Extents[0].DiskNumber);return true;
}

2)由物理磁盘的编号获取文件系统设备对象

PFILE_OBJECT FileObj;
NTSTATUS status = IoGetDeviceObjectPointer(&usDiskWin32Name, FILE_READ_DATA, &FileObj, &DevObj);
ObDereferenceObject(FileObj);
// Find FileSystem From Device Stack
UNICODE_STRING usFileSystemDriver = RTL_CONSTANT_STRING(L"\\FileSystem\\RAW");
DevObj = GetTargetDeviceFromStackByDriver(DevObj, &usFileSystemDriver);

3)由文件系统设备对象获取磁盘设备对象

IoGetDiskDeviceObject(DevObj, &DiskObj);

4)由磁盘设备对象获取磁盘驱动器对象

PDEVICE_OBJECT GetTargetDeviceFromStackByDriver(PDEVICE_OBJECT DeviceObject, PUNICODE_STRING DriverName) {PDEVICE_OBJECT TargetDevice;TargetDevice = IoGetLowerDeviceObject(DeviceObject);while (TargetDevice) {if (0 == RtlCompareUnicodeString(&TargetDevice->DriverObject->DriverName, DriverName, TRUE)) {break;}DeviceObject = TargetDevice;TargetDevice = IoGetLowerDeviceObject(DeviceObject);ObDereferenceObject(DeviceObject);}return TargetDevice;
}// Find USBSTOR From Device Stack
UNICODE_STRING usUsbstorDriver = RTL_CONSTANT_STRING(L"\\Driver\\USBSTOR");
DevObj = GetTargetDeviceFromStackByDriver(DiskObj, &usUsbstorDriver);

相关文章:

Windows驱动开发(二)

1. NT和WDM式驱动 1. NT式驱动 传统的Windows系统驱动类型。NT式驱动的启动/停止/安装/卸载只能由 服务控制管理程序组件(SCM) 来完成的。 包括最简单的hello world&#xff0c;以及目前常用的文件过滤框架 minifilter 都是基于NT式实现的。 NT式驱动的最大特点即完全不依赖硬…...

Hotspot是什么?

Hotspot 简单来说&#xff0c;JVM的一种。 一、HotSpot 的官方定义 HotSpot 是 Oracle 公司开发的一个高性能的 Java 虚拟机&#xff08;JVM&#xff09;。它通过一系列先进的技术和优化手段&#xff0c;为 Java 应用程序提供高效的运行环境&#xff0c;实现了跨平台的代码执行…...

k8s-集群部署1

k8s-集群部署1 一、基础环境准备二、docker环境准备三、k8s集群部署1.kubeadm创建集群2.使用kubeadm引导集群 总结 一、基础环境准备 首先&#xff0c;需要准备三个服务器实例&#xff0c;这里我使用了阿里云创建了三个实例&#xff0c;如果不想花钱&#xff0c;也可以在VM上创…...

wordpress Contact form 7发件人邮箱设置

此教程仅适用于演示站有留言的主题&#xff0c;演示站没有留言的主题&#xff0c;就别往下看了&#xff0c;免费浪费时间。 使用了Contact form 7插件的简站WordPress主题&#xff0c;在有人留言时&#xff0c;就会发邮件到网站的系统邮箱(一般与管理员邮箱为同一个)里。上面显…...

15分钟学 Python 第38天 :Python 爬虫入门(四)

Day38 : Python爬虫异常处理与反爬虫机制 章节1&#xff1a;异常处理的重要性 在爬虫开发过程中&#xff0c;网络请求和数据解析常常会遭遇各种异常。正确的异常处理可以提高程序的稳定性&#xff0c;避免崩溃&#xff0c;并帮助开发者快速定位问题。 章节2&#xff1a;常见…...

GWAS分析中显著位点如何注释基因:excel???

大家好&#xff0c;我是邓飞。 今天星球的小伙伴问了一个问题&#xff1a; 我现在在做GWAS分析&#xff0c;现在已经找到性状关联的SNP位点&#xff0c;下一步我如何根据position 找到基因呢&#xff1f; 关于基因注释&#xff0c;之前写过一些博客&#xff0c;可以用到的软件…...

深入浅出 CSS 定位:全面解析与实战指南

“批判他人总是想的太简单 剖析自己总是想的太困难” 文章目录 目录 前言文章有误敬请斧正 不胜感恩&#xff01;1. CSS 定位概述2. 定位类型详解2.1 static&#xff08;默认定位&#xff09;2.2 relative&#xff08;相对定位&#xff09;2.3 absolute&#xff08;绝对定位&am…...

HTTPS协议详解:从原理到流程,全面解析安全传输的奥秘

&#x1f49d;&#x1f49d;&#x1f49d;欢迎莅临我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐&#xff1a;「storm…...

Android 13.0 系统内存优化之修改dalvik虚拟机的内存参数

1.前言 在13.0的系统rom开发定制中,app应用也是运行在dalvik虚拟机上的,所以对于一些内存低的系统中,在某些大应用会出现耗内存 卡顿情况,这是系统分配的内存不够大,在进行耗内存的操作,就会出现频繁gc等等原因造成不流畅的现象,接下来就分析下 虚拟机分配内存的相关原理…...

C# 无边框窗体,加阴影效果、多组件拖动、改变大小等功能完美实现优化版效果体验

一、预览效果 国庆节第一天,祝祖国繁荣昌盛! 1.1 效果图 (WinForm无边框窗体,F11可全屏) 拖动窗体时半透明效果(拖动时参考窗体后面释放位置) 说明:本功能的实现基于网友的原型完善而来,更多代码可以参考他的文章 h...

深入解析 ChatGLM 模型:核心原理、优势与未来应用前景

1. 引言 1.1 ChatGLM 模型概述 ChatGLM 是一类基于自回归语言模型的生成式预训练模型&#xff0c;专门设计用于处理对话系统中的自然语言生成任务。ChatGLM 模型依托于 Transformer 架构&#xff0c;具备高度并行化的计算能力&#xff0c;并能够捕捉长距离的语言依赖关系。在…...

python全栈学习记录(二十二)多态性、封装、绑定方法与非绑定方法

多态性、封装、绑定方法与非绑定方法 文章目录 多态性、封装、绑定方法与非绑定方法一、多态性二、封装三、绑定方法与非绑定方法 一、多态性 多态指的是同一种事物的多种形态&#xff0c;如水&#xff1a;冰、水蒸气、液态水&#xff0c;又如动物&#xff1a;猫、狗、猪。 多…...

用Python制作自己的聊天机器人:从零开始构建智能对话助手

解锁Python编程的无限可能:《奇妙的Python》带你漫游代码世界 近年来,聊天机器人已经成为日常生活中不可或缺的工具,从自动客服到个人助手,聊天机器人在各类应用中广泛存在。如果你想了解如何制作一个自己的聊天机器人,那么这篇文章将带你一步步实现这个目标。我们将使用…...

LabVIEW裂纹深度在线监测系统

随着铁路运输技术的快速发展&#xff0c;火车安全问题成为重中之重&#xff0c;尤其是轮面裂纹的检测和管理。裂纹的出现可能导致严重的列车事故&#xff0c;因此&#xff0c;建立可靠的在线监测系统&#xff0c;实时掌握裂纹情况&#xff0c;对保障铁路运输安全至关重要。 La…...

工业物联网的伦理和社会影响

随着科技的飞速发展&#xff0c;工业物联网&#xff08;IIoT&#xff09;已经成为现代工业领域的重要组成部分。它通过将各种设备、传感器和系统连接起来&#xff0c;实现了生产过程的智能化、自动化和高效化。然而&#xff0c;在享受工业物联网带来的巨大便利和经济效益的同时…...

TCP --- 确认应答机制以及三次握手四次挥手

序言 在前一篇文章中&#xff0c;我们介绍了 UDP协议 (点击查看)&#x1f448;&#xff0c;该协议给我们的感觉就两个字 — 简单&#xff0c;只是将我们的数据进行简单的添加报头然后发送。当然使用起来虽然简单&#xff0c;但是否能送到目的地&#xff0c;那就要看网络的状态了…...

GPT带我学-设计模式17-装饰器模式

概述 装饰器模式&#xff08;Decorator Pattern&#xff09;是一种结构型设计模式&#xff0c;允许你在不改变对象接口的前提下&#xff0c;动态地给对象添加新功能。这个模式通常用于扩展类的功能。 基本结构 组件接口&#xff08;Component&#xff09;&#xff1a;定义一…...

【Redis】如何在 Ubuntu 上安装 Redis 5

&#x1f970;&#x1f970;&#x1f970;来都来了&#xff0c;不妨点个关注叭&#xff01; &#x1f449;博客主页&#xff1a;欢迎各位大佬!&#x1f448; 本期内容主要介绍如何在 Ubuntu 上安装 Redis5 一些碎碎念&#xff1a; 本来这期内容介绍如何在 Centos 安装 Redis …...

房屋水电费记账本:内置的数组数据击按钮不能删除,页面手动添加的可以删除

<!DOCTYPE html> <html lang"zh-CN"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>房租水电费记录</title><script type&qu…...

【ubuntu】apt是什么

目录 1.apt简介 2.常用apt指令 2.1安装 2.2更新列表 2.3更新已经安装的软件包 2.4搜索软件包 2.5显示软件包信息 2.6移除软件包 2.7清理无用的安装包 2.8清理无用的依赖项 3.apt和apt-get 3.1区别 3.2 总结 1.apt简介 apt的全称是advanced package …...

变量 varablie 声明- Rust 变量 let mut 声明与 C/C++ 变量声明对比分析

一、变量声明设计&#xff1a;let 与 mut 的哲学解析 Rust 采用 let 声明变量并通过 mut 显式标记可变性&#xff0c;这种设计体现了语言的核心哲学。以下是深度解析&#xff1a; 1.1 设计理念剖析 安全优先原则&#xff1a;默认不可变强制开发者明确声明意图 let x 5; …...

日语学习-日语知识点小记-构建基础-JLPT-N4阶段(33):にする

日语学习-日语知识点小记-构建基础-JLPT-N4阶段(33):にする 1、前言(1)情况说明(2)工程师的信仰2、知识点(1) にする1,接续:名词+にする2,接续:疑问词+にする3,(A)は(B)にする。(2)復習:(1)复习句子(2)ために & ように(3)そう(4)にする3、…...

使用van-uploader 的UI组件,结合vue2如何实现图片上传组件的封装

以下是基于 vant-ui&#xff08;适配 Vue2 版本 &#xff09;实现截图中照片上传预览、删除功能&#xff0c;并封装成可复用组件的完整代码&#xff0c;包含样式和逻辑实现&#xff0c;可直接在 Vue2 项目中使用&#xff1a; 1. 封装的图片上传组件 ImageUploader.vue <te…...

Reasoning over Uncertain Text by Generative Large Language Models

https://ojs.aaai.org/index.php/AAAI/article/view/34674/36829https://ojs.aaai.org/index.php/AAAI/article/view/34674/36829 1. 概述 文本中的不确定性在许多语境中传达,从日常对话到特定领域的文档(例如医学文档)(Heritage 2013;Landmark、Gulbrandsen 和 Svenevei…...

return this;返回的是谁

一个审批系统的示例来演示责任链模式的实现。假设公司需要处理不同金额的采购申请&#xff0c;不同级别的经理有不同的审批权限&#xff1a; // 抽象处理者&#xff1a;审批者 abstract class Approver {protected Approver successor; // 下一个处理者// 设置下一个处理者pub…...

Web中间件--tomcat学习

Web中间件–tomcat Java虚拟机详解 什么是JAVA虚拟机 Java虚拟机是一个抽象的计算机&#xff0c;它可以执行Java字节码。Java虚拟机是Java平台的一部分&#xff0c;Java平台由Java语言、Java API和Java虚拟机组成。Java虚拟机的主要作用是将Java字节码转换为机器代码&#x…...

Git 3天2K星标:Datawhale 的 Happy-LLM 项目介绍(附教程)

引言 在人工智能飞速发展的今天&#xff0c;大语言模型&#xff08;Large Language Models, LLMs&#xff09;已成为技术领域的焦点。从智能写作到代码生成&#xff0c;LLM 的应用场景不断扩展&#xff0c;深刻改变了我们的工作和生活方式。然而&#xff0c;理解这些模型的内部…...

C++ 设计模式 《小明的奶茶加料风波》

&#x1f468;‍&#x1f393; 模式名称&#xff1a;装饰器模式&#xff08;Decorator Pattern&#xff09; &#x1f466; 小明最近上线了校园奶茶配送功能&#xff0c;业务火爆&#xff0c;大家都在加料&#xff1a; 有的同学要加波霸 &#x1f7e4;&#xff0c;有的要加椰果…...

毫米波雷达基础理论(3D+4D)

3D、4D毫米波雷达基础知识及厂商选型 PreView : https://mp.weixin.qq.com/s/bQkju4r6med7I3TBGJI_bQ 1. FMCW毫米波雷达基础知识 主要参考博文&#xff1a; 一文入门汽车毫米波雷达基本原理 &#xff1a;https://mp.weixin.qq.com/s/_EN7A5lKcz2Eh8dLnjE19w 毫米波雷达基础…...

【WebSocket】SpringBoot项目中使用WebSocket

1. 导入坐标 如果springboot父工程没有加入websocket的起步依赖&#xff0c;添加它的坐标的时候需要带上版本号。 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-websocket</artifactId> </dep…...