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下可以看到裝置對象。
如圖所示,裝置出現在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資訊:
1)通過ROOT\Unknow\0000索引驅動的service為busenum
在HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\{SerivceName}下可以找到各種驅動注冊的服務相關的系統資料庫值:
對于busenum驅動ServiceName是busenum
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系統資料庫項: