Windows键盘驱动结构与消息机制--转
https://www.douban.com/note/318793892/
本文主要介紹按鍵消息是如何傳遞到窗口并轉(zhuǎn)化為具體的按鍵消息的。
Windows系統(tǒng)是事件驅(qū)動(dòng)的多任務(wù)系統(tǒng),其中按鍵和鼠標(biāo)是主要的事件。按鍵是由鍵盤驅(qū)動(dòng)獲得并轉(zhuǎn)換,然后廣播給各個(gè)窗口。
整個(gè)架構(gòu)的核心是csrss.exe這個(gè)進(jìn)程,對(duì)于“一般”的窗口,收到的消息都是由這個(gè)任務(wù)產(chǎn)生的。該任務(wù)負(fù)責(zé)用CreateFile方式打開鍵盤設(shè)備并讀取信息,獲得對(duì)應(yīng)的鍵碼并發(fā)送給特定的進(jìn)程,csrss.exe的啟動(dòng)的輸入線程為win32k!RawInputThread,具體要把鍵盤消息發(fā)送給哪個(gè)線程,以及如何發(fā)送,是由csrss來控制的。
所以,每個(gè)進(jìn)程的MessageLoop實(shí)際上是從這里讀取的,于是SetWindowHook之類的函數(shù)有些是掛到各個(gè)進(jìn)程里,有些實(shí)際上是掛到了csrss里,達(dá)到監(jiān)控鍵盤的目的。但對(duì)于加密的控件(如網(wǎng)銀等),SetWindowHook不管用,但如果hook到RawInpuThread里,那么還是有可能讀到信息的。
csrss訪問的是鍵盤設(shè)備,具體這個(gè)設(shè)備是一個(gè)kbdclass設(shè)備,以下部分就是內(nèi)核的代碼空間了。
因?yàn)橐粋€(gè)系統(tǒng)里可能不只一個(gè)鍵盤(同理,鼠標(biāo)也是),所以需要一個(gè)統(tǒng)一的驅(qū)動(dòng)去管理所有的鍵盤設(shè)備,這個(gè)驅(qū)動(dòng)就是kbdclass.sys,鍵盤設(shè)備類驅(qū)動(dòng),對(duì)應(yīng)的設(shè)備名是L"\\Driver\\Kdbclass",RawInpuThread實(shí)際上訪問的是這個(gè)設(shè)備,而對(duì)于每個(gè)鍵盤,則是有各自的驅(qū)動(dòng),對(duì)于PS/2鍵盤是i8042prt.sys,對(duì)于USB鍵盤,這是另外的驅(qū)動(dòng),這些驅(qū)動(dòng)稱為port驅(qū)動(dòng),是真正的設(shè)備驅(qū)動(dòng),對(duì)應(yīng)的設(shè)備是KeyboadClass0、KeyboardClass1等等(有幾個(gè)鍵盤,數(shù)字就排到多少),RawInpuThread把請(qǐng)求發(fā)送到kbdclass,kbdclass把請(qǐng)求(IRP)pend到這一層,等待下層port驅(qū)動(dòng)返回。
這里需要特別提出的一個(gè)函數(shù)是KeyboardClassServiceCallback,這個(gè)函數(shù)是kbdclass一層的callback,下層設(shè)備驅(qū)動(dòng)的所有返回值都需要經(jīng)過它。所以,如果鉤子掛到這里,那么理論上所有的輸入都可以被攔截的,已經(jīng)親自測試過網(wǎng)銀控件的密碼會(huì)在此被泄露,但QQ不會(huì),QQ2013會(huì)啟動(dòng)失敗,估計(jì)是檢查了這個(gè)驅(qū)動(dòng)。
順便說一句,早期的QQ加密沒那么恐怖,但它是啟動(dòng)一個(gè)線程不停的SetWindowHook,使得自己的hook永遠(yuǎn)在第一個(gè),然后過濾掉所有的消息防止被人監(jiān)聽。后來的QQ可能是修改IDT里的鍵盤中斷實(shí)現(xiàn)的。
當(dāng)然病毒也可以通過filter驅(qū)動(dòng)注入到kbdclass和port驅(qū)動(dòng)之間,來實(shí)現(xiàn)監(jiān)聽鍵盤,這也是一種常見的情況。
所以,一個(gè)按鍵的消息產(chǎn)生流程如下:
1)硬件中斷/硬件端口數(shù)據(jù)
//WinIO能模擬,或者修改IDT是在這一層
2)鍵盤Port驅(qū)動(dòng)(USB or PS/2)
//Filter驅(qū)動(dòng)在此
//KeyboardClassServiceCallback也在這一層被調(diào)用
3)kbdclass驅(qū)動(dòng)
//處理鍵盤布局和鍵盤語言
4)Windows內(nèi)核邊界(zwCreate/zwReadFile)
----------------------(系統(tǒng)調(diào)用)----------------------
5)Windows內(nèi)核邊界(zwCreate/zwReadFile)
6)csrss.exe的win32k!RawInputThread讀取,完成scancode和vk的轉(zhuǎn)換
//SetWindowHook工作在這里(全局)
//kbd_event工作在這里
7)csrss.exe調(diào)用DispatchMessage等函數(shù)分發(fā)消息
//SetWindowHook工作在這里(進(jìn)程)
//PostMessage和SendMessage在這里
8)各個(gè)進(jìn)程處理消息
WinIO這個(gè)驅(qū)動(dòng)比較特殊,它提供接口可以允許應(yīng)用層直接寫端口,但只能寫PS/2端口,所以有些模擬按鍵程序通過WinIO來模擬按鍵。
對(duì)于標(biāo)準(zhǔn)的程序,PostMessage等函數(shù)可以完成模擬,但對(duì)于不太標(biāo)準(zhǔn)的軟件,只能用kbd_event來模擬,但有些軟件(如網(wǎng)銀控件)就只能在更靠近內(nèi)核的區(qū)域模擬了。
同時(shí),有一種輸入是很特殊的,就是DirectInput,這是DirectX提供的一種方法,大型游戲中很常見的用法,因?yàn)镈irectInput的輸入速度很快,繞過了消息層。但對(duì)于這種軟件,在kbdclass一層甚至都無法模擬。目前還不確定DirectInput工作在哪一層,猜測可能是在kbdclass和port驅(qū)動(dòng)之間,也許是一種filter驅(qū)動(dòng)。對(duì)于這種輸入方法,可以WinIO來模擬,但對(duì)于USB鍵盤則沒有辦法。
Windows提供了一套API:SendInput,這個(gè)驅(qū)動(dòng)發(fā)送按鍵消息時(shí)有兩種類型,一種是VK模式的,實(shí)際上跟kbd_event一樣,工作在csrss這一層,而另一種是ScanCode模式,MSDN里有這樣的描述:
Windows 2000/XP: Set the KEYEVENTF_SCANCODE flag to define keyboard input in terms of the scan code. This is useful to simulate a physical keystroke regardless of which keyboard is currently being used.
可以看出,這是能夠模擬更底層的按鍵的,理論上說是可以模擬DirectInput的按鍵的,實(shí)際測試也是這樣,但文檔中沒有說明在vista以后的版本是什么狀態(tài),所以暫時(shí)也無法知道在WIN7里的工作情況。
轉(zhuǎn)載于:https://www.cnblogs.com/davidwang456/p/8708619.html
總結(jié)
以上是生活随笔為你收集整理的Windows键盘驱动结构与消息机制--转的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 网银安全控件问题
- 下一篇: 组合的json文件分隔或者拆分