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_POWER和IRP_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,以及目前常用的文件过滤框架 minifilter 都是基于NT式实现的。 NT式驱动的最大特点即完全不依赖硬…...
Hotspot是什么?
Hotspot 简单来说,JVM的一种。 一、HotSpot 的官方定义 HotSpot 是 Oracle 公司开发的一个高性能的 Java 虚拟机(JVM)。它通过一系列先进的技术和优化手段,为 Java 应用程序提供高效的运行环境,实现了跨平台的代码执行…...
k8s-集群部署1
k8s-集群部署1 一、基础环境准备二、docker环境准备三、k8s集群部署1.kubeadm创建集群2.使用kubeadm引导集群 总结 一、基础环境准备 首先,需要准备三个服务器实例,这里我使用了阿里云创建了三个实例,如果不想花钱,也可以在VM上创…...
wordpress Contact form 7发件人邮箱设置
此教程仅适用于演示站有留言的主题,演示站没有留言的主题,就别往下看了,免费浪费时间。 使用了Contact form 7插件的简站WordPress主题,在有人留言时,就会发邮件到网站的系统邮箱(一般与管理员邮箱为同一个)里。上面显…...
15分钟学 Python 第38天 :Python 爬虫入门(四)
Day38 : Python爬虫异常处理与反爬虫机制 章节1:异常处理的重要性 在爬虫开发过程中,网络请求和数据解析常常会遭遇各种异常。正确的异常处理可以提高程序的稳定性,避免崩溃,并帮助开发者快速定位问题。 章节2:常见…...
GWAS分析中显著位点如何注释基因:excel???
大家好,我是邓飞。 今天星球的小伙伴问了一个问题: 我现在在做GWAS分析,现在已经找到性状关联的SNP位点,下一步我如何根据position 找到基因呢? 关于基因注释,之前写过一些博客,可以用到的软件…...
深入浅出 CSS 定位:全面解析与实战指南
“批判他人总是想的太简单 剖析自己总是想的太困难” 文章目录 目录 前言文章有误敬请斧正 不胜感恩!1. CSS 定位概述2. 定位类型详解2.1 static(默认定位)2.2 relative(相对定位)2.3 absolute(绝对定位&am…...
HTTPS协议详解:从原理到流程,全面解析安全传输的奥秘
💝💝💝欢迎莅临我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 推荐:「storm…...
Android 13.0 系统内存优化之修改dalvik虚拟机的内存参数
1.前言 在13.0的系统rom开发定制中,app应用也是运行在dalvik虚拟机上的,所以对于一些内存低的系统中,在某些大应用会出现耗内存 卡顿情况,这是系统分配的内存不够大,在进行耗内存的操作,就会出现频繁gc等等原因造成不流畅的现象,接下来就分析下 虚拟机分配内存的相关原理…...
C# 无边框窗体,加阴影效果、多组件拖动、改变大小等功能完美实现优化版效果体验
一、预览效果 国庆节第一天,祝祖国繁荣昌盛! 1.1 效果图 (WinForm无边框窗体,F11可全屏) 拖动窗体时半透明效果(拖动时参考窗体后面释放位置) 说明:本功能的实现基于网友的原型完善而来,更多代码可以参考他的文章 h...
深入解析 ChatGLM 模型:核心原理、优势与未来应用前景
1. 引言 1.1 ChatGLM 模型概述 ChatGLM 是一类基于自回归语言模型的生成式预训练模型,专门设计用于处理对话系统中的自然语言生成任务。ChatGLM 模型依托于 Transformer 架构,具备高度并行化的计算能力,并能够捕捉长距离的语言依赖关系。在…...
python全栈学习记录(二十二)多态性、封装、绑定方法与非绑定方法
多态性、封装、绑定方法与非绑定方法 文章目录 多态性、封装、绑定方法与非绑定方法一、多态性二、封装三、绑定方法与非绑定方法 一、多态性 多态指的是同一种事物的多种形态,如水:冰、水蒸气、液态水,又如动物:猫、狗、猪。 多…...
用Python制作自己的聊天机器人:从零开始构建智能对话助手
解锁Python编程的无限可能:《奇妙的Python》带你漫游代码世界 近年来,聊天机器人已经成为日常生活中不可或缺的工具,从自动客服到个人助手,聊天机器人在各类应用中广泛存在。如果你想了解如何制作一个自己的聊天机器人,那么这篇文章将带你一步步实现这个目标。我们将使用…...
LabVIEW裂纹深度在线监测系统
随着铁路运输技术的快速发展,火车安全问题成为重中之重,尤其是轮面裂纹的检测和管理。裂纹的出现可能导致严重的列车事故,因此,建立可靠的在线监测系统,实时掌握裂纹情况,对保障铁路运输安全至关重要。 La…...
工业物联网的伦理和社会影响
随着科技的飞速发展,工业物联网(IIoT)已经成为现代工业领域的重要组成部分。它通过将各种设备、传感器和系统连接起来,实现了生产过程的智能化、自动化和高效化。然而,在享受工业物联网带来的巨大便利和经济效益的同时…...
TCP --- 确认应答机制以及三次握手四次挥手
序言 在前一篇文章中,我们介绍了 UDP协议 (点击查看)👈,该协议给我们的感觉就两个字 — 简单,只是将我们的数据进行简单的添加报头然后发送。当然使用起来虽然简单,但是否能送到目的地,那就要看网络的状态了…...
GPT带我学-设计模式17-装饰器模式
概述 装饰器模式(Decorator Pattern)是一种结构型设计模式,允许你在不改变对象接口的前提下,动态地给对象添加新功能。这个模式通常用于扩展类的功能。 基本结构 组件接口(Component):定义一…...
【Redis】如何在 Ubuntu 上安装 Redis 5
🥰🥰🥰来都来了,不妨点个关注叭! 👉博客主页:欢迎各位大佬!👈 本期内容主要介绍如何在 Ubuntu 上安装 Redis5 一些碎碎念: 本来这期内容介绍如何在 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 …...
Go语言性能分析:pprof与trace
Go语言性能分析:pprof与trace 1. pprof使用 import ("net/http/pprof"_ "net/http/pprof" )func main() {http.ListenAndServe(":6060", nil) }2. trace使用 import "runtime/trace"func main() {f, _ : os.Create("t…...
3分钟掌握Shutter Encoder:免费开源的终极视频转换工具解决方案
3分钟掌握Shutter Encoder:免费开源的终极视频转换工具解决方案 【免费下载链接】shutter-encoder A professional video compression tool accessible to all, mostly based on FFmpeg. 项目地址: https://gitcode.com/gh_mirrors/sh/shutter-encoder 还在为…...
# 040、实战项目五:多 Agent 协作系统 —— 项目经理、开发者、测试者角色模拟
从一次凌晨三点的事故说起 去年做智能客服系统重构,我犯了个低级错误——让单个Agent既写代码又自测。结果上线当天,它把“用户退款”的SQL写成了DELETE FROM orders WHERE status‘refund’,还自信满满地标注“测试通过”。凌晨三点被运维电…...
工具推荐:HTML5+AI开发必备的前端调试工具
工具推荐:HTML5AI开发必备的前端调试工具 工具推荐:HTML5AI开发必备的前端调试工具📝 本章学习目标:本章聚焦职业发展,帮助读者规划HTML5AI的学习与职业路径。通过本章学习,你将全面掌握"工具推荐&…...
GEE实战:Landsat 8 TOA和SR数据去云处理,保姆级代码对比与避坑指南
GEE实战:Landsat 8 TOA与SR数据去云处理深度解析 当你在Google Earth Engine(GEE)平台上处理Landsat 8数据时,是否曾为选择TOA(大气层顶反射率)还是SR(地表反射率)而犹豫不决&#x…...
告别Minecraft模组英文界面:MASA全家桶汉化包完全指南
告别Minecraft模组英文界面:MASA全家桶汉化包完全指南 【免费下载链接】masa-mods-chinese 一个masa mods的汉化资源包 项目地址: https://gitcode.com/gh_mirrors/ma/masa-mods-chinese 你是否曾经在Minecraft中面对满屏的英文模组界面感到困惑?…...
Logstalgia高级配置技巧:自定义颜色、分组和过滤规则
Logstalgia高级配置技巧:自定义颜色、分组和过滤规则 【免费下载链接】Logstalgia replay or stream website access logs as a retro arcade game 项目地址: https://gitcode.com/gh_mirrors/lo/Logstalgia Logstalgia是一款将网站访问日志以复古街机游戏形…...
CANN/asc-devkit Mins矢量计算
Mins(灵活标量位置) 【免费下载链接】asc-devkit 本项目是CANN 推出的昇腾AI处理器专用的算子程序开发语言,原生支持C和C标准规范,主要由类库和语言扩展层构成,提供多层级API,满足多维场景算子开发诉求。 …...
从防御者视角看Fastjson 1.2.24漏洞:如何用Docker+vulhub快速搭建靶场并验证修复方案
防御视角下的Fastjson 1.2.24漏洞实战:Docker靶场搭建与修复方案验证 在当今的软件开发中,JSON处理库的安全性问题日益凸显。作为Java生态中最流行的JSON库之一,Fastjson因其高性能而广受欢迎,但同时也因其历史漏洞频发而备受关注…...
解密ASCII图表魔法:ditaa将文本艺术转化为专业图表的技术揭秘
解密ASCII图表魔法:ditaa将文本艺术转化为专业图表的技术揭秘 【免费下载链接】ditaa ditaa is a small command-line utility that can convert diagrams drawn using ascii art (drawings that contain characters that resemble lines like | / - ), into proper…...
