?? jiurl鍵盤驅(qū)動(dòng) 2.htm
字號(hào):
創(chuàng)建文件對(duì)象。初始化這個(gè)文件對(duì)象,+04 struct _DEVICE_OBJECT *DeviceObject 賦值為鍵盤設(shè)備棧的 PDO。調(diào)用
nt!IopfCallDriver,將 IRP 發(fā)往驅(qū)動(dòng),讓驅(qū)動(dòng)進(jìn)行相應(yīng)的處理。之后一系列返回,回到 nt!ObOpenObjectByName。在
nt!ObOpenObjectByName 中繼續(xù)執(zhí)行,調(diào)用 nt!ObpCreateHandle
在進(jìn)程(csrss.exe)的句柄表中創(chuàng)建一個(gè)新的句柄,這個(gè)句柄對(duì)應(yīng)的對(duì)象是剛才創(chuàng)建初始化的那個(gè)文件對(duì)象,文件對(duì)象中的 DeviceObject
指向鍵盤設(shè)備棧的 PDO。在 nt!ObpCreateHandle 前后,我們使用命令 !handle 0 3 a0 (a0 為此時(shí)
csrss.exe進(jìn)程的進(jìn)程id),觀察 csrss.exe進(jìn)程 句柄表的前后變化,看到了多出來的那一個(gè)文件對(duì)象。<BR><BR>3.3
win32k!RawInputThread 如何從鍵盤驅(qū)動(dòng)得到按鍵的數(shù)據(jù)<BR><BR>
win32k!RawInputThread 在獲得了句柄之后,會(huì)以這個(gè)句柄為參數(shù),調(diào)用
nt!ZwReadFile,向鍵盤驅(qū)動(dòng)要求讀入數(shù)據(jù)。nt!ZwReadFile 中會(huì)創(chuàng)建一個(gè) IRP_MJ_READ 的 IRP
發(fā)給鍵盤驅(qū)動(dòng),告訴鍵盤驅(qū)動(dòng)要求讀入數(shù)據(jù)。鍵盤驅(qū)動(dòng)通常會(huì)使這個(gè) IRP Pending
(通常情況下是這樣,詳細(xì)的情況我們在鍵盤驅(qū)動(dòng)部分討論)。也就是說這個(gè) IRP_MJ_READ
不會(huì)被滿足,它會(huì)一直被放在那里,等待著來自鍵盤的數(shù)據(jù)。而發(fā)出這個(gè)讀請(qǐng)求的線程 win32k!RawInputThread
也會(huì)等待,等待著這個(gè)讀操作的完成。<BR><BR> 命中注定,這個(gè) IRP
匆匆的出現(xiàn),然后用它一生中絕大部分時(shí)間,開始一個(gè)靜靜的等待,而當(dāng)它等到的時(shí)候,它就會(huì)匆匆的消失。它的一生或許很短,或許很長,取決于它所等待著的出現(xiàn)。它在平靜的等待著什么呢?<BR><BR>
它在等待著你,按下鍵盤上的鍵。我們來說明一下鍵盤數(shù)據(jù)的源頭,鍵盤數(shù)據(jù)的源頭就是鍵盤,當(dāng)鍵盤上有鍵被按下時(shí),就產(chǎn)生了那個(gè) IRP_MJ_READ
IRP 等待著的對(duì)象。<BR><BR>
當(dāng)鍵盤上有鍵被按下時(shí),將觸發(fā)鍵盤的那個(gè)中斷,引起中斷服務(wù)例程的執(zhí)行,鍵盤中斷的中斷服務(wù)例程由鍵盤驅(qū)動(dòng)提供。鍵盤驅(qū)動(dòng)從端口讀取掃描碼,經(jīng)過一些列的處理之后,最后把從鍵盤得到的數(shù)據(jù)交給
IRP,然后結(jié)束這個(gè) IRP。<BR><BR> 這個(gè) IRP 的結(jié)束,將導(dǎo)致
win32k!RawInputThread 線程對(duì)這個(gè)讀操作的等待結(jié)束。win32k!RawInputThread
線程將會(huì)對(duì)得到的數(shù)據(jù)作出處理,分發(fā)給合適的進(jìn)程。一旦把輸入數(shù)據(jù)處理完之后,win32k!RawInputThread 線程會(huì)立刻再調(diào)用一個(gè)
簡單的說,win32k!RawInputThread 線程總是 nt!ZwReadFile
要求讀入數(shù)據(jù)。然后等待鍵盤上的鍵被按下。當(dāng)鍵盤上的鍵被按下,win32k!RawInputThread 處理 nt!ZwReadFile
得到的數(shù)據(jù),然后再 nt!ZwReadFile 要求讀入數(shù)據(jù),再等待鍵盤上的鍵被按下。<BR><BR>
上面所介紹的內(nèi)容,是當(dāng)我在看到鍵盤驅(qū)動(dòng)對(duì)于 IRP_MJ_READ 的處理,在 kbdclass!KeyboardClassRead 中,IRP
并沒有獲得數(shù)據(jù),而是被 IoMarkIrpPending 時(shí),想了想,了解到的。<BR><BR>
我簡單的跟了一下 win32k!RawInputThread
從鍵盤驅(qū)動(dòng)獲得按鍵數(shù)據(jù)的過程,下面我對(duì)這個(gè)過程做一個(gè)簡單的介紹。<BR><BR> 首先我們看看斷在
kbdclass!KeyboardClassRead 時(shí)的 call stack ,看看引起 kbdclass!KeyboardClassRead
的整個(gè)調(diào)用過程。<BR><BR># ChildEBP RetAddr Args to Child <BR>00 f90ef8dc
8041f54b fe4f5df0 fe43e9a8 fe43e9a8 kbdclass!KeyboardClassRead(struct
_DEVICE_OBJECT * Device = 0xfe4f5df0, struct _IRP * Irp = 0xfe43e9a8)
(CONV: stdcall)<BR>01 f90ef8f0 804ba5e8 fe43eacc fe43e9a8 00000000
nt!IopfCallDriver+0x35 (FPO: [0,0,2])<BR>02 f90ef904 804a2d4c fe4f5df0
fe43e9a8 fe42d668 nt!IopSynchronousServiceTail+0x60 (FPO: [Non-Fpo])<BR>03
f90ef9d8 80461691 000000d4 00000000 a005c962 nt!NtReadFile+0x5f4 (FPO:
[Non-Fpo])<BR>04 f90ef9d8 804011d5 000000d4 00000000 a005c962
nt!KiSystemService+0xc4 (FPO: [0,0] TrapFrame @ f90efa04)<BR>05 f90efa74
a005c91d 000000d4 00000000 a005c962 nt!ZwReadFile+0xb (FPO: [9,0,0])<BR>06
f90efaa8 a005c991 e1971008 fe43e9e8 80430982 win32k!StartDeviceRead+0x8c
(FPO: [1,0,3])<BR>07 f90efab4 80430982 e1971008 e1971028 00000000
win32k!InputApc+0x41 (FPO: [3,0,1])<BR>08 f90efae8 80403a44 00000000
00000000 00000000 nt!KiDeliverApc+0xdb (FPO: [Non-Fpo])<BR>09 f90efb08
8042d33d 80400b46 00000001 00000000 nt!KiSwapThread+0xfc (FPO: [EBP
0xf90efb3c] [0,0,4])<BR>0a f90efb3c a000eaf5 00000004 fe42e5a8 00000001
nt!KeWaitForMultipleObjects+0x266 (FPO: [Non-Fpo])<BR>0b f90efda8 804524f6
00000002 00000000 00000000 win32k!RawInputThread+0x3c2 (FPO:
[Non-Fpo])<BR>0c f9dc 80465b62 a000e7cd f8d5f7d0 00000000
nt!PspSystemThreadStartup+0x69 (FPO: [Non-Fpo])<BR>0d 00000000 f000ff53
f000e2c3 f000ff53 f000ff53 nt!KiThreadStartup+0x16<BR>WARNING: Frame IP
not in any known module. Following frames may be wrong.<BR>0e f000ff53
00000000 00000000 00000000 00000000 0xf000ff53<BR><BR>
線程 win32k!RawInputThread 調(diào)用 nt!ZwReadFile
要求讀入數(shù)據(jù)。<BR><BR>NTSTATUS <BR>ZwReadFile(<BR>IN HANDLE
FileHandle,<BR>IN HANDLE Event OPTIONAL,<BR>IN PIO_APC_ROUTINE ApcRoutine
OPTIONAL,<BR>IN PVOID ApcContext OPTIONAL,<BR>OUT PIO_STATUS_BLOCK
IoStatusBlock,<BR>OUT PVOID Buffer,<BR>IN ULONG Length,<BR>IN
PLARGE_INTEGER ByteOffset OPTIONAL,<BR>IN PULONG Key
OPTIONAL<BR>);<BR><BR>我們看到調(diào)用時(shí),參數(shù) FileHandle 正是前面 win32k!RawInputThread 用
ZwCreateFile 得到的句柄。而參數(shù) ApcRoutine 為 win32k!InputApc 的入口地址。也就是說當(dāng) ReadFile 的
IRP 結(jié)束時(shí),win32k!InputApc 將被調(diào)用。ZwReadFile 通過系統(tǒng)服務(wù),最終調(diào)用
nt!NtReadFile。<BR><BR>nt!NtReadFile
中。作為參數(shù)傳入的那個(gè)句柄,對(duì)應(yīng)著一個(gè)文件對(duì)象,這個(gè)文件對(duì)象中保存著鍵盤設(shè)備棧中的 PDO 的設(shè)備對(duì)象的指針。以這個(gè)句柄為參數(shù)調(diào)用
ObReferenceObjectByHandle,獲得句柄對(duì)應(yīng)的文件對(duì)象。之后用得到的文件對(duì)象做參數(shù)調(diào)用
IoGetRelatedDeviceObject ,這將獲得鍵盤設(shè)備棧中最頂端的設(shè)備對(duì)象的指針。用得到的鍵盤設(shè)備棧中最頂端的設(shè)備對(duì)象的 +30
char StackSize 作參數(shù),調(diào)用 nt!IoAllocateIrp,構(gòu)造 IRP ,然后初始化這個(gè) IRP,用傳入的參數(shù)設(shè)置這個(gè)
IRP。然后調(diào)用 IoCallDriver ,將這個(gè) IRP 發(fā)給鍵盤驅(qū)動(dòng)。<BR><BR>鍵盤驅(qū)動(dòng)通常會(huì)調(diào)用 IoMarkIrpPending
使這個(gè) IRP Pending。通常情況下是這樣,詳細(xì)的情況我們在鍵盤驅(qū)動(dòng)部分討論。于是這個(gè) IRP 就在那里等待。關(guān)于這個(gè)等待的 IRP
,我們可以使用 WinDbg 的 !irpfind 命令找到它。反過來這也解釋了,我們使用 !irpfind 為什么總能看到一個(gè) pending
的發(fā)給鍵盤設(shè)備棧棧頂?shù)?IRP_MJ_READ 的 IRP。<BR><BR>kd> !irpfind<BR>unable to get
large pool allocation table - either wrong symbols or pool tagging is
disabled<BR><BR>Searching NonPaged pool (fe313000 : fe52b000) for Tag:
Irp?<BR><BR>Irp [ Thread ] irpStack: (Mj,Mn) DevObj
[Driver]<BR>...<BR>fe439008 [fe427940] irpStack: ( 3, 0) fe4f5df0 [
\Driver\Kbdclass]<BR>...<BR><BR>這個(gè) IRP 的地址為 fe439008
,我們看看它的詳細(xì)情況<BR><BR>kd> !irp fe439008<BR>Irp is active with 6 stacks 6
is current (= 0xfe43912c)<BR>No Mdl System buffer = fe426568 Thread
fe427940: Irp stack trace. <BR>cmd flg cl Device File
Completion-Context<BR>[ 0, 0] 0 0 00000000 00000000
00000000-00000000 <BR><BR>Args: 00000000 00000000 00000000
00000000<BR>[ 0, 0] 0 0 00000000 00000000
00000000-00000000 <BR><BR>Args: 00000000 00000000 00000000
00000000<BR>[ 0, 0] 0 0 00000000 00000000
00000000-00000000 <BR><BR>Args: 00000000 00000000 00000000
00000000<BR>[ 0, 0] 0 0 00000000 00000000
00000000-00000000 <BR><BR>Args: 00000000 00000000 00000000
00000000<BR>[ 0, 0] 0 0 00000000 00000000
00000000-00000000 <BR><BR>Args: 00000000 00000000 00000000
00000000<BR>>[ 3, 0] 0 1 fe4f5df0 fe426608 00000000-00000000
pending<BR>\Driver\Kbdclass<BR>Args: 00000078 00000000 00000000
00000000<BR>看到了這個(gè) IRP pending。<BR><BR>這時(shí) 線程 win32k!RawInputThread 會(huì)在一個(gè)
nt!KeWaitForMultipleObjects 上等待,等待的對(duì)象之一就是,希望從鍵盤驅(qū)動(dòng)中讀數(shù)據(jù)的那個(gè) IRP
。<BR><BR>當(dāng)鍵盤上有鍵被按下時(shí),引發(fā)中斷,導(dǎo)致驅(qū)動(dòng)從端口讀取按鍵的掃描碼。驅(qū)動(dòng)經(jīng)過一系列處理,最后調(diào)用 IoCompleteRequest
結(jié)束那個(gè)等待著的 IRP。<BR><BR>IRP 的結(jié)束會(huì)使得 線程 win32k!RawInputThread 在
nt!KeWaitForMultipleObjects 上對(duì)從鍵盤讀取數(shù)據(jù)的等待的結(jié)束。這將使得前面 ZwReadFile 的傳入?yún)?shù)
ApcRoutine 即 win32k!InputApc 被執(zhí)行。<BR><BR>win32k!InputApc
中。調(diào)用兩個(gè)函數(shù),win32k!ProcessKeyboardInput,win32k!StartDeviceRead。win32k!ProcessKeyboardInput
負(fù)責(zé)處理剛才讀到的輸入數(shù)據(jù),比如分發(fā)給應(yīng)該得到這個(gè)鍵盤按鍵的進(jìn)程。數(shù)據(jù)處理完之后,也就是 win32k!ProcessKeyboardInput
結(jié)束之后。win32k!StartDeviceRead 被調(diào)用,win32k!StartDeviceRead 會(huì)調(diào)用 nt!ZwReadFile
要求讀入數(shù)據(jù)。<BR><BR>3.4 補(bǔ)充<BR><BR> win32k
實(shí)際是一個(gè)驅(qū)動(dòng)程序,不屬于應(yīng)用程序,所以把 win32k!RawInputThread 叫做鍵盤驅(qū)動(dòng)的使用層或許更合適。至于
win32k!RawInputThread 如何把得到的鍵盤上的按鍵分發(fā)給各個(gè)進(jìn)程,我們不研究。曾經(jīng)使我奇怪的是,為什么 ZwCreateFile
的參數(shù),能找到的設(shè)備對(duì)象是鍵盤設(shè)備棧的 PDO,而 ZwCreateFile 產(chǎn)生的 IRP 卻是發(fā)給鍵盤設(shè)備棧的棧頂。為什么 ZwReadFile
句柄所找到的設(shè)備對(duì)象是鍵盤設(shè)備棧的 PDO,而 ZwReadFile 產(chǎn)生的 IRP 卻是發(fā)給鍵盤設(shè)備棧最頂端的設(shè)備對(duì)象。后來跟蹤
NtCreateFile,NtReadFile
找到了原因。從中我們也可以看出,CreateFile,ReadFile,WriteFile,DeviceIoControl,CloseHandle
產(chǎn)生的 IRP 都是發(fā)給設(shè)備棧的棧頂?shù)模缓?IRP 在設(shè)備棧上自上而下。<BR><BR><BR>歡迎交流,歡迎交朋友,<BR>歡迎訪問<BR>主頁
<A href="http://jiurl.yeah.net/" target=_blank>http://jiurl.yeah.net/</A>
<A href="http://jiurl.nease.net/"
target=_blank>http://jiurl.nease.net/</A> 論壇 <A
href="http://jiurl.cosoft.org.cn/forum"
target=_blank>http://jiurl.cosoft.org.cn/forum</A>
<P>f啊k,不帶你們這樣的啊,有好事不叫我。
<P>
<P> </P></TD></TR></TBODY></TABLE></DIV>
<SCRIPT src="JIURL鍵盤驅(qū)動(dòng) 2.files/nnselect.js"></SCRIPT>
</BODY></HTML>
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -