[zz]驅動對象設備對象設備棧亂雜談

作者: JIURL

主頁: http://jiurl.yeah.net  

用有限的幾句話就舒舒服服的建立起對驅動對象和設備對象的概念是不可能的。剛開始是一片模糊,瞭解的多了,慢慢就清楚。下面的內容會使你對他們瞭解的清楚些。
  爲了後面的敘述方便,首先列出驅動對象和設備對象的結構。
  驅動對象結構 DRIVER_OBJECT ,定義如下
  struct _DRIVER_OBJECT (sizeof=168)
  +00 int16 Type
  +02 int16 Size
  +04 struct _DEVICE_OBJECT *DeviceObject
  +08 uint32 Flags
  +0c void *DriverStart
  +10 uint32 DriverSize
  +14 void *DriverSection
  +18 struct _DRIVER_EXTENSION *DriverExtension
  +1c struct _UNICODE_STRING DriverName
  +1c uint16 Length
  +1e uint16 MaximumLength
  +20 uint16 *Buffer
  +24 struct _UNICODE_STRING *HardwareDatabase
  +28 struct _FAST_IO_DISPatch *FastIoDispatch
  +2c function *DriverInit
  +30 function *DriverStartIo
  +34 function *DriverUnload
  +38 function *MajorFunction[28]
  DDK 中有對於一些域的說明
  [00] IRP_MJ_CREATE
  [01] IRP_MJ_CREATE_NAMED_PIPE
  [02] IRP_MJ_CLOSE
  [03] IRP_MJ_READ
  [04] IRP_MJ_WRITE
  [05] IRP_MJ_QUERY_INFORMATION
  [06] IRP_MJ_SET_INFORMATION
  [07] IRP_MJ_QUERY_EA
  [08] IRP_MJ_SET_EA
  [09] IRP_MJ_FLUSH_BUFFERS
  [0a] IRP_MJ_QUERY_VOLUME_INFORMATION
  [0b] IRP_MJ_SET_VOLUME_INFORMATION
  [0c] IRP_MJ_DIRECTORY_CONTROL
  [0d] IRP_MJ_FILE_SYSTEM_CONTROL
  [0e] IRP_MJ_DEVICE_CONTROL
  [0f] IRP_MJ_INTERNAL_DEVICE_CONTROL
  [10] IRP_MJ_SHUTDOWN
  [11] IRP_MJ_LOCK_CONTROL
  [12] IRP_MJ_CLEANUP
  [13] IRP_MJ_CREATE_MAILSLOT
  [14] IRP_MJ_QUERY_SECURITY
  [15] IRP_MJ_SET_SECURITY
  [16] IRP_MJ_POWER
  [17] IRP_MJ_SYSTEM_CONTROL
  [18] IRP_MJ_DEVICE_CHANGE
  [19] IRP_MJ_QUERY_QUOTA
  [1a] IRP_MJ_SET_QUOTA
  [1b] IRP_MJ_PNP
  struct _DRIVER_EXTENSION (sizeof=24)
  +00 struct _DRIVER_OBJECT *DriverObject
  +04 function *AddDevice
  +08 uint32 Count
  +0c struct _UNICODE_STRING ServiceKeyName
  +0c uint16 Length
  +0e uint16 MaximumLength
  +10 uint16 *Buffer
  +14 struct _IO_CLIENT_EXTENSION *ClientDriverExtension
  設備對象結構 DEVICE_OBJECT ,定義如下
  struct _DEVICE_OBJECT (sizeof=184)
  +00 int16 Type
  +02 uint16 Size
  +04 int32 ReferenceCount
  +08 struct _DRIVER_OBJECT *DriverObject
  +0c struct _DEVICE_OBJECT *NextDevice
  +10 struct _DEVICE_OBJECT *AttachedDevice
  +14 struct _IRP *CurrentIrp
  +18 struct _IO_TIMER *Timer
  +1c uint32 Flags
  +20 uint32 Characteristics
  +24 struct _VPB *Vpb
  +28 void *DeviceExtension
  +2c uint32 DeviceType
  +30 char StackSize
  +34 union __unnamed62 Queue
  +34 struct _LIST_ENTRY ListEntry
  +34 struct _LIST_ENTRY *Flink
  +38 struct _LIST_ENTRY *Blink
  +34 struct _WAIT_CONTEXT_BLOCK Wcb
  +34 struct _KDEVICE_QUEUE_ENTRY WaitQueueEntry
  +34 struct _LIST_ENTRY DeviceListEntry
  +34 struct _LIST_ENTRY *Flink
  +38 struct _LIST_ENTRY *Blink
  +3c uint32 SortKey
  +40 byte Inserted
  +44 function *DeviceRoutine
  +48 void *DeviceContext
  +4c uint32 NumberOfMapRegisters
  +50 void *DeviceObject
  +54 void *CurrentIrp
  +58 struct _KDPC *BufferChainingDpc
  +5c uint32 AlignmentRequirement
  +60 struct _KDEVICE_QUEUE DeviceQueue
  +60 int16 Type
  +62 int16 Size
  +64 struct _LIST_ENTRY DeviceListHead
  +64 struct _LIST_ENTRY *Flink
  +68 struct _LIST_ENTRY *Blink
  +6c uint32 Lock
  +70 byte Busy
  +74 struct _KDPC Dpc
  +74 int16 Type
  +76 byte Number
  +77 byte Importance
  +78 struct _LIST_ENTRY DpcListEntry
  +78 struct _LIST_ENTRY *Flink
  +7c struct _LIST_ENTRY *Blink
  +80 function *DeferredRoutine
  +84 void *DeferredContext
  +88 void *SystemArgument1
  +8c void *SystemArgument2
  +90 uint32 *Lock
  +94 uint32 ActiveThreadCount
  +98 void *SecurityDescriptor
  +9c struct _KEVENT DeviceLock
  +9c struct _DISPATCHER_HEADER Header
  +9c byte Type
  +9d byte Absolute
  +9e byte Size
  +9f byte Inserted
  +a0 int32 SignalState
  +a4 struct _LIST_ENTRY WaitListHead
  +a4 struct _LIST_ENTRY *Flink
  +a8 struct _LIST_ENTRY *Blink
  +ac uint16 SectorSize
  +ae uint16 Spare1
  +b0 struct _DEVOBJ_EXTENSION *DeviceObjectExtension
  +b4 void *Reserved
  DDK 中有對於一些域的說明
  struct _DEVOBJ_EXTENSION (sizeof=36)
  +00 int16 Type
  +02 uint16 Size
  +04 struct _DEVICE_OBJECT *DeviceObject
  +08 uint32 PowerFlags
  +0c *Dope
  +10 uint32 ExtensionFlags
  +14 void *DeviceNode
  +18 struct _DEVICE_OBJECT *AttachedTo
  +1c struct _LIST_ENTRY FileObjectList
  +1c struct _LIST_ENTRY *Flink
  +20 struct _LIST_ENTRY *Blink
  有一個載入內存的驅動程序文件,就會有一個驅動對象(DRIVER_OBJECT)。
  比如,驅動 i8042prt 是在系統初始化階段,IO 管理器調用函數 nt!IopLoadDriver 載入的。nt!IopLoadDriver 讀取註冊表,獲得驅動程序文件 i8042prt.SYS 的路徑,將這個文件載入內存。之後會調用 nt!ObCreateObject 創建一個驅動對象,並初始化這個驅動對象。
  設備對象(DEVICE_OBJECT)由驅動創建。一個驅動可以創建多個設備對象(DEVICE_OBJECT)。通過驅動對象(DRIVER_OBJECT),可以找到由該驅動創建的所有設備對象(DEVICE_OBJECT)。一個驅動創建的所有設備對象(DEVICE_OBJECT)鏈成一條鏈,該驅動的驅動對象(DRIVER_OBJECT)可以找到這個鏈。一個設備對象(DEVICE_OBJECT)也可以找到創建它的驅動的驅動對象(DRIVER_OBJECT)。下面我們使用 WinDBG 實際觀察驅動 i8042prt 的情況,i8042prt 是完成 ps/2 鍵盤驅動主要功能的驅動程序。
  在這裏我們先做個說明,對於同時插有 ps/2 鍵盤和 ps/2 鼠標的計算機上, i8042prt 會創建兩個設備對象,一個用於鍵盤,一個用於鼠標。
  首先我們從命名對象地址空間,找到 i8042prt 的 DRIVER_OBJECT 的地址
  kd> !object \driver\i8042prt
  Object: fe4f69f0 Type: (fe4ec3e0) Driver
  ObjectHeader: fe4f69d8
  HandleCount: 0 PointerCount: 5
  Directory Object: fe51bf30 Name: i8042prt
  下面我們看 i8042prt 的 DRIVER_OBJECT 中的內容 
  kd> !strct driver_object fe4f69f0
  struct _DRIVER_OBJECT (sizeof=168)
  +00 int16 Type = 0004
  +02 int16 Size = 00a8
  +04 struct _DEVICE_OBJECT *DeviceObject = FE4D3BA0 
  // 注意 DeviceObject 鏈上的第一個設備對象
  +08 uint32 Flags = 00000012
  +0c void *DriverStart = FE1BD000
  +10 uint32 DriverSize = 00021000
  +14 void *DriverSection = FE4F6CC8
  +18 struct _DRIVER_EXTENSION *DriverExtension = FE4F6A98
  +1c struct _UNICODE_STRING DriverName
  +1c uint16 Length = 0020
  +1e uint16 MaximumLength = 0020
  +20 uint16 *Buffer = E127FE88
  +24 struct _UNICODE_STRING *HardwareDatabase = 80541FC0
  +28 struct _FAST_IO_DISPATCH *FastIoDispatch = 00000000
  +2c function *DriverInit = FE1D8000
  +30 function *DriverStartIo = FE1BF444
  +34 function *DriverUnload = FE1CB920
  +38 function *MajorFunction[28] = FE1CB000
  80425354
  FE1CB14E
  80425354
  80425354
  80425354
  80425354
  80425354
  80425354
  FE1BE558
  80425354
  80425354
  80425354
  80425354
  FE1CB243
  FE1BE667
  80425354
  80425354
  80425354
  80425354
  80425354
  80425354
  FE1D2C63
  FE1D3633
  80425354
  80425354
  80425354
  FE1D1BFB
  我們看到了 DeviceObject 上的第一個設備對象的地址 FE4D3BA0 ,我們使用 WinDbg 的 !devobj 命令,來獲得一些信息
  kd> !devobj FE4D3BA0
  Device object (fe4d3ba0) is for:
  \Driver\i8042prt DriverObject fe4f69f0
  Current Irp 00000000 RefCount 0 Type 00000027 Flags 00002004
  DevExt fe4d3c58 DevObjExt fe4d3ed8 
  ExtensionFlags (0xc0000000) 
  Unknown flags 0xc0000000
  AttachedDevice (Upper) fe4d3a60 \Driver\vmmouse
  AttachedTo (Lower) fe4dd610 \Driver\ACPI
  Device queue is not busy.
  從獲得的信息來看,這是用於鼠標的那個設備對象,下面我們看這個設備對象 DEVICE_OBJECT 中的具體內容
  kd> !strct device_object FE4D3BA0
  struct _DEVICE_OBJECT (sizeof=184)
  +00 int16 Type = 0003
  +02 uint16 Size = 0338
  +04 int32 ReferenceCount = 00000000
  +08 struct _DRIVER_OBJECT *DriverObject = FE4F69F0 
  // 正是 \Driver\i8042prt 的驅動對象的地址
  +0c struct _DEVICE_OBJECT *NextDevice = FE4F5020
  // DeviceObject 鏈的下一個
  +10 struct _DEVICE_OBJECT *AttachedDevice = FE4D3A60
  +14 struct _IRP *CurrentIrp = 00000000
  ...
  我們看到了設備對象 +0c struct _DEVICE_OBJECT *NextDevice 處是 DeviceObject 鏈上的下一個設備對象的地址,值爲 FE4F5020 ,我們使用 WinDbg 的 !devobj 命令,來獲得一些信息
  kd> !devobj FE4F5020
  Device object (fe4f5020) is for:
  \Driver\i8042prt DriverObject fe4f69f0
  Current Irp 00000000 RefCount 0 Type 00000027 Flags 00002004
  DevExt fe4f50d8 DevObjExt fe4f5358 
  ExtensionFlags (0xc0000000) 
  Unknown flags 0xc0000000
  AttachedDevice (Upper) fe4f5df0 \Driver\Kbdclass
  AttachedTo (Lower) fe4dd730 \Driver\ACPI
  Device queue is not busy.
  從獲得的信息來看,這是用於鍵盤的那個設備對象,下面我們看這個設備對象 DEVICE_OBJECT 中的具體內容
  kd> !strct device_object FE4F5020
  struct _DEVICE_OBJECT (sizeof=184)
  +00 int16 Type = 0003
  +02 uint16 Size = 0338
  +04 int32 ReferenceCount = 00000000
  +08 struct _DRIVER_OBJECT *DriverObject = FE4F69F0
  // 正是 \Driver\i8042prt 的驅動對象的地址
  +0c struct _DEVICE_OBJECT *NextDevice = 00000000
  // 爲空,表明鏈結束了。
  +10 struct _DEVICE_OBJECT *AttachedDevice = FE4F5DF0
  +14 struct _IRP *CurrentIrp = 00000000
  ...
  我們觀察初始化時,看到 i8042prt 調用 IoCreateDevice 創建設備對象,並且 IoCreateDevice 會把新創建的這個設備對象,鏈入驅動的設備鏈中。
  現在我們對驅動對象和設備對象之間的聯繫,做一個總結,
  驅動調用 IoCreateDevice 創建設備對象,一個驅動創建的所有設備對象鏈成一個鏈,這個鏈以空表示結束。驅動對象通過 +04 struct _DEVICE_OBJECT *DeviceObject 可以找到這個鏈。設備對象通過 +0c struct _DEVICE_OBJECT *NextDevice 鏈在一起。設備對象通過 +08 struct _DRIVER_OBJECT *DriverObject 可以找到創建它的驅動的驅動對象。
  下面我們來講講設備棧。一個物理設備的驅動任務,通常由幾個驅動程序一層一層的共同完成。每層一個設備對象,他們聯繫在一起,組成一個設備棧。一個設備棧上的設備對象,從上自下,聯繫在一起。從下自上,也聯繫在一起。我們以 ps/2 鍵盤驅動爲例,使用 WinDbg 來觀察它的設備棧,以及他們如何聯繫在一起。
  ps/2 鍵盤驅動的設備棧,大概就是這個樣子
  kd> !devstack fe4f5020
  !DevObj !DrvObj !DevExt ObjectName
  fe4f5df0 \Driver\Kbdclass fe4f5ea8 KeyboardClass0
  > fe4f5020 \Driver\i8042prt fe4f50d8 
  fe4dd730 \Driver\ACPI fe507468 0000000e
  !DevNode fe4fed68 :
  DeviceInst is "ACPI\PNP0303\4&5289e18&0"
  ServiceName is "i8042prt"
  最上面的 DEVICE_OBJECT 地址爲 fe4f5df0,屬於驅動 \Driver\Kbdclass
  中間的 DEVICE_OBJECT 地址爲 fe4f5020,屬於驅動 \Driver\i8042prt
  最下面的 DEVICE_OBJECT 地址爲 fe4dd730,屬於驅動 \Driver\ACPI
  下面我們看這3個設備對象,如何聯繫在一起。
  最上面一層的 DEVICE_OBJECT
  kd> !devobj fe4f5df0
  Device object (fe4f5df0) is for:
  KeyboardClass0 \Driver\Kbdclass DriverObject fe4f6330
  Current Irp fe43a1c8 RefCount 0 Type 0000000b Flags 00002044
  DevExt fe4f5ea8 DevObjExt fe4f5fd8 
  ExtensionFlags (0000000000) 
  AttachedTo (Lower) fe4f5020 \Driver\i8042prt
  Device queue is busy -- Queue empty.
  看到這個設備對象有名字,叫 KeyboardClass0 ,屬於驅動 Kbdclass
  kd> !strct device_object fe4f5df0
  struct _DEVICE_OBJECT (sizeof=184)
  +00 int16 Type = 0003
  +02 uint16 Size = 01e8
  +04 int32 ReferenceCount = 00000000
  +08 struct _DRIVER_OBJECT *DriverObject = FE4F6330
  // 正是 kbdclass 的 DRIVER_OBJECT 的地址
  +0c struct _DEVICE_OBJECT *NextDevice = 00000000
  +10 struct _DEVICE_OBJECT *AttachedDevice = 00000000
  // 爲空結束,表示上面沒有其它設備對象了
  +14 struct _IRP *CurrentIrp = FE43A1C8
  ...
  +ae uint16 Spare1 = 0000
  +b0 struct _DEVOBJ_EXTENSION *DeviceObjectExtension = FE4F5FD8
  // 它的 DEVOBJ_EXTENSION 在 FE4F5FD8
  +b4 void *Reserved = 00000000
  kd> !strct DEVOBJ_EXTENSION FE4F5FD8
  struct _DEVOBJ_EXTENSION (sizeof=36)
  +00 int16 Type = 000d
  +02 uint16 Size = 0000
  +04 struct _DEVICE_OBJECT *DeviceObject = FE4F5DF0
  +08 uint32 PowerFlags = 00000010
  +0c *Dope = 00000000
  +10 uint32 ExtensionFlags = 00000000
  +14 void *DeviceNode = 00000000
  +18 struct _DEVICE_OBJECT *AttachedTo = FE4F5020
  // 下面一層的設備對象爲 FE4F5020
  +1c struct _LIST_ENTRY FileObjectList
  +1c struct _LIST_ENTRY *Flink = 00000000
  +20 struct _LIST_ENTRY *Blink = 00000000
  中間層的 DEVICE_OBJECT
  kd> !devobj fe4f5020
  Device object (fe4f5020) is for:
  \Driver\i8042prt DriverObject fe4f69f0
  Current Irp 00000000 RefCount 0 Type 00000027 Flags 00002004
  DevExt fe4f50d8 DevObjExt fe4f5358 
  ExtensionFlags (0xc0000000) 
  Unknown flags 0xc0000000
  AttachedDevice (Upper) fe4f5df0 \Driver\Kbdclass
  AttachedTo (Lower) fe4dd730 \Driver\ACPI
  Device queue is not busy.
  看到這個設備對象沒有名字,屬於驅動 i8042prt
  kd> !strct device_object fe4f5020
  struct _DEVICE_OBJECT (sizeof=184)
  +00 int16 Type = 0003
  +02 uint16 Size = 0338
  +04 int32 ReferenceCount = 00000000
  +08 struct _DRIVER_OBJECT *DriverObject = FE4F69F0
  // 正是 i8042prt 的 DRIVER_OBJECT 的地址
  +0c struct _DEVICE_OBJECT *NextDevice = 00000000
  +10 struct _DEVICE_OBJECT *AttachedDevice = FE4F5DF0
  // 上面一層的設備對象
  +14 struct _IRP *CurrentIrp = 00000000
  ...
  +ae uint16 Spare1 = 0001
  +b0 struct _DEVOBJ_EXTENSION *DeviceObjectExtension = FE4F5358
  // 它的 DEVOBJ_EXTENSION 在 FE4F5358
  +b4 void *Reserved = 00000000
  kd> !strct DEVOBJ_EXTENSION FE4F5358
  struct _DEVOBJ_EXTENSION (sizeof=36)
  +00 int16 Type = 000d
  +02 uint16 Size = 0000
  +04 struct _DEVICE_OBJECT *DeviceObject = FE4F5020
  +08 uint32 PowerFlags = 00000000
  +0c *Dope = 00000000
  +10 uint32 ExtensionFlags = c0000000
  +14 void *DeviceNode = 00000000
  +18 struct _DEVICE_OBJECT *AttachedTo = FE4DD730
  // 下面一層的設備對象
  +1c struct _LIST_ENTRY FileObjectList
  +1c struct _LIST_ENTRY *Flink = 00000000
  +20 struct _LIST_ENTRY *Blink = 00000000
  最下面一層的 DEVICE_OBJECT
  kd> !devobj fe4dd730
  Device object (fe4dd730) is for:
  0000000e \Driver\ACPI DriverObject fe4e8ad0
  Current Irp 00000000 RefCount 1 Type 00000032 Flags 00001040
  DevExt fe507468 DevObjExt fe4dd7e8 DevNode fe4fed68 
  ExtensionFlags (0000000000) 
  AttachedDevice (Upper) fe4f5020 \Driver\i8042prt
  Device queue is not busy.
  看到這個設備對象有名字,叫 0000000e ,屬於驅動 acpi
  kd> !strct device_object fe4dd730
  struct _DEVICE_OBJECT (sizeof=184)
  +00 int16 Type = 0003
  +02 uint16 Size = 00b8
  +04 int32 ReferenceCount = 00000001
  +08 struct _DRIVER_OBJECT *DriverObject = FE4E8AD0
  // 正是 acpi 的 DRIVER_OBJECT 的地址
  +0c struct _DEVICE_OBJECT *NextDevice = FE4DD850
  +10 struct _DEVICE_OBJECT *AttachedDevice = FE4F5020
  // 上面一層的設備對象
  +14 struct _IRP *CurrentIrp = 00000000
  ...
  +ae uint16 Spare1 = 0001
  +b0 struct _DEVOBJ_EXTENSION *DeviceObjectExtension = FE4DD7E8
  // 它的 DEVOBJ_EXTENSION 在 FE4DD7E8
  +b4 void *Reserved = 00000000
  kd> !strct DEVOBJ_EXTENSION FE4DD7E8
  struct _DEVOBJ_EXTENSION (sizeof=36)
  +00 int16 Type = 000d
  +02 uint16 Size = 0000
  +04 struct _DEVICE_OBJECT *DeviceObject = FE4DD730
  +08 uint32 PowerFlags = 00000010
  +0c *Dope = 00000000
  +10 uint32 ExtensionFlags = 00000000
  +14 void *DeviceNode = FE4FED68
  +18 struct _DEVICE_OBJECT *AttachedTo = 00000000
  // 爲空結束,表示下面沒有其它設備對象了
  +1c struct _LIST_ENTRY FileObjectList
  +1c struct _LIST_ENTRY *Flink = 00000000
  +20 struct _LIST_ENTRY *Blink = 00000000
  從上自下。\Device\KeyboardClass0(DRIVER_OBJECT 是 kbdclass)可以找到 沒有名字地址爲fe4f5020的DEVICE_OBJECT(DRIVER_OBJECT 是 i8042prt)。沒有名字地址爲fe4f5020的DEVICE_OBJECT(DRIVER_OBJECT 是 i8042prt)可以找到 \Device\0000000e(DRIVER_OBJECT 是 ACPI)。
  從下自上。\Device\0000000e(DRIVER_OBJECT 是 ACPI) 可以找到 沒有名字地址爲fe4f5020的DEVICE_OBJECT(DRIVER_OBJECT 是 i8042prt)。沒有名字地址爲fe4f5020的DEVICE_OBJECT(DRIVER_OBJECT 是 i8042prt)可以找到 \Device\KeyboardClass0(DRIVER_OBJECT 是 ACPI)。
  現在我們對設備棧上的設備對象之間的聯繫,做一個總結,
  設備棧上的設備對象,從上自下,通過 DEVICE_OBJECT 的 DEVOBJ_EXTENSION 的 +18 struct _DEVICE_OBJECT *AttachedTo 聯繫在一起。
  設備棧上的設備對象,從下自上,通過 DEVICE_OBJECT 的 +10 struct _DEVICE_OBJECT *AttachedDevice 聯繫在一起。
  在觀察鍵盤驅動的初始化過程中,我們看到了設備棧是如何建立起來的。
  驅動 i8042prt ,驅動 kbdclass 分別調用 IoAttachDeviceToDeviceStack ,把自己相應的設備對象加入到鍵盤設備棧中。IoAttachDeviceToDeviceStack 會設置 DEVICE_OBJECT 的 DEVOBJ_EXTENSION 的 +18 struct _DEVICE_OBJECT *AttachedTo 和 DEVICE_OBJECT 的 +10 struct _DEVICE_OBJECT *AttachedDevice ,把兩個對象聯繫在一起。並設置新加入的設備對象的 +30 char StackSize。
  暈了吧
  歡迎交流,歡迎交朋友,
  歡迎訪問
  主頁 http://jiurl.yeah.net http://jiurl.nease.net 論壇 http://jiurl.cosoft.org.cn/forum 
  f啊k,不帶你們這樣的啊,有好事不叫我。
發佈了0 篇原創文章 · 獲贊 3 · 訪問量 5萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章