windows設備驅(qū)動程序_第1頁
windows設備驅(qū)動程序_第2頁
windows設備驅(qū)動程序_第3頁
windows設備驅(qū)動程序_第4頁
windows設備驅(qū)動程序_第5頁
已閱讀5頁,還剩22頁未讀 繼續(xù)免費閱讀

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權,請進行舉報或認領

文檔簡介

匯報人:邢成婧玉軟工(實)11401Windows設備驅(qū)動程序前言Linux是一種日趨成熟完善的操作系統(tǒng).越來越多的軟硬件廠商開始使用Linux平臺來開發(fā)自己的產(chǎn)品,因而對基于該平臺的設備驅(qū)動程序的需求也愈來愈多。同時PCI總線作為一個具有兼容性強、平臺無關性等特點從的計算機總線標準。日前得到了廣泛的應用。目錄0304編寫驅(qū)動程序的基礎知識驅(qū)動中使用鏈表01驅(qū)動開發(fā)環(huán)境的創(chuàng)建02驅(qū)動程序結構1驅(qū)動開發(fā)環(huán)境的搭建01OPTION關于DDK02OPTION關于驅(qū)動程序的編譯03OPTION關于驅(qū)動程序的運行關于DDK開發(fā)驅(qū)動程序必備的一個東西就是DDK(DeviceDevelopmentKit,設備驅(qū)動開發(fā)包),它跟我們在ring3常聽到的SDK差不多,只不過它們分別支持開發(fā)不同的程序而已。DDK和微軟其他的產(chǎn)品一樣,具有良好的向后兼容性,比如你用DDK2000開發(fā)的驅(qū)動在DDKXP里面同樣可以編譯,但反之卻不能保證DriverStudio之類的驅(qū)動開發(fā)工具,其實那只是對DDK的簡單封裝,跟SDK與MFC的關系差不多,不過DriverStudio不僅僅是對DDK的封裝,而是個完整的開發(fā)工具包,它提供了很多有用的工具用于驅(qū)動程序的開發(fā)和調(diào)試,不過這些工具可以單獨提取出來使用?!?sys”文件,同時還需要自己編寫makefile和sources文件。對于使用VC開始學習編程的人們來說,makefile概念有點可能有點陌生。實際上VC本身只是個框架,“編譯”這個工作還是由一個名為“cl.exe”的命令行工具執(zhí)行的,VC不過是通過一個良好的界面幫我們完成了一些參數(shù)設置的工作。使用VC來編譯驅(qū)動程序是可行的。VC6.0到新的VS2008都沒有被遺漏。

使用EasySys這個小工具,可以通過簡單的設置生成一個完整的“.dsw”工程。關于驅(qū)動程序的編譯關于驅(qū)動程序的運行通常生成的驅(qū)動程序格式都是“.sys”,雖然它也是PE格式,但不能直接運行,必須被加載到系統(tǒng)中。因此編寫好一個驅(qū)動程序后,如果想運行查看結果,則必須使用一些工具來進行加載。使用一個名為“KmdManager”的小工具來加載驅(qū)動。運行界面如圖2驅(qū)動程序結構01驅(qū)動程序頭文件02驅(qū)動程序入口點03創(chuàng)建設備歷程04卸載驅(qū)動歷程

NT式驅(qū)動需要導入的頭文件是“ntddk.h”,而WDM式驅(qū)動需要導入的“wdm.h”,即:#include“ntddk.h”;。在驅(qū)動中用到的變量或函數(shù)都需要指定分配在分頁或非分頁內(nèi)存中,分頁內(nèi)存在物理內(nèi)存不夠的情況下可能會被交換出去,對于一些需要高IRQL的例程絕對不能被交換出頁面,因此它們必須被定義為非分頁內(nèi)存。通常來說在驅(qū)動程序的自定義頭文件中都是定義了一些宏或函數(shù)聲明。驅(qū)動程序頭文件驅(qū)動程序入口點在驅(qū)動對象DriverObject中,有個函數(shù)指針數(shù)組MajorFunction,它里面的每一個元素都記錄著一個函數(shù)的地址對應著相應的IRP,我們可以通過簡單地設置這個數(shù)組將IRP與相應的派遣函數(shù)關聯(lián)起來。由于在進入DriverEntry之前,I/O管理器會_IopInvalidDeviceRequest的地址填滿整個MajorFunction數(shù)組,因此除了我們自行設置過的IRP之外,其他的IRP都與系統(tǒng)默認的_IopInvalidDeviceRequest函數(shù)關聯(lián)。

驅(qū)動中的例程實際上就是函數(shù)的另外一種說法,實際上例程與函數(shù)還是有所區(qū)別的。創(chuàng)建設備是在DriverEntry中完成的創(chuàng)建設備歷程創(chuàng)建設備歷程//創(chuàng)建設備對象

RtlInitUnicodeString(&ntDeviceName,TEST_DEVICE_NAME_W);Status=IoCreateDevice(DriverObject,sizeof(DEVICE_EXTENSION),//DeviceExtensionSize&ntDeviceName,//DeviceNameFILE_DEVICE_TEST,//DeviceType0,//DeviceCharacteristicsTRUE,//Exclusive&deviceObject//[OUT]);

if(!NT_SUCCESS(Status))

{KdPrint(("[Test]IoCreateDeviceErrorCode=0x%X\n",Status));returnStatus;}deviceExtension=(PDEVICE_EXTENSION)deviceObject->DeviceExtension;//創(chuàng)建符號鏈接RtlInitUnicodeString(&dosDeviceName,TEST_DOS_DEVICE_NAME_W);Status=IoCreateSymbolicLink(&dosDeviceName,&ntDeviceName);if(!NT_SUCCESS(Status)){KdPrint(("[Test]IoCreateSymbolicLinkErrorCode=0x%X\n",Status));IoDeleteDevice(deviceObject);returnStatus;

}卸載驅(qū)動例程是我們在DriverEntry中自己定義的,當驅(qū)動被卸載時I/O管理器負責調(diào)用該例程,它主要做一些掃尾處理的工作。相關代碼如下所示:UNICODE_STRINGdosDeviceName;

//釋放其他資源

//刪除符號鏈接

RtlInitUnicodeString(&dosDeviceName,TEST_DOS_DEVICE_NAME_W);IoDeleteSymbolicLink(&dosDeviceName);//刪除設備對象

IoDeleteDevice(DriverObject->DeviceObject);KdPrint(("[Test]Unloaded"));要想輸出一些信息,就需要調(diào)用DbgPrint函數(shù),不過這個函數(shù)輸出的信息我們無法直接看到,需要使用一些專門的工具,比如DbgView等。有些內(nèi)容我們只想在調(diào)試版輸出,在發(fā)行版忽略,因此DDK中定義了一個宏KdPrint,它在發(fā)行版不被編譯,只在調(diào)試版才會運行。KdPrint的用法很奇怪,由于它的定義:#defineKdPrint(_x_)DbgPrint_x_,這就導致了它的用法很奇怪,在使用時外層要有兩個連續(xù)的括號。卸載設備例程編寫驅(qū)動程序的基礎知識ABCD示例程序內(nèi)核模式下的字符串操作內(nèi)核模式下各種開頭函數(shù)的區(qū)別關系內(nèi)核模式下的字符串操作內(nèi)核模式與用戶模式一樣都是有ANSI和UNICODE兩種字符串,Windows內(nèi)核是使用Unicode編碼的,ANSI只在很少的特殊場合才會使用,而這種場合往往是非常罕見的,因此不考慮ANSI字符串。Unicode字符串有一個結構體定義如下:

typedefstruct_UNICODE_STRING{USHORTLength;//字符串的長度(字節(jié)數(shù))USHORTMaximumLength;//字符串緩沖區(qū)的長度(字節(jié)數(shù))

PWSTRBuffer;//字符串緩沖區(qū)

}UNICODE_STRING,*PUNICODE_STRING;需要注意的是,當我們定義了一個UNICODE_STRING變量之后,它的Buffer域還沒有分配空間,因此我們不能直接賦值,好的做法是使用微軟提供的Rtl系列函數(shù)。

UNICODE_STRINGstr;RtlInitUnicodeString(&str,L"myfirststring!");或者如下所示:

#include<ntdef.h>UNICODE_STRINGstr=RTL_CONSTANT_STRING(L"myfirststring!");UNICODE字符串并不是以“\0”來表示字符串結束的,而是依靠UNICODE_STRING的Length域來確定。在驅(qū)動開發(fā)的過程中,可能遇到很多不同開頭的函數(shù),如前面遇到過的Rtl和Io系列,此外還有比如Ex、Ps、Nt等等。常見的函數(shù)開頭及其含義如下表所示。內(nèi)核模式下各種開頭函數(shù)區(qū)別NativeAPI從用戶模式穿越進入到內(nèi)核模式調(diào)用系統(tǒng)服務,這個穿越過程是通過軟中斷的方式進入的。這個軟中斷的實現(xiàn)方法在不同版本的Windows實現(xiàn)方式略有不同,在Win2K下是通過“int2eh”實現(xiàn)的,在WinXP是通過“sysenter”指令完成的。

軟中斷會將NativeAPI的參數(shù)和系統(tǒng)服務號的參數(shù)一起傳進內(nèi)核模式,不同的NativeAPI會對應不同的系統(tǒng)服務號,這個過程是由SSDT輔助完成的。

系統(tǒng)服務函數(shù)一般和NativeAPI具有相同的名字,例如都是NtCreateFile,但它們的實現(xiàn)不同,系統(tǒng)服務調(diào)用是在“ntoskrnl.exe”導出的。

示例程序關系在驅(qū)動中使用鏈表內(nèi)存的分配與釋放設備驅(qū)動分層使用LISTENTRY設備驅(qū)動內(nèi)存的分配與釋放傳統(tǒng)的C語言中,分配內(nèi)存常常使用的函數(shù)是malloc,但在驅(qū)動開發(fā)過程中這個函數(shù)不再有效。驅(qū)動中分配內(nèi)存,常用的是調(diào)用ExAllocatePoolWithTag或ExAllocatePool。

//定義一個內(nèi)存分配標記

#defineMEM_TAG‘MyTt’//目標字符串,接下來它需要分配空間。

UNICODE_STRINGdst={0};//分配空間給目標字符串。根據(jù)源字符串的長度。dst.Buffer=(PWCHAR)ExAllocatePoolWithTag(NonpagedPool,src->Length,MEM_TAG);if(dst.Buffer==NULL){//錯誤處理status=STATUS_INSUFFICIENT_RESOUCRES;

}dst.Length=dst.MaximumLength=src->Length;ExAllocatePoolWithTag的第一個參數(shù)NonpagedPool表明分配的內(nèi)存是非分頁內(nèi)存,這樣它們可以永遠存在于物理內(nèi)存,而不會被分頁交換到硬盤上去;第二個參數(shù)是長度;第三個參數(shù)是一個所謂的“內(nèi)存分配標記”。Windows內(nèi)核提供了一個雙向鏈表結構LIST_ENTRY,此外還有一些其他的結構,比如SINGLE_LIST_ENTRY(單向鏈表).LIST_ENTRY是一個雙向鏈表結構,但直接使用它將毫無任何意義,通常的做法是自定義一個結構體,將LIST_ENTRY作為該結構體的一個子域,這樣給予了大限度的靈活性,因為數(shù)據(jù)需求千差萬別,只要簡單修改一下便可利用LIST_E

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
  • 4. 未經(jīng)權益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責。
  • 6. 下載文件中如有侵權或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

最新文檔

評論

0/150

提交評論