天天看点

DDK样例toaster分析(1)

    msddk样例中toaster是一个比较完整和值得学习的pnp驱动,包括了一个完整的设备栈(含总线驱动/功能驱动,以及设备栈中各层过滤驱动)和驱动安装程序(含驱动安装包/类安装程序/协安装程序)。本篇记录在xp下调试busenum驱动入口(关于环境的搭建网上一搜一大把,这里就省了,当然也可以参考这篇:​​win7 x64部署和串口调试虚拟驱动toaster​​)。

    通过添加硬件的方式安装busenum.sys后,会依次进入busenum.c!DriverEntry和pnp.c!Bus_AddDevice。AddDevice是本篇的重点,因此进入DriverEntry后在这个函数上下一个断点:

kd> lmvm busenum //查看驱动和调试符号加载是否正确
start    end        module name
b20e9000 b20f2b80   busenum    (private pdb symbols)  d:\winddk\7600.16385.1\src\general\toaster\wdm\bus\objchk_wxp_x86\i386\BusEnum.pdb
    Loaded symbol image file: busenum.sys 

kd> !itoldyouso busenum
busenum.sys
    Timestamp: 57639546
  SizeOfImage: 9B80
          pdb: d:\winddk\7600.16385.1\src\general\toaster\wdm\bus\objchk_wxp_x86\i386\BusEnum.pdb
      pdb sig: A0EB3691-6995-416E-9BF4-C25A160C9318
          age: 1
Loaded pdb is d:\winddk\7600.16385.1\src\general\toaster\wdm\bus\objchk_wxp_x86\i386\BusEnum.pdb
BusEnum.pdb
      pdb sig: A0EB3691-6995-416E-9BF4-C25A160C9318
          age: 1

MATCH: BusEnum.pdb and busenum.sys      

确定sys文件加载正确后,查找函数并下断点,然后继续运行:

kd> x busenum!Bus_AddDevice
b20eca60 busenum!Bus_AddDevice (struct _DRIVER_OBJECT *, struct _DEVICE_OBJECT *)
kd> bp busenum!Bus_AddDevice
kd> bl
 1 e b20eca60     0001 (0001) busenum!Bus_AddDevice      

当windbg进入Bus_AddDevice遇到断点时,函数有两个参数:PDRIVER_OBJECT DriverObject和PDEVICE_OBJECT PhysicalDeviceObject。DriverObject很好理解,就是busenum.sys,有windbg为证:

kd> dd DriverObject l1
f8ae99e8  8227a3b8

kd> !drvobj 8227a3b8
Driver object (8227a3b8) is for:
 \Driver\busenum      

PhysicalDeviceObject是什么 呢?如果是pnp设备驱动,那很简单,这就是底层总线驱动对应的设备。但busenum本身是总线驱动,谁提供底层设备?答案是pnp管理器

kd> dd PhysicalDeviceObject l1
f8ae99ec  81f41030
kd> !devobj 81f41030 ---> 这个设备是pnp创建的设备
Device object (81f41030) is for:
 00000082 \Driver\PnpManager DriverObject 823eb2b0 ---> windbg指出,创建设备对象的驱动对象

kd> !drvobj 823eb2b0
Driver object (823eb2b0) is for:
 \Driver\PnpManager  --->驱动对象
Driver Extension List: (id , addr)
该驱动对象的设备对象
Device Object list:
81f41030  823e73d0  823e7610  823e7850      

原来,pnp管理器为了维护一颗设备树,在加载总线驱动前会为总线设备创建一个pnpmanage设备对象,作为设备栈的栈底对象,让总线设备attach上去。在busenum.sys代码中也有这种设备栈的上下体现:

NTSTATUS
Bus_AddDevice(
    __in PDRIVER_OBJECT DriverObject,
    __in PDEVICE_OBJECT PhysicalDeviceObject
    )
{
    status = IoCreateDevice (
                    DriverObject,...,&deviceObject);
    deviceData->UnderlyingPDO = PhysicalDeviceObject;
    deviceData->NextLowerDriver = IoAttachDeviceToDeviceStack (
                                    deviceObject,
                                    PhysicalDeviceObject);
}      

首先代码创建busenum.sys的设备对象,然后attach到pnpmanager设备对象上。难怪toaster的帮助文档中注释这个对象为Fdo,而把Bus_AddDevice的第二个参数认为是Pdo。

来看下创建设备后设备栈情况:

kd> !drvobj 8227a3b8
Driver object (8227a3b8) is for:
 \Driver\busenum
Driver Extension List: (id , addr)
;相比刚进入DriverEntry时,现在busenum驱动对象下已经有一个设备对象了,这个就是调用IoCreateDevice时创建的
Device Object list:
81f2a930      
kd> dd deviceObject l1
f8ae99dc  81f2a930 ;设备对象的地址
kd> !devobj 81f2a930 ;验证一下设备对象的属主
Device object (81f2a930) is for:
  \Driver\busenum DriverObject 8227a3b8 
Current Irp 00000000 RefCount 0 Type 0000002a Flags 00000088
DevExt 81f2a9e8 DevObjExt 81f2aa90 
ExtensionFlags (0000000000)  
Device queue is not busy.      
kd> !devstack 81f2a930 ;81f2a930就是前面IoCreateDevice创建的设备对象

  !DevObj   !DrvObj            !DevExt   ObjectName
 > 81f2a930  \Driver\busenum    81f2a9e8  
  81f41030  \Driver\PnpManager 00000000  00000082
  !DevNode 81f2a008 :
  DeviceInst is "ROOT\UNKNOWN\0000" ;设备实例
  ServiceName is "busenum"          ;设备对应的服务名      

至此busenum的设备栈已经成形了,可以创建Fdo了。

在结束本文前,还有一些琐碎的东西需要记录。就是busenum.inf中DDinstall section

    安装busenum驱动后,打开设备管理器,在system devices下可以看到设备对象。

DDK样例toaster分析(1)

如图所示,设备出现在system devices下,设备实例是ROOT\Unknow\0000。问题来了,为什么会这样?

首先,设备管理器是以类设备为视图,不同的设备类归入不同的类下(物以类聚)。因此出现在system devices下一定是刻意设定,那么这由谁来设定?当然是inf文件了,在version节中指定:下面的内容摘自bus.inf

[Version]
Signature="$WINDOWS NT$"
Class=System ;指明busenum属于system类
ClassGuid={4D36E97D-E325-11CE-BFC1-08002BE10318} ;类的guid
Provider=%MSFT%
DriverVer=09/21/2006,6.0.5736.1
CatalogFile=toaster.cat      

其次,硬件ID,由inf文件DDinstall节指定,msdn文档上一般将DDinstall节认为是从Manufacturer开始:

[Manufacturer]
%StdMfg%=Standard

[Standard]
; These are the toaster bus pnp ids

%ToasterBus.DeviceDesc%=ToasterBus_Device, root\busenum ;root\busenum指定了设备的HardwareID      

有了这两项,在结合驱动在注册表下的路径可以找到相应的信息:

先确定设备的总线关系,inf文件中已经指出了busenum属于root总线,它在注册表中的路径为:

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\Root

设备实例ROOT\Unknow\0000表明,busenum在root总线的Unknow\0000下,在这个项中可以找到驱动的service和class信息:

DDK样例toaster分析(1)

1)通过ROOT\Unknow\0000索引驱动的service为busenum

在HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\{SerivceName}下可以找到各种驱动注册的服务相关的注册表值:

对于busenum驱动ServiceName是busenum

DDK样例toaster分析(1)

ImagePath是驱动程序被安装的路径,这些信息在Inf文件中都有对应内容,

[ToasterBus_Device.NT.Services] ;这个节是服务安装节
AddService = busenum,%SPSVCINST_ASSOCSERVICE%, busenum_Service_Inst      
;AddService对应驱动在HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\下创建的服务名
{4D36E97D-E325-11CE-BFC1-08002BE10318}
; -------------- busenum driver install sections
[busenum_Service_Inst]
DisplayName    = %busenum.SVCDESC% ;<span style="font-family: Arial, Helvetica, sans-serif;">busenum.SVCDESC</span><span style="font-family: Arial, Helvetica, sans-serif;">=busenum.SVCDESC = "Toaster Bus Enumerator"对应注册表项DisplayName和在设备管理器上显示的名字</span>
ServiceType    = 1               ; SERVICE_KERNEL_DRIVER 
StartType      = 3               ; SERVICE_DEMAND_START <span style="font-family: Arial, Helvetica, sans-serif;">;对应注册表的Start</span>
ErrorControl   = 1               ; SERVICE_ERROR_NORMAL
ServiceBinary  = %12%\busenum.sys                       ;对应注册表中ImagePath
LoadOrderGroup = Extended Base      

2)通过ROOT\Unknow\0000索引驱动的class信息

在HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Class\{ClassGuid}

对于busenum驱动ClassGuid是{4D36E97D-E325-11CE-BFC1-08002BE10318},挨个找过去可以找到busenum注册表项:

继续阅读