好啦,辛辛苦苦終于寫(xiě)完了程序,讓我們編譯運(yùn)行吧!按下Ctrl+F5(嘿嘿,讓我們先假設(shè)你習(xí)慣用VC來(lái)寫(xiě)程序),我等啊等……疑?怎么毫無(wú)動(dòng)靜的?再看看Output窗口,哇!有幾百個(gè)錯(cuò)誤?。?!不禁頭大——這是怎么回事呢? 原來(lái),WDM程序編譯出來(lái)的并不是我們常見(jiàn)的.exe,而是.sys文件,在未經(jīng)設(shè)置編譯環(huán)境之前,是不能直接用VC來(lái)編譯的(這就是為什么會(huì)有幾百個(gè)錯(cuò)誤了)。這種類型的文件你可以在WINNT\System32\Drivers里面找到很多。其實(shí)驅(qū)動(dòng)程序也是一種PE文件,它同樣由DOS MZ header開(kāi)頭,也有完整的DOS stub和PE header,同樣擁有Import table和Export table——hoho……那跟普通的PE文件有什么不一樣呢?偉大的領(lǐng)袖毛主席教育我們,實(shí)踐是檢驗(yàn)真理的唯一標(biāo)準(zhǔn)。那么就讓我們先來(lái)做個(gè)小剖析,加深對(duì).sys文件的認(rèn)識(shí)吧!(如果你對(duì).sys的內(nèi)部細(xì)節(jié)沒(méi)有興趣的話,可以略過(guò)不看。^_^) 首先祭出Delphi里附帶的tdump.exe程序(別問(wèn)我為什么用這個(gè),這只是純粹的習(xí)慣問(wèn)題)。讓我們鍵入: C:\WINNT\System32\Drivers>tdump ccport.sys -em -ee 參數(shù)-em是列出Import table,-ee是列出Export table。回車之后,屏幕列出一大堆東西:
C:\WINNT\SYSTEM32\DRIVERS>tdump ccport.sys -em -ee Turbo Dump Version 5.0.16.12 Copyright ? 1988, 2000 Inprise Corporation Display of File CCPORT.SYS
IMPORT: NTOSKRNL.EXE={hint:011Fh}.’memcpy’ IMPORT: NTOSKRNL.EXE={hint:003Dh}.’IoDeleteDevice’ IMPORT: NTOSKRNL.EXE={hint:0030h}.’IoAttachDeviceToDeviceStack’ IMPORT: NTOSKRNL.EXE={hint:008Eh}.’KeSetEvent’ IMPORT: NTOSKRNL.EXE={hint:0068h}.’IofCallDriver’ IMPORT: NTOSKRNL.EXE={hint:0095h}.’KeWaitForSingleObject’ IMPORT: NTOSKRNL.EXE={hint:0074h}.’KeInitializeEvent’ IMPORT: NTOSKRNL.EXE={hint:003Fh}.’IoDetachDevice’ IMPORT: NTOSKRNL.EXE={hint:00D3h}.’RtlFreeUnicodeString’ IMPORT: NTOSKRNL.EXE={hint:0077h}.’KeInitializeSpinLock’ IMPORT: NTOSKRNL.EXE={hint:0129h}.’strcpy’ IMPORT: NTOSKRNL.EXE={hint:0121h}.’memset’ IMPORT: NTOSKRNL.EXE={hint:003Ch}.’IoCreateUnprotectedSymbolicLink’ IMPORT: NTOSKRNL.EXE={hint:0038h}.’IoCreateDevice’ IMPORT: NTOSKRNL.EXE={hint:00C2h}.’RtlAnsiStringToUnicodeString’ IMPORT: NTOSKRNL.EXE={hint:0069h}.’IofCompleteRequest’ IMPORT: NTOSKRNL.EXE={hint:0124h}.’sprintf’ IMPORT: NTOSKRNL.EXE={hint:003Eh}.’IoDeleteSymbolicLink’ IMPORT: NTOSKRNL.EXE={hint:0042h}.’IoFreeIrp’ IMPORT: NTOSKRNL.EXE={hint:004Dh}.’IoInitializeIrp’ IMPORT: NTOSKRNL.EXE={hint:002Dh}.’IoAllocateIrp’ IMPORT: NTOSKRNL.EXE={hint:0027h}.’InterlockedExchange’ IMPORT: NTOSKRNL.EXE={hint:0025h}.’InterlockedCompareExchange’ IMPORT: NTOSKRNL.EXE={hint:0035h}.’IoCancelIrp’ IMPORT: NTOSKRNL.EXE={hint:012Ah}.’strlen’ IMPORT: NTOSKRNL.EXE={hint:0126h}.’strcat’ IMPORT: NTOSKRNL.EXE={hint:0114h}.’atoi’ IMPORT: NTOSKRNL.EXE={hint:0128h}.’strcmp’ IMPORT: NTOSKRNL.EXE={hint:0034h}.’IoBuildSynchronousFsdRequest’ IMPORT: NTOSKRNL.EXE={hint:00D5h}.’RtlInitAnsiString’ IMPORT: HAL.DLL={hint:0006h}.’KfAcquireSpinLock’ IMPORT: HAL.DLL={hint:0009h}.’KfReleaseSpinLock’
EXPORT ord:0001=’Vcomm_DriverControl’
|
我們可以很清楚地看到,它主要調(diào)用了NTOSKRNL.EXE和HAL.DLL文件(實(shí)際上你會(huì)發(fā)現(xiàn),幾乎所有的WDM驅(qū)動(dòng)程序都會(huì)調(diào)用NTOSKRNL.EXE文件,從它的名字你可以看出為什么了吧?),并且輸出了一個(gè)函數(shù)“Vcomm_DriverControl”。這表明,其實(shí).sys跟.exe文件一樣,都是一種PE文件來(lái)的。不同的是,.sys文件Import的通常是NTOSKRNL.EXE,而.exe文件Import的通常是KERNEL32.DLL和USER32.DLL。 知道了這些有什么用呢?實(shí)際上,由于.sys通常不調(diào)用KERNEL32.DLL和USER32.DLL,所以你是不能在設(shè)備驅(qū)動(dòng)程序里面調(diào)用任何C、C++和Win32函數(shù)的,而且也不能用C++關(guān)鍵字new和delete等(可以用malloc和free來(lái)代替),而必須使用大量的內(nèi)核函數(shù)。為了讀者的方便,下面我列出一些常見(jiàn)的驅(qū)動(dòng)程序可用的內(nèi)核函數(shù):
Ex… 執(zhí)行支持 Hal… 硬件抽象層(僅NT/Windows 2000) Io… I/O管理器(包括即插即用函數(shù)) Ke… 內(nèi)核 Ks… 內(nèi)核流IRP管理函數(shù) Mm… 內(nèi)存管理器 Ob… 對(duì)象管理器 Po… 電源管理 Ps… 進(jìn)程結(jié)構(gòu) Rtl… 運(yùn)行時(shí)庫(kù) Se… 安全引用監(jiān)視 Zw… 其他函數(shù)
|
最后讓我們?cè)賮?lái)看看,寫(xiě)設(shè)備驅(qū)動(dòng)程序時(shí)必須注意的一些問(wèn)題: 1、 內(nèi)核宏如果查看DDK頭文件,會(huì)發(fā)現(xiàn)有幾個(gè)內(nèi)核函數(shù)是以宏的方式實(shí)現(xiàn)的。這種宏中有幾個(gè)宏的定義是相當(dāng)糟糕的。例如,我們看到RemoveHeadList的定義如下:
#define RemoveHeadList(ListHead) (ListHead)->Flink; {RemoveEntryList((ListHead)->Flink)}
|
如果以以下方式調(diào)用RemoveHeadList,則將編譯錯(cuò)誤的代碼:
if(SomethingInList) Entry = RemoveHeadList(list);
|
使這個(gè)調(diào)用安全的唯一方法是使用花括號(hào):
if(SomethingInList) { Entry = RemoveHeadList(list); }
|
所以我們切勿為了貪圖一時(shí)的方便,而使用不太規(guī)范的寫(xiě)法,最好是在所有的if、for和while等語(yǔ)句中使用花括號(hào)。
2、驅(qū)動(dòng)程序函數(shù)名稱 跟C/C++的main()函數(shù)一樣,設(shè)備驅(qū)動(dòng)程序也有一個(gè)必須存在,而且只能以DriverEntry()為名稱的入口函數(shù)。然而,除此之外,我們可以使用任何名字來(lái)給其他函數(shù)命名——只要你自己記得就行了,當(dāng)然,最好符合某些特定的規(guī)范啦,例如匈牙利命名法……
3、安裝時(shí)的問(wèn)題 ·在Windows98中驅(qū)動(dòng)程序可執(zhí)行文件必須是8.3文件名。(別問(wèn)我為什么,我也不知道,我只能建議你去問(wèn)比爾該死) ·如果INF文件中含有非法節(jié)的詳細(xì)資料,Windows將不使用這個(gè)INF文件。
呼~~講了那么多,先去喝口水吧。其實(shí)本節(jié)羅羅嗦嗦講了一大堆,跟實(shí)際的編程卻并沒(méi)有太大的關(guān)系,不過(guò)為了將來(lái)養(yǎng)成良好的編程習(xí)慣,還是應(yīng)該遵守一下的,對(duì)嗎?好了,下一節(jié)我將詳細(xì)講解如何編譯、安裝驅(qū)動(dòng)程序,敬請(qǐng)留意。
|