本文主要讲的是磁盘设备过滤器驱动(Disk Device Filter Driver),其可以附加到本机磁盘驱动器上,过滤系统中的所有磁盘设备,实现对特定磁盘写保护的功能。
Windows上有几种不同类型的过滤器驱动程序,从文件系统过滤器、Ndis封包过滤器到特定的PnP设备过滤器等。本文主要讲的是磁盘设备过滤器驱动(Disk Device Filter Driver),其可以附加到本机磁盘驱动器上,过滤系统中的所有磁盘设备,实现对特定磁盘写保护的功能。
【资料图】
本文涉及到的名词及缩写,在介绍设备过滤器驱动时简单科普部分名词解释。
Windows设备对象堆栈
操作系统按照设备对象来表示设备,一个或多个设备对象与每个设备相关联,通过操作设备对象来对设备进行相关操作。
FDO:全称为Functional Device Object,表示功能设备对象,是设备的主要驱动程序;PDO:全称为Physical Device Object,表示物理设备对象,但不一定是物理设备,本质是总线上的设备与总线本身之间的接口;FiDO:过滤器驱动,属于可选驱动程序,在FDO上方的被称为upper filter上层过滤器,在FDO下方的被称为low filter下层过滤器。PnP
表示即插即用设备
IRP
IRP(I/O request packets)是io数据请求包的缩写,是一种复杂的数据结构,用于与内核模式驱动程序进行通信,发送到设备驱动程序的大部分请求都打包在I/O请求数据包,详细的数据结构可以看msdn:IRP结构。
FIDO可以是上层过滤器或下层过滤器,上层过滤器在设备堆栈的FDO之上实例化,所以上层过滤器可以在设备的FDO设备对象看到之前,处理发送到FDO设备的IRP操作,本文主要讲的就是一个基于KMDF框架的上层过滤器驱动。
安装某一类设备驱动过滤器时,会在对应设备类(详细设备类及GUID)注册对应的UpperFilters及LowerFilters键值,在收到此类设备的PnP时,系统会尝试启动对应的过滤器驱动,下图为本文的磁盘设备上层过滤器驱动的注册表值:
磁盘设备Class = DiskDrive
ClassGuid = {4d36e967-e325-11ce-bfc1-08002be10318}
WDF过滤器的结构与FDO相同,在DriverEntry中创建WDFDRIVER对象并与框架链接,对于过滤器驱动,当PnP Manager枚举指定设备的驱动程序时,将会调用EvtDriverDeviceAdd事件用于处理回调。
DriverEntry
在主函数中没有处理太多逻辑,主要是实例化WdfDriver对象并连接框架:
extern "C"NTSTATUSDriverEntry(PDRIVER_OBJECT DriverObject,PUNICODE_STRING RegistryPath){WDF_DRIVER_CONFIG config;NTSTATUS status;WDF_DRIVER_CONFIG_INIT(&config,DiskProtEvtDeviceAdd);//创建一个wdf驱动对象status = WdfDriverCreate(DriverObject,RegistryPath,WDF_NO_OBJECT_ATTRIBUTES,&config,WDF_NO_HANDLE); if (!NT_SUCCESS(status)) {#if DBGDbgPrint("WdfDriverCreate failed - 0x%x\n",status);#endifreturn status;}return STATUS_SUCCESS;}
EvtDriverDeviceAdd
_Use_decl_annotations_NTSTATUSDiskProtEvtDeviceAdd(WDFDRIVER Driver,PWDFDEVICE_INIT DeviceInit){NTSTATUS status;WDF_OBJECT_ATTRIBUTES wdfObjectAttr;WDFDEVICE wdfDevice;PDISKPROT_DEVICE_CONTEXT devContext;WDF_IO_QUEUE_CONFIG ioQueueConfig;//PnP管理器报告新设备存在时 回调该 api 并执行设备初始化操作#if DBGDbgPrint("DiskProtEvtDeviceAdd: Adding device...\n");#endifUNREFERENCED_PARAMETER(Driver);//PnP管理器报告新设备存在时 回调该 api 并执行设备初始化操作WdfFdoInitSetFilter(DeviceInit);//// 指定设备上下文//WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&wdfObjectAttr,DISKPROT_DEVICE_CONTEXT);status = WdfDeviceCreate(&DeviceInit,&wdfObjectAttr,&wdfDevice);if (!NT_SUCCESS(status)) {#if DBGDbgPrint("WdfDeviceCreate failed - 0x%x\n",status);#endifreturn status;}devContext = DiskProtGetDeviceContext(wdfDevice);devContext->WdfDevice = wdfDevice;//创建默认队列 以及注册相关回调函数WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE(&ioQueueConfig,WdfIoQueueDispatchParallel);ioQueueConfig.EvtIoRead = DiskProtEvtRead;ioQueueConfig.EvtIoWrite = DiskProtEvtWrite;ioQueueConfig.EvtIoDeviceControl = DiskProtEvtDeviceControl;//// 创建WDF队列//status = WdfIoQueueCreate(devContext->WdfDevice,&ioQueueConfig,WDF_NO_OBJECT_ATTRIBUTES,WDF_NO_HANDLE);if (!NT_SUCCESS(status)) {#if DBGDbgPrint("WdfIoQueueCreate failed - 0x%x\n",status);#endifreturn status;}return STATUS_SUCCESS;}
EvtIoDeviceControl
KMDF框架通过EvtIoDeviceControl处理接收到的对应设备的IOCTL请求,本文主要实现磁盘的写保护功能,也就是需要响应IOCTL_DISK_IS_WRITABLE控制请求,通过WdfRequestComplete返回这个磁盘受到保护的状态码STATUS_MEDIA_WRITE_PROTECTED。
_Use_decl_annotations_VOIDDiskProtEvtDeviceControl(WDFQUEUE Queue,WDFREQUEST Request,size_t OutputBufferLength,size_t InputBufferLength,ULONG IoControlCode){PDISKPROT_DEVICE_CONTEXT devContext;devContext = DiskProtGetDeviceContext(WdfIoQueueGetDevice(Queue));UNREFERENCED_PARAMETER(OutputBufferLength);UNREFERENCED_PARAMETER(InputBufferLength);#if DBGDbgPrint("DiskProtEvtDeviceControl -- Request 0x%p\n",Request);#endif//获取磁盘是否只读IOCTLif (IoControlCode == IOCTL_DISK_IS_WRITABLE) {if(DiskProtGetBusType(devContext) == STORAGE_BUS_TYPE::BusTypeUsb){//返回一个只读的状态码WdfRequestComplete(Request, STATUS_MEDIA_WRITE_PROTECTED);return;}FilterSendWithCallback(Request,devContext);return;}FilterSendAndForget(Request,devContext);}
另一个问题,如何判断这个磁盘是需要进行写入保护的磁盘?此处的做法是通过磁盘的IOCTL_STORAGE_QUERY_PROPERTY来获取当前设备对象的磁盘信息,通过获取总线结构,判断当前磁盘类型,只对一类总线结构的类型进行写保护,同时此处也可以自由拓展,由应用层来决定对某些磁盘的保护控制。
_Use_decl_annotations_STORAGE_BUS_TYPE DiskProtGetBusType(PDISKPROT_DEVICE_CONTEXT devContext){WDFIOTARGET hidTarget = nullptr;WDF_MEMORY_DESCRIPTOR outputDescriptor;STORAGE_PROPERTY_QUERY query = {};PSTORAGE_DESCRIPTOR_HEADER descriptor = nullptr;PSTORAGE_DEVICE_DESCRIPTOR DeviceDescriptor = nullptr;STORAGE_BUS_TYPE currentBusType = STORAGE_BUS_TYPE::BusTypeUnknown;hidTarget = WdfDeviceGetIoTarget(devContext->WdfDevice);WDF_MEMORY_DESCRIPTOR_INIT_BUFFER(&outputDescriptor,(PVOID)&query,sizeof(STORAGE_PROPERTY_QUERY));query.PropertyId = StorageDeviceProperty;query.QueryType = PropertyStandardQuery;descriptor = (PSTORAGE_DESCRIPTOR_HEADER)&query;NTSTATUS status = WdfIoTargetSendIoctlSynchronously(hidTarget,NULL,IOCTL_STORAGE_QUERY_PROPERTY,&outputDescriptor,&outputDescriptor,NULL,NULL);if (!NT_SUCCESS(status)){DbgPrint("DiskProtEvtDeviceControl WdfIoTargetSendIoctlSynchronously failed 0x%x\n", status);return currentBusType;}else{DbgPrint("DiskProtEvtDeviceControl %d\n", descriptor->Size);ULONG bufferLength = 0;bufferLength = descriptor->Size;NT_ASSERT(bufferLength >= sizeof(STORAGE_PROPERTY_QUERY));bufferLength = max(bufferLength, sizeof(STORAGE_PROPERTY_QUERY));descriptor = (PSTORAGE_DESCRIPTOR_HEADER)ExAllocatePoolWithTag(NonPagedPoolNx, bufferLength, "GYqw");RtlZeroMemory(&query, sizeof(STORAGE_PROPERTY_QUERY));query.PropertyId = StorageDeviceProperty;query.QueryType = PropertyStandardQuery;RtlCopyMemory(descriptor,&query,sizeof(STORAGE_PROPERTY_QUERY));//开辟完空间重新获取数据WDF_MEMORY_DESCRIPTOR_INIT_BUFFER(&outputDescriptor,(PVOID)descriptor,bufferLength);status = WdfIoTargetSendIoctlSynchronously(hidTarget,NULL,IOCTL_STORAGE_QUERY_PROPERTY,&outputDescriptor,&outputDescriptor,NULL,NULL);DeviceDescriptor = (PSTORAGE_DEVICE_DESCRIPTOR)descriptor;DbgPrint("DiskProtEvtDeviceControl StorageDeviceProperty %d\n", DeviceDescriptor->BusType);currentBusType = DeviceDescriptor->BusType;FREE_POOL(DeviceDescriptor);}return currentBusType;}
Install inf
需要在inf安装文件中指定需要附加在哪一类设备以及需要提供相应的GUID,此外还需要在注册表中指定为`UpperFilters,此外在inf中指定驱动的启动类型,SERVICE_BOOT_START表示由操作系统(OS)加载程序启动的驱动。
[Version]Signature = "$Windows NT$"Class = %ClassNameToFilter% ClassGUID = %ClassGUIDToFilter% Provider = %Provider%DriverVer = CatalogFile = DiskProt.cat[DefaultInstall.NT]CopyFiles = @DiskProt.sysAddreg = DiskProt.AddReg[DestinationDirs]DefaultDestDir = 12[DiskProt.AddReg]HKLM, System\CurrentControlSet\Control\Class\%ClassGUIDToFilter%, UpperFilters, 0x00010008, %DriverName% [DefaultInstall.NT.Services]AddService = DiskProt, , DiskProt.Service.Install[DiskProt.Service.Install]DisplayName = %ServiceName%Description = %ServiceDescription%ServiceBinary = %12%\%DriverName%.sys ServiceType = 1 ;SERVICE_KERNEL_DRIVERStartType = 0 ;SERVICE_BOOT_START ErrorControl = 1 ;SERVICE_ERROR_NORMALAddReg = KMDFVerifierAddReg[KMDFVerifierAddReg]HKR, Parameters\Wdf,VerifierOn,0x00010001,1HKR, Parameters\Wdf,VerboseOn,0x00010001,1HKR, Parameters\Wdf,DbgBreakOnError,0x00010001,1[SourceDisksFiles]DiskProt.sys=1[SourceDisksNames]1 = %DiskName%[Strings]ClassGUIDToFilter = "{4d36e967-e325-11ce-bfc1-08002be10318}"ClassNameToFilter = "DiskDrive" Provider = "yunshanwuyin"ServiceDescription = "disk protect"ServiceName = "DiskProt"DriverName = "DiskProt"DiskName = "DiskProt Installation Disk"
效果
关于磁盘相关的驱动,最好配置双击调试进行测试,否则可能由于某些代码或安装问题导致蓝屏,处理起来会很麻烦,数据的安全性也无法保证。
1.存储类设备除了使用驱动进行控制,应用层通过修改注册表以及策略组,也可以达到只读、禁用等功能;
应用层禁用USB设备注册表位置:HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\USBSTOR
修改start项:3表示启用、4表示禁用
应用层限制USB存储设备写保护注册表位置:HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\StorageDevicePolicies
修改WriteProtect项:0表示不限制只读,1表示限制为只读
修改注册表的策略并不是实时生效的,在修改完之后重新接入U盘,策略才会生效
2.手机类型设备属于WPD设备,控制需要使用其他的ClassGuid进行管理,在应用层想要限制WPD设备的相关操作,需要配置策略组,home版本没有策略组的同样可以通过修改注册表来解决,如注册表中无以下内容,可自行创建。
应用层WPD设备禁用以及只读策略注册表位置:HKEY_LOCAL_MACHINE\Software\Policies\Microsoft\Windows\RemovableStorageDevices\{6AC27878-A6FA-4155-BA85-F98F491D4F33}
包含两个项Deny_Read,`Deny_Write: 0表示正常读取、写入1表示禁用
开启策略:wpd的策略设置完成之后还需要配置开启策略的选项注册表位置:HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\RemovableStorageDevices\{F33FDC04-D1AC-4E8E-9A30-19BBD4B108AE}
包含两个项Deny_Read,Deny_Write:0表示禁用对应的读取/写入策略、1表示启用策略
Git Hub:https://github.com/yunshanwuyin/DiskProt
Gitee:https://gitee.com/yunshanwuyin/DiskProt
本文主要讲的是磁盘设备过滤器驱动(DiskDeviceFilterDriver),其可...
哪怕如此,三星的出货量还是同比下降了19%,不仅仅是三星,苹果、小...
5月6日电,据天津市纪委监委驻市卫生健康委纪检监察组、天津市河西...
加拿大多伦多S&P TSX综合指数中表现最好的股票为OpenTextCorp (TSX...
这个水果它很高纤,所以适合便秘的朋友,它能量也很高,却有大量文...
4月17日,浙江省金华市武义县凤凰山工业区内一厂房发生重大火灾事故...
1、HPV是乳头瘤病毒,常见的尖锐湿疣就是这病毒引起的。2、HVP感染...
无商业险谁来赔?西安:大风吹倒一整面墙,百万劳斯莱斯被砸!,车行...
原标题:88岁作曲家谷建芬谱写50多首“新学堂歌”(引题)她让古诗...
洪武帝的愤怒,沈万三该死掏空家底又如何,好了,今天小编就说到这里...
2023年是全面贯彻落实党的二十大精神的开局之年。近日,共青团中央...
近日,农业农村部公布2022年国家农民合作社示范社公示名单,我市固...
文化和旅游部最新数据显示,“五一”假期国内旅游出游合计2 74亿人...
本文来源:时代周报作者:韩利明日前,教育部印发《2023年全国综合...
来源 未来迹撰文 陈龙向婷婷著名赛车手埃尔顿·塞纳曾说:你不能...
2023年4月27日,恺英网络股份有限公司(以下简称“恺英网络”或“公...
人民网北京5月6日电(记者李栋)农业农村部最新数据显示,4月份,农...
地处湘西大山深处的辰溪县罗子山瑶族乡学校地处边远瑶乡山区,2019...
青海移动发文宣布,青海移动、北京启明星辰共同为青海移动网络安全...
本报北京电(记者柴逸扉)今年9月在杭州开幕的第19届亚运会是两岸体...
今天来聊聊关于描述英文单词的文章,现在就为大家来简单介绍下描述...
1、恢复一下出厂设置吧…应该是升级的过程中出现某个文件与校园网不...
尽管本周油价大幅走低,但现货市场保持紧俏的迹象表明此前的抛售可...
婆娑的意思,婆娑是什么意思这个很多人还不知道,现在让我们一起来看...
重庆市涪陵区气象台2023年5月5日22时45分发布雷电黄色预警信号:“预...
5月5日上午,“大美云南·云水典范”珍茗云水摄影展在云南省图书馆开展。
1、他是一个著名的水上之城。2、面积:只有6 9平方公里。3、人口:...
1、正聘是一个汉语词语。2、读音是zhèngpìn。3、是谓诸侯间因公事...
继百亿补贴之后,京东低价策略在618前再迈一步。记者近日从京东内部...
智通财经APP讯明志科技688355SH披露向特定对象发行A股股票预案发行...