DDK样例toaster分析(2)

转载:http://blog.csdn.net/lixiangminghate/article/details/51705710

前一篇 DDK样例toaster分析(1) 主要讨论了toaster样例中的busenum总线驱动。本篇将讨论从总线驱动过渡到功能驱动,也就是toaster.sys。

成功安装busenum.sys后,运行toaster/exe/enum目录下的enum程序模拟一个toaster设备插入:

[cpp] view plain copy

  1. enum -p 1

前面busenum.sys!Bus_AddDevice创建Fdo的同时还为Fdo创建一个接口:

[cpp] view plain copy

  1. status = IoRegisterDeviceInterface (
  2.                 PhysicalDeviceObject,
  3.                 (LPGUID) &GUID_DEVINTERFACE_BUSENUM_TOASTER,
  4.                 NULL,
  5.                 &deviceData->InterfaceName);
  6. DEFINE_GUID (GUID_DEVINTERFACE_BUSENUM_TOASTER,
  7.         0xD35F7840, 0x6A0C, 0x11d2, 0xB8, 0x41, 0x00, 0xC0, 0x4F, 0xAD, 0x51, 0x71);
  8. //  {D35F7840-6A0C-11d2-B841-00C04FAD5171}

enum.exe通过SetupDi函数打开并通过ioctl访问这个接口:

[cpp] view plain copy

  1. hardwareDeviceInfo=SetupDiGetClassDevs(GUID_DEVINTERFACE_BUSENUM_TOASTER,…);
  2. SetupDiEnumDeviceInterfaces(hardwareDeviceInfo,…,&deviceInterfaceData);
  3. file = CreateFile ( deviceInterfaceDetailData->DevicePath,…);

调用Ioctl后,最终进入到Bus_Ioctl中,因为是插入设备,所以最终会调用Bus_PlugInDevice

[cpp] view plain copy

  1. NTSTATUS
  2. Bus_PlugInDevice (
  3.     PBUSENUM_PLUGIN_HARDWARE    PlugIn,
  4.     ULONG                       PlugInSize,
  5.     PFDO_DEVICE_DATA            FdoData
  6.     )

先看下FdoData中的内容,确定enum打开的是busenum.sys创建的Fdo:

[cpp] view plain copy

  1. kd> dd FdoData l1
  2. 0x81ec60e8
  3. kd> dt _FDO_DEVICE_DATA 81ec60e8
  4. busenum!_FDO_DEVICE_DATA
  5.     +0x01c UnderlyingPDO    : 0x823e73d0 _DEVICE_OBJECT
  6. kd> !devobj 0x823e73d0
  7. Device object (823e73d0) is for:
  8.  00000034 \Driver\PnpManager DriverObject 823eb2b0
  9. Current Irp 00000000 RefCount 1 Type 00000004 Flags 00001040
  10. Dacl e1594174 DevExt 823e7488 DevObjExt 823e7490 DevNode 823e7288
  11. ExtensionFlags (0000000000)
  12. AttachedDevice (Upper) 81ec6030 \Driver\busenum
  13. Device queue is not busy.

FdoData用UnderlyingPDO指出了堆叠在设备下面的设备。从windbg的输出看出,UnderlyingPDO就是busenum.sys所依赖的pnpmanager设备对象。

M$的帮助文档将busenum.sys!Bus_AddDevice创建的设备描述为Fdo,而将Bus_PlugInDevice创建的设备描述为Pdo。这是因为在Bus_PlugInDevice中创建出来的devobj代表了busenum总线对象,作为toaster.sys创建的设备对象的堆叠基石。另外也可以从windbg的输出看到,busenum新创建的设备对象并没有attach到任何已有设备对象上:
1).调用Bus_PlugInDevice!IoCreateDeviceSecure前,属于busenum.sys驱动对象的设备对象:

[cpp] view plain copy

  1. kd> !drvobj busenum
  2. Driver object (81dfdda0) is for:
  3.  \Driver\busenum
  4. Driver Extension List: (id , addr)
  5. Device Object list:
  6. 81ec6030 <—是attach在\Driver\PnpManager上的Fdo对象,上一张图中有描述
[cpp] view plain copy

  1. kd> !devstack 81ec6030
  2.   !DevObj   !DrvObj            !DevExt   ObjectName
  3. > 81ec6030  \Driver\busenum    81ec60e8
  4.   823e73d0  \Driver\PnpManager 823e7488  00000034
  5. !DevNode 823e7288 :
  6.   DeviceInst is “Root\UNKNOWN\0000”
  7.   ServiceName is “busenum”

上图中,busenum.sys只有一个设备对象
2).调用IoCreateDeviceSecure后,busenum.sys会新增一个设备对象:

[cpp] view plain copy

  1. kd> !drvobj busenum
  2. Driver object (81dfdda0) is for:
  3.  \Driver\busenum
  4. Driver Extension List: (id , addr)
  5. Device Object list:
  6. 82062408<—新加的设备对象  81ec6030 <—原有的设备对象
  7. kd> !devobj 82062408
  8. Device object (82062408) is for:
  9.  0000008a \Driver\busenum DriverObject 81dfdda0
  10. Current Irp 00000000 RefCount 0 Type 0000002a Flags 000000c0
  11. Dacl e23ad84c DevExt 820624c0 DevObjExt 820624f8
  12. ExtensionFlags (0000000000)
  13. Device queue is not busy.

从windbg输出可以看到,这个新的设备对象下面并没有attach其他设备对象

之后,busenum为这个新创建的设备对象创建HardwareID(总线设备的职责不就是为新加入的设备分配设备ID吗?)

[cpp] view plain copy

  1. pdoData->HardwareIDs =
  2.             ExAllocatePoolWithTag (NonPagedPool, length, BUSENUM_POOL_TAG);
  3. RtlCopyMemory (pdoData->HardwareIDs, PlugIn->HardwareIDs, length);
  4. 后分配busenum pdo的HardwardID
  5. kd> dd pdoData l1
  6. b21fdbec  820624c0
  7. kd> dt _PDO_DEVICE_DATA  820624c0
  8. busenum!_PDO_DEVICE_DATA
  9.     +0x020 HardwareIDs      : 0x8213aa50  -> 0x7b
  10. kd> du 0x8213aa50 <——注意,这是busenum.sys为pdo对象设置的硬件id,之后要按这个id匹配功能驱动
  11. 8213aa50  “{B85B7C50-6A01-11d2-B841-00C04FA”
  12. 8213aa90  “D5171}\MsToaster”

最后,Bus_PlugInDevice通过IoInvalidateDeviceRelations,通知pnp管理器:有新的设备加入设备树,pnp管理器要更新设备树关系(说人话,就是为新设备加载匹配的驱动)

由于系统中并没有安装这个Pdo的驱动,因此会跳出搜索驱动的对话框,这里选择手动安装,选择toaster/inf/sample.inf文件。至于为什么要选这个文件,因为sample.inf文件的硬件兼容列表里表示支持这个设备:

[cpp] view plain copy

  1. [Manufacturer]
  2. %StdMfg%=Standard
  3. [Standard]
  4. ; DisplayName               Section           DeviceId
  5. ; ———–               ——-           ——–
  6. %ToasterDevice.DeviceDesc%=Toaster_Device, {b85b7c50-6a01-11d2-b841-00c04fad5171}\MsToaster <—硬件兼容列表

这个列表中的内容完全匹配新创建设备对象的HardwareID,因此系统加载sample.inf中指定的sys文件,并创建对应的服务,最后把执行权限交给toaster.sys:

[cpp] view plain copy

  1. [Version]
  2. Signature=“$WINDOWS NT$”
  3. Class=TOASTER
  4. ClassGuid={B85B7C50-6A01-11d2-B841-00C04FAD5171}
  5. Provider=%MSFT%
  6. DriverVer=09/21/2006,6.0.5736.1
  7. CatalogFile=toaster.cat
  8. [Toaster_Device.NT]
  9. CopyFiles=Toaster_Device.NT.Copy
  10. [Toaster_Device.NT.Copy]
  11. toaster.sys

驱动安装后,设备管理器里多出一个toaster设备,查看Driver Detail可以看到驱动文件的信息:


扯点题外话,可以通过Update Driver替换新的inf文件,比如选择toasterf.inf(含设备过滤驱动的toaster.sys),并指定sys文件路径后,再查看Driver Detail可以看到功能驱动和过滤驱动:(tmd公司要做驱动测试,测试老问我加载过滤驱动后,怎么在设备管理器里看到!还一定要在设备管理器里看到,注册表里不算,我折腾很久才发现这个!!)

当然这种更新操作要底层设备支持disable/enable,像磁盘设备的,不支持disable/enable操作就不能这样更新驱动(这要感谢同事周AM的解释)
好好,扯远了,回到正题,执行权从busenum.sys过渡到toaster.sys。当然了进入toaster.sys后还会调用toaster的AddDevice函数ToasterAddDevice,因此要在这个函数上下断:

[cpp] view plain copy

  1. DriverEntry
  2. kd> !drvobj 8216db10
  3. Driver object (8216db10) is for:
  4.  \Driver\toaster
  5. Driver Extension List: (id , addr)
  6. Device Object list:
[cpp] view plain copy

  1. kd> bp toaster!ToasterAddDevice;g
  2. kd> dd DriverObject l1
  3. f8aed9e8  8216db10
  4. kd> !drvobj 8216db10
  5. Driver object (8216db10) is for:
  6.  \Driver\toaster
  7. Driver Extension List: (id , addr)
  8. Device Object list:

刚进入ToasterAddDevice时,驱动对象下还没有设备对象。顺带看下ToasterAddDevice的接口

[cpp] view plain copy

  1. NTSTATUS
  2. ToasterAddDevice(
  3.     __in PDRIVER_OBJECT DriverObject,
  4.     __in PDEVICE_OBJECT PhysicalDeviceObject
  5.     )

DriverObject不用说肯定是toaster.sys的,PhysicalDeviceObject,则是前面busenum创建的pdo了(由于刚才更新驱动时停用启用过设备,设备对象跟上文不能连续了,不过还是能通过!drvobj !devstack来观察结果):

[cpp] view plain copy

  1. kd> dd PhysicalDeviceObject l1 ;<—PhysicalDeviceObject的值
  2. f8ae99ec  82062408
  3. kd> !devstack 82062408  ;<—通过设备堆栈证明这个是前面busenum创建的Pdo
  4.   !DevObj   !DrvObj            !DevExt   ObjectName
  5. > 82062408  \Driver\busenum    820624c0  0000008a ;<—这个设备对象下面并没有attach其他设备,跟上文的结论一下,因此可以认为是Pdo
  6. !DevNode 82266878 :
  7.   DeviceInst is “{B85B7C50-6A01-11d2-B841-00C04FAD5171}\MsToaster\1&1aafb3d5&0&01”
  8.   ServiceName is “toaster”
  9. kd> !drvobj busenum  ;<—当然,有人不信,那只能列出busenum驱动对象下的设备对象
  10. Driver object (81dfdda0) is for:
  11.  \Driver\busenum
  12. Driver Extension List: (id , addr)
  13. Device Object list:
  14. 82062408  81ec6030  <—这个驱动对像目前只有2个设备对象,为了证明82062408对象是Pdo,只要证明81ec6030  是Fdo就行了,剩下的靠排除法就能证明
[cpp] view plain copy

  1. kd> !devstack 81ec6030 ;<—81ec6030的设备栈显示,这个就是Fdo,attach在pnpmanager设备对象上
  2. !DevObj !DrvObj !DevExt ObjectName
  3. > 81ec6030 \Driver\busenum 81ec60e8 823e73d0 \Driver\PnpManager 823e7488 00000034!DevNode 823e7288 : DeviceInst is “Root\UNKNOWN\0000” ServiceName is “busenum”

 


之后,Toaster.sys调用IoCreateDevice创建功能驱动(注意是toaster.sys的Fdo不是busenum.sys的Fdo),把这个Fdo堆叠到busenum.sys的Pdo上:

[html] view plain copy

  1. status = IoCreateDevice (DriverObject,
  2.                              sizeof (FDO_DATA),
  3.                              NULL,
  4.                              FILE_DEVICE_UNKNOWN,
  5.                              FILE_DEVICE_SECURE_OPEN,
  6.                              FALSE,
  7.                              &deviceObject);
  8. fdoData->NextLowerDriver = IoAttachDeviceToDeviceStack (deviceObject,
  9.                                                        PhysicalDeviceObject);

这样就完成了从busenum到toaster的过渡。

发表评论

电子邮件地址不会被公开。 必填项已用*标注