📄 jiurl键盘驱动 4.htm
字号:
ControlSet001 是CurrentControlSet 。<BR><BR>在 i8042prt!DriverEntry
中,<BR>初始化一些全局变量。<BR>从
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\i8042prt\Parameters
下读取一些参数,放在全局变量中。<BR>设置驱动对象的各种例程。<BR><BR>DriverObject->DriverStartIo =
I8xStartIo;<BR>DriverObject->DriverUnload =
I8xUnload;<BR>DriverObject->DriverExtension->AddDevice =
I8xAddDevice;<BR><BR>DriverObject->MajorFunction[IRP_MJ_CREATE] =
I8xCreate;<BR>DriverObject->MajorFunction[IRP_MJ_CLOSE] =
I8xClose;<BR>DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL]
=<BR>I8xInternalDeviceControl; <BR>DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL]
=
I8xDeviceControl; <BR>DriverObject->MajorFunction[IRP_MJ_FLUSH_BUFFERS]
= I8xFlush;<BR><BR>DriverObject->MajorFunction[IRP_MJ_PNP] =
I8xPnP;<BR>DriverObject->MajorFunction[IRP_MJ_POWER] =
I8xPower;<BR><BR>DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] =
I8xSystemControl;<BR><BR><BR>从注册表中读数据的函数 RtlQueryRegistryValues
的用法值得一提<BR><BR>NTSTATUS <BR>RtlQueryRegistryValues(<BR>IN ULONG
RelativeTo,<BR>IN PCWSTR Path,<BR>IN PRTL_QUERY_REGISTRY_TABLE
QueryTable,<BR>IN PVOID Context,<BR>IN PVOID Environment
OPTIONAL<BR>);<BR><BR>可以一次获得一个注册表键(Key)下的多个注册表值(Value)的数据。在从注册表中取得驱动的参数时很方便。<BR><BR>typedef
struct _RTL_QUERY_REGISTRY_TABLE {<BR>PRTL_QUERY_REGISTRY_ROUTINE
QueryRoutine;<BR>ULONG Flags;<BR>PWSTR Name;<BR>PVOID
EntryContext;<BR>ULONG DefaultType;<BR>PVOID DefaultData;<BR>ULONG
DefaultLength;<BR>} RTL_QUERY_REGISTRY_TABLE,
*PRTL_QUERY_REGISTRY_TABLE;<BR><BR>对于 QueryTable 如果 Flags 为
RTL_QUERY_REGISTRY_DIRECT 时<BR><BR>QueryRoutine 被忽略,并且 EntryContext
指向存储结果的地方。<BR>如果访问的键值不存在的话,会使用 DefaultData 做为结果存储到 EntryContext
中。<BR><BR>[kdbclass!DriverEntry]<BR><BR>此时的 Call Stack<BR><BR># ChildEBP
RetAddr Args to Child <BR>00 f901f510 804a4431 fe4f6310 fe4f5000
00000000 kbdclass!DriverEntry(struct _DRIVER_OBJECT * DriverObject =
0xfe4f6310, struct _UNICODE_STRING * RegistryPath = 0xfe4f5000) (CONV:
stdcall)<BR>01 f901f5d8 80426f6d 80000044 fe4f5000 f901f6e0
nt!IopLoadDriver+0x672 (FPO: [Non-Fpo])<BR>02 f901f608 80506535 fe4f72c8
80000044 00000001 nt!IopCallDriverAddDeviceQueryRoutine+0x356 (FPO:
[Non-Fpo])<BR>03 f901f654 80497df1 e129eec6 00000007 f901f6b0
nt!RtlpCallQueryRegistryRoutine+0x1a2 (FPO: [Non-Fpo])<BR>04 f901f6b8
804a4b67 00000000 00000082 00000001 nt!RtlQueryRegistryValues+0x1ed (FPO:
[Non-Fpo])<BR>05 f901f77c 8054f1bb 80000048 00000001 f901f800
nt!IopCallDriverAddDevice+0x499 (FPO: [Non-Fpo])<BR>06 f901f798 804e504e
fe4fed68 f901f864 fe4d6368 nt!IopProcessAddDevicesWorker+0x6c (FPO:
[2,0,3])<BR>07 f901f7a8 8054f184 fe4d6368 8054f147 f901f864
nt!IopForAllChildDeviceNodes+0x1f (FPO: [3,0,1])<BR>08 f901f7c4 804e504e
fe4d6368 f901f864 fe4e7c28 nt!IopProcessAddDevicesWorker+0x3d (FPO:
[2,0,3])<BR>09 f901f7d4 8054f184 fe4e7c28 8054f147 f901f864
nt!IopForAllChildDeviceNodes+0x1f (FPO: [3,0,1])<BR>0a f901f7f0 804e504e
fe4e7c28 f901f864 fe5181a8 nt!IopProcessAddDevicesWorker+0x3d (FPO:
[2,0,3])<BR>0b f901f800 8054f184 fe5181a8 8054f147 f901f864
nt!IopForAllChildDeviceNodes+0x1f (FPO: [3,0,1])<BR>0c f901f81c 804e504e
fe5181a8 f901f864 fe51b5e8 nt!IopProcessAddDevicesWorker+0x3d (FPO:
[2,0,3])<BR>0d f901f82c 8054f184 fe51b5e8 8054f147 f901f864
nt!IopForAllChildDeviceNodes+0x1f (FPO: [3,0,1])<BR>0e f901f848 8054f114
fe51b5e8 f901f864 00000003 nt!IopProcessAddDevicesWorker+0x3d (FPO:
[2,0,3])<BR>0f f901f86c 8054dfdf fe51baa8 0000ffff 00000003
nt!IopProcessAddDevices+0x59 (FPO: [Non-Fpo])<BR>10 f901f8c0 8054c5c9
00000000 00000032 00000000 nt!IopInitializeSystemDrivers+0x25 (FPO:
[Non-Fpo])<BR>11 f901fa58 8054b35a 80087000 00000000 00000000
nt!IoInitSystem+0x644 (FPO: [Non-Fpo])<BR>12 f901fda8 804524f6 80087000
00000000 00000000 nt!Phase1Initialization+0x71b (FPO: [Non-Fpo])<BR>13
f901fddc 80465b62 8054aca6 80087000 00000000
nt!PspSystemThreadStartup+0x69 (FPO: [Non-Fpo])<BR><BR>DriverEntry(<BR>IN
PDRIVER_OBJECT DriverObject,<BR>IN PUNICODE_STRING
RegistryPath<BR>)<BR><BR>RegistryPath 指向的 unicode 字符串为
"\REGISTRY\MACHINE\SYSTEM\ControlSet001\Services\kbdclass"<BR><BR>在
kbdclass!DriverEntry 中,<BR>初始化一些全局变量。<BR>从
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\kbdclass\Parameters
下读取一些参数,放入全局变量中。<BR>设置驱动对象的各种例程。<BR><BR>DriverObject->DriverStartIo =
KeyboardClassStartIo;<BR>DriverObject->MajorFunction[IRP_MJ_CREATE] =
KeyboardClassCreate;<BR>DriverObject->MajorFunction[IRP_MJ_CLOSE] =
KeyboardClassClose;<BR>DriverObject->MajorFunction[IRP_MJ_READ] =
KeyboardClassRead;<BR>DriverObject->MajorFunction[IRP_MJ_FLUSH_BUFFERS]
=
KeyboardClassFlush;<BR>DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL]
=
KeyboardClassDeviceControl;<BR>DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL]
=<BR>KeyboardClassPassThrough;<BR>DriverObject->MajorFunction[IRP_MJ_CLEANUP]
= KeyboardClassCleanup;<BR>DriverObject->MajorFunction[IRP_MJ_PNP] =
KeyboardPnP;<BR>DriverObject->MajorFunction[IRP_MJ_POWER] =
KeyboardClassPower;<BR>DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL]
=
KeyboardClassSystemControl;<BR>DriverObject->DriverExtension->AddDevice
= KeyboardAddDevice;<BR><BR>[i8042prt!I8xAddDevice]<BR><BR>此时的 Call
Stack<BR><BR># ChildEBP RetAddr Args to Child <BR>00 f901f6c4
8048e8f2 fe4f69f0 fe4dd730 00000000 i8042prt!I8xAddDevice(struct
_DRIVER_OBJECT * Driver = 0xfe4f69f0, struct _DEVICE_OBJECT * PDO =
0xfe4dd730) (CONV: stdcall)<BR>01 f901f77c 8054f1bb 80000048 00000002
f901f800 nt!IopCallDriverAddDevice+0x52d (FPO: [Non-Fpo])<BR>02 f901f798
804e504e fe4fed68 f901f864 fe4d6368 nt!IopProcessAddDevicesWorker+0x6c
(FPO: [2,0,3])<BR>03 f901f7a8 8054f184 fe4d6368 8054f147 f901f864
nt!IopForAllChildDeviceNodes+0x1f (FPO: [3,0,1])<BR>04 f901f7c4 804e504e
fe4d6368 f901f864 fe4e7c28 nt!IopProcessAddDevicesWorker+0x3d (FPO:
[2,0,3])<BR>05 f901f7d4 8054f184 fe4e7c28 8054f147 f901f864
nt!IopForAllChildDeviceNodes+0x1f (FPO: [3,0,1])<BR>06 f901f7f0 804e504e
fe4e7c28 f901f864 fe5181a8 nt!IopProcessAddDevicesWorker+0x3d (FPO:
[2,0,3])<BR>07 f901f800 8054f184 fe5181a8 8054f147 f901f864
nt!IopForAllChildDeviceNodes+0x1f (FPO: [3,0,1])<BR>08 f901f81c 804e504e
fe5181a8 f901f864 fe51b5e8 nt!IopProcessAddDevicesWorker+0x3d (FPO:
[2,0,3])<BR>09 f901f82c 8054f184 fe51b5e8 8054f147 f901f864
nt!IopForAllChildDeviceNodes+0x1f (FPO: [3,0,1])<BR>0a f901f848 8054f114
fe51b5e8 f901f864 00000003 nt!IopProcessAddDevicesWorker+0x3d (FPO:
[2,0,3])<BR>0b f901f86c 8054dfdf fe51baa8 0000ffff 00000003
nt!IopProcessAddDevices+0x59 (FPO: [Non-Fpo])<BR>0c f901f8c0 8054c5c9
00000000 00000032 00000000 nt!IopInitializeSystemDrivers+0x25 (FPO:
[Non-Fpo])<BR>0d f901fa58 8054b35a 80087000 00000000 00000000
nt!IoInitSystem+0x644 (FPO: [Non-Fpo])<BR>0e f901fda8 804524f6 80087000
00000000 00000000 nt!Phase1Initialization+0x71b (FPO: [Non-Fpo])<BR>0f
f901fddc 80465b62 8054aca6 80087000 00000000
nt!PspSystemThreadStartup+0x69 (FPO: [Non-Fpo])<BR>10 00000000 00000000
00000000 00000000 00000000 nt!KiThreadStartup+0x16<BR><BR>IO 管理器调用了
i8042prt!I8xAddDevice。<BR><BR>i8042prt!I8xAddDevice 中,<BR>调用
IoCreateDevice 创建设备对象。<BR>调用 IoAttachDeviceToDeviceStack 将产生的 i8042prt
的设备对象放入键盘设备栈。<BR>初始化自定义的设备扩展中的一些域。<BR><BR>IoCreateDevice 的参数 DeviceName
,调用时为空,说明这个设备对象没有名字。<BR><BR>IoAttachDeviceToDeviceStack 中的参数,TargetDevice
决定了产生的 i8042prt 的设备对象将被放入哪个设备栈。而调用时参数 TargetDevice ,为
i8042prt!I8xAddDevice 传入参数 PDO。系统如何知道给 i8042prt!I8xAddDevice 传入哪个 PDO
呢?答案是,键盘设备栈的 PDO 通过注册表中保存的键盘设备栈的信息,找到了 i8042prt,才调用了 i8042prt 的
DriverObject->DriverExtension->AddDevice,所以当然知道 PDO
。<BR><BR>设备栈上的设备对象,从上自下,通过 DEVICE_OBJECT 的 DEVOBJ_EXTENSION 的 +18 struct
_DEVICE_OBJECT *AttachedTo 联系在一起。设备栈上的设备对象,从下自上,通过 DEVICE_OBJECT 的 +10
struct _DEVICE_OBJECT *AttachedDevice
联系在一起。<BR>IoAttachDeviceToDeviceStack 会把一个设备对象,放入设备栈的栈顶,也就是把这个设备对象的
DEVICE_OBJECT 的 DEVOBJ_EXTENSION 的 +18 struct _DEVICE_OBJECT *AttachedTo 和
DEVICE_OBJECT 的 +10 struct _DEVICE_OBJECT *AttachedDevice
这两个域和原来设备栈的栈顶的设备对象的这两个域发生联系。还会相应的设置这个新放入设备栈的设备对象的 +30 char
StackSize。<BR><BR>[kbdclass!KeyboardAddDevice]<BR><BR>此时的 Call
Stack<BR><BR># ChildEBP RetAddr Args to Child <BR>00 f901f6c4
8048e8f2 fe4f6310 fe4dd730 00000000 kbdclass!KeyboardAddDevice(struct
_DRIVER_OBJECT * DriverObject = 0xfe4f6310, struct _DEVICE_OBJECT *
PhysicalDeviceObject = 0xfe4dd730) (CONV: stdcall)<BR>01 f901f77c 8054f1bb
80000048 00000004 f901f800 nt!IopCallDriverAddDevice+0x52d (FPO:
[Non-Fpo])<BR>02 f901f798 804e504e fe4fed68 f901f864 fe4d6368
nt!IopProcessAddDevicesWorker+0x6c (FPO: [2,0,3])<BR>03 f901f7a8 8054f184
fe4d6368 8054f147 f901f864 nt!IopForAllChildDeviceNodes+0x1f (FPO:
[3,0,1])<BR>04 f901f7c4 804e504e fe4d6368 f901f864 fe4e7c28
nt!IopProcessAddDevicesWorker+0x3d (FPO: [2,0,3])<BR>05 f901f7d4 8054f184
fe4e7c28 8054f147 f901f864 nt!IopForAllChildDeviceNodes+0x1f (FPO:
[3,0,1])<BR>06 f901f7f0 804e504e fe4e7c28 f901f864 fe5181a8
nt!IopProcessAddDevicesWorker+0x3d (FPO: [2,0,3])<BR>07 f901f800 8054f184
fe5181a8 8054f147 f901f864 nt!IopForAllChildDeviceNodes+0x1f (FPO:
[3,0,1])<BR>08 f901f81c 804e504e fe5181a8 f901f864 fe51b5e8
nt!IopProcessAddDevicesWorker+0x3d (FPO: [2,0,3])<BR>09 f901f82c 8054f184
fe51b5e8 8054f147 f901f864 nt!IopForAllChildDeviceNodes+0x1f (FPO:
[3,0,1])<BR>0a f901f848 8054f114 fe51b5e8 f901f864 00000003
nt!IopProcessAddDevicesWorker+0x3d (FPO: [2,0,3])<BR>0b f901f86c 8054dfdf
fe51baa8 0000ffff 00000003 nt!IopProcessAddDevices+0x59 (FPO:
[Non-Fpo])<BR>0c f901f8c0 8054c5c9 00000000 00000032 00000000
nt!IopInitializeSystemDrivers+0x25 (FPO: [Non-Fpo])<BR>0d f901fa58
8054b35a 80087000 00000000 00000000 nt!IoInitSystem+0x644 (FPO:
[Non-Fpo])<BR>0e f901fda8 804524f6 80087000 00000000 00000000
nt!Phase1Initialization+0x71b (FPO: [Non-Fpo])<BR>0f f901fddc 80465b62
8054aca6 80087000 00000000 nt!PspSystemThreadStartup+0x69 (FPO:
[Non-Fpo])<BR>10 00000000 00000000 00000000 00000000 00000000
nt!KiThreadStartup+0x16<BR><BR>kbdclass!KeyboardAddDevice 中,<BR>调用
IoCreateDevice 创建设备对象。<BR>初始化自定义的设备扩展中的一些域。<BR>从 NonPagedPool 为 kbdclass
的输入数据队列,分配内存。<BR>初始化设备扩展中的使用输入数据队列的相关域。<BR>调用 IoAttachDeviceToDeviceStack
将产生的 kbdclass 的设备对象放入键盘设备栈。<BR>调用 IoRegisterDeviceInterface
,暴露驱动的接口给应用层。<BR>调用函数 kbdclass!KbdSendConnectRequest
,把自己(kbdclass)的处理输入数据的回调函数告诉下一层(i8042prt)。<BR><BR>IoCreateDevice 的参数
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -