前面写了安装功能驱动,过滤驱动,本篇谈谈调整过滤驱动的位置。设备栈上总线驱动和功能驱动的数量比较固定,但过滤驱动就不一样了,可以不断的往设备栈上叠加。如果仅仅像垒书本一样,往现有堆栈顶添加过滤驱动使得设备栈的深度不断增加,倒也简单。但如果要调整一下过滤驱动的位置,比如从最顶端移到较低的位置,那该怎么做?本篇的写作目的就是回答这个疑问。
仍然以toaster的过滤驱动为例(不要质问我为什么老拿它开刀,因为其他的我也不会)。我为toaster添加了2个类下层过滤驱动:将clslower.sys一式两份,取名为clslower.sys和clslower1.sys。同时修改clafilter用以添加这对双胞胎:
下列为clslower.sys的inf文件clslower.inf
[Version]
signature = "$Windows NT$"
[SourceDisksNames]
1 = %ClasFilt.MediaDesc%
[SourceDisksFiles]
clslower.sys = 1
[DestinationDirs]
DefaultDestDir = 12 ; DIRID_DRIVERS
[DefaultInstall.NT]
CopyFiles = @clslower.sys
AddReg = ClassFilter_AddReg
[ClassFilter_AddReg]
HKLM, System\CurrentControlSet\Control\Class\{b85b7c50-6a01-11d2-b841-00c04fad5171}, LowerFilters, 0x00010008, clasfilt0
[DefaultInstall.NT.Services]
AddService = clasfilt0, , clasfilt_Service_Inst
[clasfilt_Service_Inst]
DisplayName = %ClasFilt.SvcDesc%
ServiceType = %SERVICE_KERNEL_DRIVER%
StartType = %SERVICE_DEMAND_START%
ErrorControl = %SERVICE_ERROR_IGNORE%
ServiceBinary = %12%\clslower.sys
[Strings]
ClasFilt.SvcDesc = "Lower Class 0 Filter Driver"
ClasFilt.MediaDesc = "Class Filter 0 Driver Disc"
SERVICE_KERNEL_DRIVER = 1
SERVICE_DEMAND_START = 3
SERVICE_ERROR_IGNORE = 0
REG_EXPAND_SZ = 0x00020000
REG_DWORD = 0x00010001
下列为clslower1.sys的inf文件clslower1.inf
[Version]
signature = "$Windows NT$"
[SourceDisksNames]
1 = %ClasFilt.MediaDesc%
[SourceDisksFiles]
clslower1.sys = 1
[DestinationDirs]
DefaultDestDir = 12 ; DIRID_DRIVERS
[DefaultInstall.NT]
CopyFiles = @clslower1.sys
AddReg = ClassFilter_AddReg
[ClassFilter_AddReg]
HKLM, System\CurrentControlSet\Control\Class\{b85b7c50-6a01-11d2-b841-00c04fad5171}, LowerFilters, 0x00010008, clasfilt
[DefaultInstall.NT.Services]
AddService = clasfilt, , clasfilt_Service_Inst
[clasfilt_Service_Inst]
DisplayName = %ClasFilt.SvcDesc%
ServiceType = %SERVICE_KERNEL_DRIVER%
StartType = %SERVICE_DEMAND_START%
ErrorControl = %SERVICE_ERROR_IGNORE%
ServiceBinary = %12%\clslower1.sys
[Strings]
ClasFilt.SvcDesc = "Lower Class Filter Driver"
ClasFilt.MediaDesc = "Class Filter Driver Disc"
SERVICE_KERNEL_DRIVER = 1
SERVICE_DEMAND_START = 3
SERVICE_ERROR_IGNORE = 0
REG_EXPAND_SZ = 0x00020000
REG_DWORD = 0x00010001
右键安装这两个类过滤驱动后,可以看到如下结果:
注册表LowerFilter项显示toaster类设备有两个类下层驱动;设备管理器大概也是从注册表读取信息,因此有同样的值。用windbg查看toaster设备栈:
kd> !drvobj toaster ;参看toaster驱动对象信息
Driver object (fffffa80051dbe70) is for:
\Driver\toaster
Driver Extension List: (id , addr)
Device Object list:
fffffa8005a56bb0 fffffa80051dccc0
kd> !devstack fffffa8005a56bb0 ;toaster设备对象的设备栈信息
!DevObj !DrvObj !DevExt ObjectName
> fffffa8005a56bb0 \Driver\toaster fffffa8005a56d00 -->toaster功能设备
fffffa80059ce8c0 \Driver\clasfilt0 fffffa80059cea10 -->类过滤驱动
fffffa8003e7a460 \Driver\clasfilt fffffa8003e7a5b0 -->类过滤驱动
fffffa8003dfb080 \Driver\busenum fffffa8003dfb1d0 000000b6
!DevNode fffffa8004b2e9d0 :
DeviceInst is "{B85B7C50-6A01-11d2-B841-00C04FAD5171}\MsToaster\1&79f5d87&0&01"
ServiceName is "toaster"
windbg罗列了toaster设备栈的堆叠情况,从结果来看classfilter0堆叠在clasfilter之上。如果你看过前一篇文章,可能记得
删除驱动时会调用GetFilters,GetFilters通过GetDeviceRegistryProperty函数从注册表中获得过滤驱动的信息,返回的结果是一个字符串数组。对于这里的情况,字符串数组的内容应该包括clasfilt和clasfilt0两个字符串。移除驱动的时候,是把其中一个字符串从字符串数组中移除,然后再调用SetDeviceRegistryProperty把结果写回注册表。受此启发,你可能会想到,可以直接在注册表中调整两个字符串的位置,到达调整驱动位置的目的。为此,我们来验证这个猜想的正确性。
验证的步骤如下:首先停用设备然后修改注册表LowerFilter,最后启用设备用windbg查看设备栈:
图为修改后注册表的值,重新启用设备,查看设备栈的值:
kd> !drvobj toaster
Driver object (fffffa80051dbe70) is for:
\Driver\toaster
Driver Extension List: (id , addr)
Device Object list:
fffffa8005a12cc0 fffffa80051dccc0
kd> !devstack fffffa8005a12cc0
!DevObj !DrvObj !DevExt ObjectName
> fffffa8005a12cc0 \Driver\toaster fffffa8005a12e10
fffffa8003fc7600 \Driver\clasfilt fffffa8003fc7750
fffffa800408b040 \Driver\clasfilt0 fffffa800408b190
fffffa8003dfb080 \Driver\busenum fffffa8003dfb1d0 000000b6
!DevNode fffffa8004b2e9d0 :
DeviceInst is "{B85B7C50-6A01-11d2-B841-00C04FAD5171}\MsToaster\1&79f5d87&0&01"
ServiceName is "toaster"
不出所料,设备栈中的过滤驱动果然发生了变化,猜想可行,接下来就是用程序实现调整驱动了。其实winddk已经实现了这部分代码为于src/setup/devcon/Cmds.cpp的cmdClassFilter函数中。这个函数对应于强大的devcon classfilter命令,可以通过devcon help classfilter查看命令帮助文档。