📄 jiurl键盘驱动 4.htm
字号:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<!-- saved from url=(0058)http://jiurl.nease.net/cn/document/KbdDriver/JiurlKbd4.htm -->
<HTML><HEAD><TITLE>JIURL键盘驱动 4</TITLE>
<META http-equiv=Content-Type content="text/html; charset=gb2312">
<STYLE type=text/css>.title {
FONT-WEIGHT: bold; FONT-SIZE: 21px; LINE-HEIGHT: 48px; FONT-FAMILY: "黑体", Arial, sans-serif; TEXT-DECORATION: none
}
.author {
FONT-SIZE: 12px; LINE-HEIGHT: 16px; FONT-FAMILY: "宋体"
}
.content {
FONT-SIZE: 14px; LINE-HEIGHT: 20px
}
</STYLE>
<META content="MSHTML 6.00.2900.2668" name=GENERATOR></HEAD>
<BODY bgColor=#f7f7f7 topMargin=5>
<DIV align=center>
<CENTER>
<TABLE height=29 cellSpacing=0 cellPadding=0 width="96%" border=0>
<TBODY>
<TR>
<TD class=title width="100%" height=41>
<P align=center><FONT face=宋体>JIURL键盘驱动 </FONT><FONT
face=宋体>4</FONT></P></TD></TR></CENTER>
<TR>
<TD class=author width="100%" height=9>
<P align=center><FONT face=宋体>作者: <A
href="mailto:jiurl@mail.china.com">JIURL</A> </FONT></P></TD></TR>
<TR>
<TD class=author width="100%" height=6>
<P align=center><FONT
face=宋体>
主页: <A href="http://jiurl.yeah.net/">http://jiurl.yeah.net/</A>
</FONT></P></TD></TR>
<TR>
<TD class=author width="100%" height=2>
<P align=center><FONT face=宋体> 日期: 2003-12-13</FONT>
</P></TD></TR></TBODY></TABLE></DIV>
<DIV align=center>
<CENTER>
<TABLE height=1 cellSpacing=0 cellPadding=0 width="96%" border=0>
<TBODY>
<TR>
<TD width="100%" height=1>
<HR color=#396da5 SIZE=3>
</TD></TR></TBODY></TABLE></CENTER></DIV>
<DIV align=center>
<TABLE class=content height=200 cellSpacing=0 cellPadding=0 width="96%"
border=0>
<TBODY>
<TR>
<TD vAlign=top width="131%" height=200>
<P>6.2 初始化与注册表<BR><BR>在驱动的初始化中,注册表起着非常重要的作用。<BR><BR>6.2.1
重要认识<BR><BR>
每台计算机的硬件配置可能是不同的,系统是如何知道需要为哪些硬件载入驱动?系统是如何知道要载入的驱动文件是哪个文件?答案是通过注册表,注册表中保存着这些信息。那么注册表中的这些信息是哪里来的?答案是在安装驱动的时候,安装程序放到注册表中的。<BR><BR>6.2.2
确定驱动载入顺序的基本知识<BR><BR>
在系统初始化的时候,决定驱动程序在什么时候被载入的信息保存在注册表中。最早的一批驱动是由ntldr载入内存的(仅仅是载入),第二批是由IO管理器载入内存的,第三批是由
SCM(Service Control Manager) 载入的。一个驱动在第几批中被载入是由
HKLM\SYSTEM\CurrentControlSet\Services\驱动名\Start
的值来决定。该值为0,第一批被载入。该值为1,第二批被载入。该值为2,第三批被载入。对于同一批驱动中的驱动,按驱动所在组的先后载入。组的先后顺序由
HKLM\SYSTEM\CurrentControlSet\Control\ServiceGroupOrder\List 决定。每个驱动的
HKLM\SYSTEM\CurrentControlSet\Services\驱动名\Group 决定了驱动所属的组,如果没有这个
Services\驱动名\Group ,那么就在所有组之后。对于同一个组中的驱动,按驱动的Tag的先后载入。Tag的先后顺序由
HKLM\SYSTEM\CurrentControlSet\Control\GroupOrderList\组名 决定。每个驱动的
HKLM\SYSTEM\CurrentControlSet\Services\驱动名\Tag
决定了驱动在组中的Tag。<BR><BR>
关于系统初始化过程和如何确定驱动载入的顺序的更详细内容,可以参考下面两个资料:<BR>Inside the Boot Process Part 1
,Inside the Boot Process Part 2
。<BR>http://osg.informatik.tu-chemnitz.de/lehre/seminar/lwb/Doku/SystemInitiation.pdf
。<BR>"6.2.2 确定驱动载入顺序的基本知识"的内容就是从这两个资料中翻译的。<BR><BR>6.2.3
注册表与设备栈<BR><BR>
设备栈的建立,是靠注册表中的信息。这些信息放在以下两个键下。<BR>HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\<BR>HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Class\ <BR>具体请看,稍后对注册表中决定键盘设备栈的信息的讨论。<BR><BR>参考
...\NTDDK\src\general\toaster\toaster.htm<BR><BR>6.2.4
驱动文件的路径<BR><BR>HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\驱动名\ImagePath<BR><BR>6.2.5
键盘驱动与注册表<BR><BR>6.2.5.1 键盘驱动载入顺序<BR><BR>查看注册表中决定键盘驱动 i8042prt, kbdclass
载入顺序的内容。<BR><BR>[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\i8042prt]<BR>"Type"=dword:00000001<BR>"Start"=dword:00000001<BR>"Group"="Keyboard
Port"<BR>"ErrorControl"=dword:00000001<BR>"DisplayName"="i8042 Keyboard
and PS/2 Mouse Port
Driver"<BR>"ImagePath"="System32\DRIVERS\i8042prt.sys"<BR>"Tag"=dword:00000004<BR><BR>[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Kbdclass]<BR>"ErrorControl"=dword:00000001<BR>"Group"="Keyboard
Class"<BR>"Start"=dword:00000001<BR>"Tag"=dword:00000001<BR>"Type"=dword:00000001<BR>"DisplayName"="Keyboard
Class Driver"<BR>"ImagePath"="System32\DRIVERS\kbdclass.sys"<BR><BR>两个的
Start 类型都是 1,即 SERVICE_SYSTEM_START ,所以他们都将由 IO 管理器载入。还可以看到 i8042prt 属于组
"Keyboard Port" ,kbdclass 属于组 "Keyboard Class"
。<BR><BR>查看这两个组的先后顺序。组的先后顺序保存在
HKEY_LOCAL_MACHINE\CurrentControlSet\Control\ServiceGroupOrder\List 中,由于使用
regedit.exe 来看这个值不是很方便,我们使用系统中另一个注册表编辑器regedt32.exe 。
可以看到下面的内容。<BR><BR>System Reserved<BR>...<BR>Keyboard Port<BR>Pointer
Class<BR>Keyboard Class<BR>...<BR>MS Transactions<BR><BR>组 "Keyboard Port"
在 组 "Keyboard Class" 之前,所以 i8042prt 在 kbdclass
之前被载入。<BR><BR>确定了顺序之后,HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\驱动名\ImagePath
是驱动程序文件的路径,通过这个值,就可以在硬盘上找到驱动程序文件,也就可以把它读入内存。<BR><BR>6.2.5.2
键盘设备栈与注册表<BR><BR>[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\ACPI\PNP0303\4&5289e18&0]<BR>"Capabilities"=dword:00000020<BR>"HardwareID"=hex(7):41,00,43,00,50,00,49,00,5c,00,50,00,4e,00,50,00,30,00,33,\<BR>00,30,00,33,00,00,00,2a,00,50,00,4e,00,50,00,30,00,33,00,30,00,33,00,00,00,\<BR>00,00<BR>"Service"="i8042prt"<BR>"ClassGUID"="{4D36E96B-E325-11CE-BFC1-08002BE10318}"<BR>"ConfigFlags"=dword:00000000<BR>"Driver"="{4D36E96B-E325-11CE-BFC1-08002BE10318}\\0000"<BR>"Mfg"="(标准键盘)"<BR>"DeviceDesc"="Standard
101/102-Key or Microsoft Natural PS/2
Keyboard"<BR><BR>[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Class\{4D36E96B-E325-11CE-BFC1-08002BE10318}]<BR>"Class"="Keyboard"<BR>"Icon"="-3"<BR>"Installer32"="SysSetup.Dll,KeyboardClassInstaller"<BR>"UpperFilters"="kbdclass"<BR>@="键盘"<BR>"NoInstallClass"="1"<BR>"TroubleShooter-0"="tshoot.chm,hdw_keyboard.htm"<BR><BR>HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\ACPI\PNP0303\4&5289e18&0\Service<BR>通过这里找到键盘设备栈中的
i8042prt<BR><BR>HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\ACPI\PNP0303\4&5289e18&0\ClassGUID<BR>通过这里找到类的GUID,用这个GUID就可以在
HKLM\SYSTEM\CurrentControlSet\Control\Class\
下找到键盘驱动类,进而找到键盘类的过滤程序<BR><BR>HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Class\{4D36E96B-E325-11CE-BFC1-08002BE10318}\UpperFilters<BR>通过这里找到键盘设备栈中的
kbdclass<BR><BR><BR>6.3 键盘驱动初始化分析<BR><BR>6.3.1
键盘驱动本身的初始化部分<BR><BR>系统初始化进行到下图所示阶段
<P align=center><IMG src="JIURL键盘驱动 4.files/init1.gif" border=0>
<P>[i8042prt!DriverEntry]<BR><BR>此时的 Call Stack<BR><BR># ChildEBP RetAddr
Args to Child <BR>00 f901f510 804a4431 fe4f69f0 fe4f5000 00000000
i8042prt!DriverEntry(struct _DRIVER_OBJECT * DriverObject = 0xfe4f69f0,
struct _UNICODE_STRING * RegistryPath = 0xfe4f5000) (CONV: stdcall)<BR>01
f901f5d8 80426f6d 80000044 fe4f5000 f901f6e0 nt!IopLoadDriver+0x672 (FPO:
[Non-Fpo])<BR>02 f901f608 8049ccaa fe4f7348 80000044 00000001
nt!IopCallDriverAddDeviceQueryRoutine+0x356 (FPO: [Non-Fpo])<BR>03
f901f654 80497df1 00000012 00000001 f901f6b0
nt!RtlpCallQueryRegistryRoutine+0x349 (FPO: [Non-Fpo])<BR>04 f901f6b8
804a4ac0 00000000 00000082 00000001 nt!RtlQueryRegistryValues+0x1ed (FPO:
[Non-Fpo])<BR>05 f901f77c 8054f1bb 80000048 00000001 f901f864
nt!IopCallDriverAddDevice+0x38f (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>可以看到是 IO 管理器调用
nt!IopLoadDriver 载入了驱动文件 i8042prt.sys,并调用
i8042prt!DriverEntry。<BR><BR>介绍一下 nt!IopLoadDriver
的执行过程<BR><BR>nt!IopLoadDriver 会遍历 PsLoadedModuleList ,查看是否已经有叫
i8042prt.SYS 的模组。也就是查看是否 i8042prt.SYS 已经被载入。发现没有载入,就读取 "ImagePath"
下的数据,获得了路径 "System32\DRIVERS\i8042prt.sys"。使用获得的路径做参数,调用
nt!MmLoadSystemImage,载入驱动。使用 nt!ObCreateObject
创建一个驱动对象。按下面的叙述顺序初始化这个驱动对象。给 DRIVER_OBJECT 的 +18 struct _DRIVER_EXTENSION
*DriverExtension 赋值,驱动对象的首地址加上0xa8,即紧跟在 DRIVER_OBJECT 之后的地址。将
DRIVER_EXTENSION 的 +00 struct _DRIVER_OBJECT *DriverObject 赋值为驱动对象的首地址。用
nt!IopInvalidDeviceRequest 初始化驱动对象的整个 MajorFunction[28] 。初始化驱动对象的
Type,Size,Flags。用 i8042prt!DriverEntry 初始化驱动对象的 +2c function *DriverInit
。初始化 +14 void *DriverSection 。用 i8042prt 在内存中的首地址初始化 +0c void *DriverStart
。用 i8042prt 的大小初始化 +10 uint32 DriverSize 。用 nt!ObInsertObject 将
DRIVER_OBJECT 插入命名对象空间,即在插入前 \driver\ 下是没有 i8042prt 的,插入后就有了。初始化 +24
struct _UNICODE_STRING *HardwareDatabase 。从 PagedPool 分配内存,用刚分配的内存初始化 +1c
struct _UNICODE_STRING DriverName,放入 "\Driver\i8042prt"。从 NonPagedPool
分配内存,初始化 DRIVER_EXTENSION 的 ServiceKeyName,放入 "i8042prt"。将 PUNICODE_STRING
RegistryPath ,PDRIVER_OBJECT DriverObject 压入堆栈,然后调用 DriverObject+0x2c 即
DriverInit 即 DriverEntry。从 DriverEntry 中返回之后,nt!IopLoadDriver 继续执行,会释放为
RegistryPath 所申请的空间。<BR><BR>DriverEntry(<BR>IN PDRIVER_OBJECT
DriverObject,<BR>IN PUNICODE_STRING RegistryPath<BR>)<BR><BR>RegistryPath
指向的 unicode 字符串为
"\REGISTRY\MACHINE\SYSTEM\ControlSet001\Services\i8042prt"<BR>此时我的
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -