複製鏈接
請複製以下鏈接發送給好友

內核模式驅動

鎖定
Windows系統中兩種基本驅動程序之一,它的特點是:1、內核模式驅動程序將在執行其他應用程序代碼(包括受保護的子系統代碼)的非特權處理器模式中運行。除非用户模式驅動程序調用 Win32 API,否則將無法獲取對系統數據的訪問權。2、內核模式驅動程序將作為操作系統的執行部分(即支持一個或多個受保護的子系統的基礎操作系統組件)運行。大多數設備驅動程序將在內核模式中運行。內核模式驅動程序可執行某些受保護的操作,並可訪問用户模式驅動程序無法訪問的系統結構。但隨着訪問權的增加,調試難度和系統損害幾率也隨之增大。
中文名
內核模式驅動
性    質
Windows系統中基本驅動程序之一
特    點
將作為操作系統的執行部分運行等
分    類
虛擬設備驅動程序、打印驅動程等

內核模式驅動定義

Intel x86體系結構的處理器定義了4個級別的權限(稱為Ring),Windows系統使用了Ring0(供特權模式使用)和Ring3(供用户模式使用),Windows系統只使用了2個級別的權限級別的原因是為了和其他一些硬件系統兼容,這些硬件系統只有2個級別的權限,如Compaq Alpha和Silicon Graphics MIPS等。
每個用户模式的進程有其私有的地址空間,這些進程在最低的權限級別下運行(稱為Ring3或者用户模式),它們不允許執行CPU的特權指令,對系統所屬的數據、地址空間以及硬件等的訪問也是被嚴格限制的,例如,如果某個用户程序訪問4G地址空間中的高位2G,那麼系統就會立即將其終止執行。要注意的是,進程調用系統功能的時候,可以切換到內核模式執行,但是調用結束後,就返回到用户模式了。
用户模式的進程總是被認為是對操作系統穩定性的潛在威脅,所以它們的權限被嚴格地限制,任何觸及這些限制的舉動都將使進程被終止。
而內核模式的組件則可以共享這些受保護的內核模式內存空間,在特權級別下運行(也稱為Ring0),允許執行任何CPU指令,包括特權指令,可以無限制地訪問系統數據、代碼和硬件資源。
內核模式代碼運行在系統地址空間中,並總是被認為是可信任的,一旦被裝載運行後,驅動程序就是系統的一部分,可以無限制地做任何事情。
總的來説,用户模式程序被完全從操作系統隔離,這對操作系統的完整性來説是件好事情,但對某些種類的應用程序來説就太頭痛了,比如Debug工具。幸運地是,這些在用户模式幾乎不可能完成的任務完全可以通過內核模式的驅動程序來完成,因為這些驅動程序的操作是不受限制的。因此,如果你打算從用户模式存取操作系統內部的數據結構或者函數的話,唯一的方法就是將一個內核模式驅動程序裝載到系統的地址空間中(並調用它),這是很簡單的事情,操作系統完全支持這樣的操作。

內核模式驅動主要組成部分

根據地址空間、代碼權限和職責的不同,Windows NT內部劃分為兩個截然不同的部分。
地址空間的享用方式也非常容易理解,整個32位系統的4GB內容被劃分為兩個相等的部分,用户模式(user-mode)的進程使用的地址空間被映射到低位的2GB上(地址範圍00000000 - 7FFFFFFFh),而高位的2GB(地址範圍80000000h - 0FFFFFFFFh)則供操作系統的組成部分來使用,如設備驅動程序、系統內存池、系統使用的數據結構等,在這部分中,內存共享的權限和職責等方面就要複雜一點了。
下面就是用户模式進程的一些簡單分類:
◎ 系統支持進程--如Logon進程(位於\%SystemRoot%\System32\Winlogon.exe)
◎ 服務進程--如Spooler進程(位於\%SystemRoot%\System32\spoolsv.exe
用户應用程序--任何Win32、Windows 3.1、DOS、POSIX或者OS/2程序
◎ 子系統--Windows內置3個子系統:Win32(位於\%SystemRoot%\System32\Csrss.exe)、POSIX子系統(位於\%SystemRoot%\System32\Psxss.exe)和OS/2子系統(位於\%SystemRoot%\System32\Os2ss.exe),在Windows XP以及後續的操作系統中,POSIX和OS/2子系統已經被去掉了。
而下面是內核模式的一些模塊:
◎ 運行模塊--內存管理、進程和線程的管理、安全機制等
◎ 內核--線程調度、中斷、異常的分派等(運行模塊和內核位於\%SystemRoot%\System32\Ntoskrnl.exe
◎ 設備驅動程序--硬件設備驅動程序、文件系統和網絡驅動程序
硬件抽象層(Hardware Abstraction Layer, HAL)--將內核、設備驅動程序和運行模塊和具體的硬件平台隔離開(位於\%SystemRoot%\System32\Hal.dll
◎ 窗口和圖形系統--實現GUI函數,如處理窗口、用户界面的控制和繪畫等(位於\%SystemRoot%\System32\Win32k.sys)

內核模式驅動分類

Windows NT支持的設備驅動程序的範圍很廣,它們的分類如下:
用户模式的驅動程序
虛擬設備驅動程序(Virtual Device Drivers/VDD)--用户模式的組件,用於為16位的MS-DOS應用程序提供虛擬的執行環境,雖然和Windows 95/98裏面的VxD從功能上看起來是差不多的,但實際上兩者根本不同。
打印驅動程序--將與設備無關的圖形轉換到和打印機相關的指令
內核模式驅動程序:
◎ 文件系統驅動程序--實現標準的文件系統模型
◎ 傳統設備驅動程序--用於在沒有其他驅動程序幫助的情況下控制硬件設備,它們是為老版本的Windows NT系統所寫的,但是也可以不加修改地運行在Windows 2000/XP/2003系統上
視頻驅動程序--不用多介紹了吧?
◎ 流驅動程序--支持多媒體設備,如聲卡
◎ WDM驅動程序--即Windows Driver Model,WDM包括對Windows NT電源管理即插即用的支持,WDM可以在Windows 2000、Windows 98和Windows ME下實現,所以在這些操作系統下,WDM驅動程序在源代碼級別是兼容的,在有些情況下,在二進制代碼級別上也是兼容的
在不同的資料中,對驅動程序的分類方法可能完全不同,但這並不是問題。
從名稱理解,設備驅動程序是用於控制某個設備的,但這個"設備"並不一定指的是物理上存在的設備,它也可以是虛擬設備
從文件結構上講,設備驅動程序就是一個普普通通的PE格式文件,就像其他EXE或者DLL文件一樣。設備驅動程序是一個可裝載的內核模式模塊,一般以SYS為擴展名。他們之間的不同點在於兩種的裝載方法是完全不同的。實際上,我們可以把設備驅動程序理解成一個內核模式的DLL,用於完成在用户模式下所不能完成的功能,本質上的不同就在於我們無法直接存取設備驅動程序的代碼和數據(注:DLL的代碼和數據是可以被直接存取的,這方面的資料可以參考《Windows環境下32位彙編語言程序設計一書》中的DLL一章),唯一的存取方式是通過I/O管理器,它提供了簡單的驅動程序管理環境。
剛開始學習KMD的開發的時候,你可能感覺自己根本就是一個菜蟲(旁白:就是比菜鳥還低級,呵呵~~~),因為你以前用Windows API開發程序的經驗在這裏根本幫不上忙,即使你以前寫過n多個(n趨向無窮大……)用户模式下的應用系統也沒用。內核提供了完全不同的函數和數據結構,以至於你要從頭開始瞭解,而且資料奇缺無比,一般情況下,可供參考的只有頭文件。

內核模式驅動驅動程序

大部分控制硬件設備的驅動程序是分層的驅動程序,分層驅動的概念就是當用户模式發出一個請求時,每個請求從高層次的驅動程序逐層處理並流傳到低層次的驅動程序中,一個I/O請求的處理可能分步在多個驅動程序中,例如,如果一個應用程序發出讀盤請求,處理請求會在多個驅動程序中流過,在其中你也可以再加入n多個過濾驅動程序(比如插入一個加解密的模塊)。
單層的驅動程序是最簡單的一類驅動程序,這一類驅動程序通常並不依賴於其他已裝載的驅動程序,他們的接口僅僅針對用户模式的應用程序,開發和調試這一類驅動程序是非常簡單的,我們即將開始討論的就是這類程序,其他類型的驅動程序將在以後討論。
在大多數情況下,我們的系統中只安裝了一個CPU,所以,對於所有這些運行中的程序來説,操作系統對每個進程中的線程所使用的CPU時間進行調度,循環為每個線程分配時間片,這就造成了多個程序同時執行的假象。如果系統中安裝了多個CPU,那麼操作系統的調度算法將複雜得多,因為它要將各CPU上的線程進行平衡。如果Windows檢測到一個新線程要開始運行了,它將進行一次上下文切換(context switch)(注:上下文(Content)實際上就是線程運行的環境,也就是運行時各寄存器和其他東東的狀態,更自然的理解就是"線程狀態")。所謂上下文切換就是保存線程運行時的機器狀態,然後將另一個線程的狀態恢復並重新開始執行。如果重新開始執行的線程屬於另一個進程,那麼該進程的地址空間也將被同時切換過來(通過在CR3寄存器中裝入頁表)。
每個用户進程都有私有的地址空間,所以他們的頁表都是不同的,CPU通過切換頁表來將虛擬地址映射到物理地址,設備驅動程序並不需要直接做這些工作。上下文切換比較耗CPU時間,所以驅動程序一般不創建它們自己的線程,它們一般在下列環境中的一箇中運行:
1. 在發起I/O請求的用户線程中運行
2. 在內核模式下的系統線程中運行
3. 作為中斷運行(並不處於哪個特定的進程或線程中,因為它們都被暫時掛起了)
在處理I/O請求包(IRPs)時,我們總是運行在和用户模式的調用者相同的進程上下文中運行,這樣我們就能對用户程序地址空間進行尋址。但是當驅動程序被加載或者卸載的時候,我們將在系統進程中運行,這時存取的只能是系統的地址空間。
中斷是任何操作系統都少不了的組成部分,中斷使處理器打斷正常的程序流程來首先處理它們,中斷分硬件中斷和軟件中斷兩種,中斷是分優先級的,一個高優先級的中斷可以打斷低優先級的中斷的執行。
Windows中把中斷優先級稱為IRQLs(interrupt request levels),在系統中表示為從0(被動)到31(高級)的整數,其中大的數值對應高優先級的中斷。注意IRQL值的含義和線程調度優先級的含義是完全兩碼事情。
嚴格來説,IRQL=0的中斷並不是中斷,因為它無法打斷任何其他代碼的執行(因為沒有比0更低級的代碼了),所有的用户模式線程在這個級別上運行,該級別也稱為被動級別(passive level)。我們後面要討論的驅動程序代碼也在這個級別上運行,注意這並不意味着其他的驅動程序也在被動級別下運行。
因此這裏還有兩個重要的結論:
首先:當驅動程序運行於用户模式程序的線程中時,代碼的執行可能被高IRQL級別的代碼打斷,一些函數可以用來獲取當前的IRQL值,並可以對其進行提升或者降低。
第二:被動模式IRQL下的代碼可以調用任何的內核函數(DDK指明瞭每個函數允許調用的IRQL級別),可以對已分頁的或未分頁的內存進行尋址(注:即已映射過的虛擬地址還是物理內存地址)。反過來,當在一個比較高的IRQL級別下對分頁內存進行尋址時(指等於或高於DISPATCH_LEVEL),系統將崩潰,因為這時內存管理器的IRQL級別反而比較低,以至於無法處理頁錯誤了。
我想每個人都見過著名的藍屏死機畫面,即"Blue Screen Of Death",簡稱為BSOD,也許根本不需要解釋它是怎麼出現或者在什麼時候出現的,因為在後面的KMD開發過程中,你會很頻繁地遇到它們。
內核模式下,Windows不對任何系統內存進行保護,由於內核模式的驅動程序可以對系統內存和操作系統的地址空間進行任意存取,所以你必須對你開發的驅動程序進行嚴格的測試,以防它危及到系統的穩定。
你可以把這個作為最基本的原則,另外,如果沒有線程上下文、中斷優先級、內核模式和用户模式等方面的概念,開發內核模式驅動程序將是不可能的事(天哪,我才發現,我連菜蟲都算不上,我竟然是~~~~~~菜菜的單細胞生物!嗚嗚~~)
Windows DDK是MSDN專業版和宇宙版的一部分,它也可以從microsoft.com ddk 下載,對於開發設備驅動程序來説,DDK是關於Windows NT內部信息,包括系統函數、數據結構等的豐富資源,不幸的是,微軟已經停止了免費發放DDK,所以只好去買正版的CD了(沒有槍,沒有炮,盜版游擊隊給我們造~~~)
除了文檔,DDK還包含了一堆的庫文件(*.lib),這些庫可以在鏈接的時候用上。這些庫有兩種版本:普通的版本(稱為free build)和特殊的包含Debug信息的版本(稱為checked build),它們分別位於%ddk%\libfre\i386和%ddk%\libchk\i386目錄下,check build是在編譯Windows源代碼時加上DEBUG標誌後生成的,在開發驅動程序時,它們可以提供更加精確的錯誤定位,但是你首先要根據你的操作系統選擇合適的lib版本才行。
KmdKit包含了所有用匯編開發KMD所需要的東西:include文件、lib文件宏定義、例子文件、工具和一些文章,你可以自己在軟件包中找到更多的東西,下一節我們將從這個軟件包中包括的一些例子開始學習KMD的編程。
調試內核模式的代碼需要合適的調試器,Compuware的SoftIce是個不錯的選擇(見compuware.com products numega index.htm),當然你也可以使用Microsoft Kernel Debugger,它需要兩台計算機:主機和目標機器,目標機器是被調試的機器,主機是運行調試軟件的機器。Mark Russinovich ( sysinternals.com ) 也寫了一個工具,叫做LiveKd,它允許在單台機器上運行Microsoft Kernel Debugger,而不再需要兩台機器了。