VxD入門教程
1.背景知識(shí)?????
??為了看懂本篇所給的例子,需要C,?匯編及Windows?設(shè)備驅(qū)動(dòng)程序的相關(guān)知識(shí)。?
??
???
??2.開發(fā)工具??
???
??需要?Micros以下采??
用?VC++?6.0?為例)??
???
??3.目的??
???
??利用以上所列的開發(fā)工具,編寫一個(gè)動(dòng)態(tài)裝入的?VxD,?利用該VxD可以讀取內(nèi)存?
地址0??
處的中斷向量表。??
???
??4.開始??
???
??第一步:??
???
??用?VC++?新建一個(gè)工程,取名為?MiniVxd,?類型為?Win32?App?或?Console?App?
因?yàn)閂??
C++不提供直接生成??
???
??VxD的App?Wizard,所以只好自己在以上兩種App中選擇一個(gè),然后再進(jìn)行手工修?
改一下??
,需要修改的內(nèi)容??
???
??只有一處,即在?Link?的命令行上加上一個(gè)選項(xiàng)??
???
???/VXD??
???
??第二步:??
???
??新建一個(gè)空文件,在其中輸入以下代碼:??
???
??TITLE?MINIVXD?-?By?Ding?Kai??
???
??.386p??
???
??include?vmm.inc??
???
???
??MINIVXD_DYNAMIC?EQU?1??
???
??;?定義設(shè)備驅(qū)動(dòng)程序塊?DDB,?由于是動(dòng)態(tài)裝入的,所以設(shè)備ID和裝入順序可以取?
未定??
義值.??
???
??DECLARE_VIRTUAL_DEVICE?MINIVXD,?1,?0,?MsgDispatch,UNDEFINED_DEVICE_ID,?
??
???
???Undefined_Init_Order,?0,?0??
???
??VXD_LOCKED_CODE_SEG??
???
??;?定義消息派遣表,本例中只需要一條消息,即W32_DEVICEIOCONTROL,用于從?
Win32Ap??
p中利用??
???
??;?DeviceIoControl?API函數(shù)同本VxD進(jìn)行通訊.??
???
???
??BeginProc?MsgDispatch??
???
??Control_Dispatch?W32_DEVICEIOCONTROL,?W32DeviceIoControl,?sCall,??
???
???
???clc??
???
???ret??
???
??EndProc?MsgDispatch??
???
???
??VXD_LOCKED_CODE_EN???
??END??
???
???
??將文件存盤,文件名取為?VxdStub.asm,?然后用下列命令編譯該文件:??
???
??Aml?-coff?-W2?-DBLD_COFF?-DIS_32?-c?-Cx?-DMASM6?-I\95DDK\INC32??
VxdStub.asm??
???
???
??這將會(huì)生成?vxdstub.obj,將此OBJ文件加入到工程文件中。??
???
???
??第三步:??
???
??創(chuàng)建一個(gè)?C?語言文件,文件名取為?MiniVxd.c,在文件中輸入以下代碼:??
??#define?WIN40SERVICES??
???
??#pragma?warning?(disable:4229)??
???
??#include??
???
??#define?WANTVXDWRAPS??
???
??#pragma?intrinsic(memcpy)??
???
??#pragma?VxD_LOCKED_DATA_SEG??
???
???
??//?此處可以定義任何在VxD中需要的全局變量.??
???
??char?AnyData[200];??
???
??#pragma?VxD_LOCKED_CODE_SEG??
???
??///////////////////////////////////////////??
???
??DWORD?__stdcall?GetMemory(?DWORD?dwDDB,?PDIOCPARAMETERS?pD?)??
???
??{??
???
???BYTE?*p;??
???
??//?此處忽略了參數(shù)檢查,實(shí)際應(yīng)用中切不可如此?!!??
???
???p?=?(PBYTE)pD->lpvOutBuffer;??
???
???memcpy(p,?0,?1024);?//?讀取中斷向量表,共?1024?字節(jié)??
???
???return?1024;??
???
??}??
???
??///////////////////////////////////////////////////////??
???
??/*?Win32?interface?*/??
???
??///////////////////////////////////////////////////////??
???
??int?__stdcall??
???
??W32DeviceIoControl(?DWORD?dwIoCtrlCode,?/*ecx*/??
???
??DWORD?dwDDB,?/*ebx*/??
???
??DWORD?pDIOCParams?)?/*esi*/??
???
??{??
???
???PDIOCPARAMETERS?pD;??
???
???pD?=?(PDIOCPARAMETERS)pDIOCParams;??
???
???if?(?dwIoCtrlCode?==?DIOC_OPEN?||??
???
???dwIoCtrlCode?==?DIOC_CLOSEHANDLE)??
???
???return?0L;??
???
???//?Init?returned?value??
???
???if?(pD->lpcbBytesReturned)??
???
???*(DWORD?*)pD->lpcbBytesReturned?=?0;??
???
???if?(dwIoCtrlCode==1)?{?//?1?=?DeviceIoControl代碼??
???
???GetMemory(dwDDB,?pD);??
???
??}??
???
??else??
???
???return?ERROR_NOT_SUPPORTED;??
???
???return?0;??
???
??}??
???
??將本文件加入到工程文件中.??
???
???
??第四步:??
???
??創(chuàng)建一個(gè)模塊定義文件,此文件將要定義最終生成的VxD文件的段屬性并輸出設(shè)備?
驅(qū)動(dòng)??
程序塊,??
???
??輸入下面的代碼,并將文件存為?MiniVxd.def,同時(shí)將其加入到工程文件中.??
???
??VXD?MINIVXD?DYNAMIC??
???
??DESCRIPTION?'Written?by?Ding?Kai'??
???
??SEGMENTS??
???
??_LTEXT?CLASS?'LCODE'?PRELOAD?NONDISCARDABLE??
???
??_LDATA?CLASS?'LCODE'?PRELOAD?NONDISCARDABLE??
???
??_TLS?CLASS?'LCODE'?PRELOAD?NONDISCARDABLE??
???
??_BSS?CLASS?'LCODE'?PRELOAD?NONDISCARDABLE??
???
??_ITEXT?CLASS?'ICODE'?DISCARDABLE??
???
??_IDATA?CLASS?'ICODE'?DISCARDABLE??
???
??_PTEXT?CLASS?'PCODE'?NONDISCARDABLE??
???
??_PDATA?CLASS?'PDATA'?NONDISCARDABLE?SHARED??
???
??HEAPSIZE?10240??
???
??STACKSIZE?40960??
???
??EXPORTS??
???
??MINIVXD_DDB?@1??
???
???
??當(dāng)然,其中有些段在本程序中不存在,此處列出來是想將此文件做為一個(gè)模板以?
供以??
后使用。??
???
???
??第五步:??
???
??加入本工程文件需要的最后一個(gè),VxdWarps.clb,?這個(gè)文件是DDK的LIB目錄中.?
??
???
??第六步:??
???
??所需的四個(gè)文件已經(jīng)全部加入完畢,它們是:??
???
??vxdstub.obj??
???
??minivxd.c??
???
??minivxd.def??
???
??vxdwarps.clb??
???
???
??在進(jìn)行make之前請(qǐng)檢查一下文件路徑,?在?Include?中一定要包含?DDK?目錄中的?
INC3??
?
2?目錄.??
???
??確認(rèn)無誤后可以按?F7?鍵進(jìn)行?Make?了。??
???
???
??結(jié)果會(huì)在?DEBUG?目錄或?Release?目錄?(依賴于工程文件的設(shè)置)?生成?
MiniVxd.vxd??
文件。??
???
???
??至此,一個(gè)小小的Vxd文件生成完畢,?可以在程序中用下面的代碼與本VxD進(jìn)行通?
訊.??
???
???
???
??BYTE?buffer[1024];??
???
??DeviceIoControl(hVxd,?1,?NULL,?NULL,?buffer,?1024,?NULL,?0);??
???
???
??結(jié)果,當(dāng)前的中斷向量表就會(huì)出現(xiàn)在?buffer?數(shù)組中。??
???
??本文不再提供完整的測試程序,需要的話請(qǐng)與作者聯(lián)系??
???
??5.小結(jié)??
???
???
??本文用一個(gè)簡單的示例介紹了如何在?Windows?95?下編寫可動(dòng)態(tài)安裝的?VxD,?這?
種方??
法及用這種方法??
???
??編寫的VxD在Windows?98?下同樣適用。然而,在?Windows?NT?不能采用這種方法?
??
???
???
???
???
*****************************?
**??
*******************************************??
???
??標(biāo)?題:?VxD世界——虛擬的Windows世界??
???
???
??從事Windows系統(tǒng)編程的讀者一定聽說過VxD──這個(gè)在Windows(注:指Windows?
?3.1??
/95/98,??
???
??非Windows?NT)的世界里無所不能的超級(jí)武器。迄今為止,越來越多的人有了深?
入了??
解Windows的愿望,??
???
??這也使得VxD技術(shù)愈來愈受到重視。VxD,意即Virtual?Something?Driver,這里?
的x就??
是指Something。比如??
???
??說鍵盤驅(qū)動(dòng)程序VKD、鼠標(biāo)驅(qū)動(dòng)程序VMD等。在許多人的腦海中,只有硬件開發(fā)者?
才會(huì)??
用到VxD,其實(shí)不??
???
??然,對(duì)于軟件開發(fā)來說,VxD也是無所不能的。在Windows3.1下這點(diǎn)還不明顯,?
而在W??
indows95中,隨著??
???
??線程與局部化概念的引入,想控制系統(tǒng)的全部資源變得愈來愈困難。舉個(gè)簡單的?
例子??
,由于32位的Windows??
???
??應(yīng)用程序擁有獨(dú)立的4GB線性地址空間,在Windows?3.1下常用的Windows應(yīng)用程?
序之間??
通信及共享變量的??
???
??方法不再完全適用了,想做些“出格”的事,比如說截獲別的應(yīng)用程序的消息,?
變得??
愈發(fā)困難了。就在您一??
???
??愁莫展的時(shí)候,采用VxD技術(shù)或許會(huì)令您“豁然開朗”──既然操作系統(tǒng)能控制?
全部資??
源,那么與操作系統(tǒng)??
???
??享有同樣最高權(quán)限的VxD(或者干脆說作為操作系統(tǒng)一部分的VxD)也一定能夠幫?
助您??
完成“出格行為”。??
???
??為什么VxD有如此神通?最根本的原因,是由于VxD運(yùn)行在系統(tǒng)的Ring?0級(jí),而用?
SDK(??
或現(xiàn)在大家熟知的??
???
??VC++、BC++、Borl?and?C++?Builder、VB、Delphi)開發(fā)出的應(yīng)用程序運(yùn)?
行在??
Ring?3級(jí)。在80x86??
???
??保護(hù)模式下,運(yùn)行在Ring?0級(jí)的VxD擁有系統(tǒng)最高權(quán)限(操作系統(tǒng)也運(yùn)行在?
Ring?0級(jí))??
。??
???
??要想真正掌握VxD技術(shù),您必須:??
???
???對(duì)80x86的保護(hù)模式有清楚的認(rèn)識(shí);??
???
???深入理解Windows的運(yùn)行機(jī)制;??
???
?
???熟悉VxD本身的運(yùn)行機(jī)制。??
???
??對(duì)于保護(hù)模式,目前國內(nèi)市面上有一些參考書籍,希望您能硬著頭皮看幾遍。雖?
說?不??
能使人茅塞頓開,卻也??
???
??對(duì)保護(hù)模式能有個(gè)比較清楚的認(rèn)識(shí)。??
???
???
??讓我們先來認(rèn)識(shí)一下Windows本身吧。??
???
???
??虛擬的Windows世界??
???
???
??運(yùn)行在Windows95下的幾種應(yīng)用程序:DOS應(yīng)用程序、Win16應(yīng)用程序、Win32應(yīng)用?
程序??
。其中DOS?應(yīng)用程??
???
??序大多運(yùn)行在字符模式,而Win16/Win32?應(yīng)用程序卻是運(yùn)行在圖形模式下的。為?
了使??
這幾種運(yùn)作方式大相??
???
??徑庭的應(yīng)用程序能“和平共處”,Windows采用了虛擬機(jī)(Virtual?machine)的?
方式??
。每個(gè)DOS應(yīng)用程序??
???
??運(yùn)行在一個(gè)獨(dú)立的DOS?VM中,使得這個(gè)愣頭青似的DOS應(yīng)用程序感到自己控制著?
所有的??
資源,它可以肆意??
???
??地在它認(rèn)為的全屏上涂涂改改,在它以為自己獨(dú)占的硬盤上讀出寫入(微軟在設(shè)?
計(jì)DO??
S時(shí)怎么也想不到PC機(jī)??
???
??硬件的發(fā)展如此迅速)。而所有的Windows應(yīng)用程序,不管是16位的,還是32位?
的,都??
運(yùn)行在同一個(gè)System??
???
???VM中。這是由于Windows?應(yīng)用程序守規(guī)矩得多,熟悉Windows編程的讀者一定對(duì)?
句柄??
(Handle)這個(gè)概念??
???
??有非常深刻的印象。Windows應(yīng)用程序的一舉一動(dòng)都是通過各種各樣的句柄(?
HWND、H??
DC、HANDLE、??
???
??HMOUDLE等)來實(shí)現(xiàn)的,正是通過句柄這個(gè)中介,使得系統(tǒng)有機(jī)會(huì)在同一個(gè)?
System?VM??
中協(xié)調(diào)多個(gè)Windows??
???
???應(yīng)用程序。不信嗎?好,讓我們做個(gè)實(shí)驗(yàn)(我假定您已經(jīng)安裝了Softice?for??
Win95??
),啟動(dòng)Windows95,啟動(dòng)??
???
??結(jié)束之后,不要運(yùn)行任何DOS應(yīng)用程序,按下Control+D激活Softice(在有的?
Softic??
e的缺省安裝中,激活??
???
??Softice的熱鍵是Alt+D),然后敲入指令:??
???
??:vm??
???
???
??VM?Handle?Status?High?Addr?VM?ID?Client?Regs??
???
??C39200E8?00001862?C3800000?00000001?C3449F70??
???
???
??從Softice的輸出可以看到這時(shí)只有一個(gè)VM,它的ID是1。??
???
???
??按Control+D返回Windows桌面,這時(shí),再運(yùn)行幾個(gè)Windows應(yīng)用程序,不管是?
16位的??
,還是32位的。重復(fù)??
???
??剛才的操作,按下Control+D激活Softice,敲入指令VM。我們看到Softice輸出?
的結(jié)??
果是一樣的。也就是說盡??
???
??管有多個(gè)Windows應(yīng)用程序在運(yùn)行,可是系統(tǒng)中只存在一個(gè)VM,這個(gè)VM就是?
System?VM??
。??
???
???
??按Control+D返回Windows桌面,這時(shí),從“開始選單”中運(yùn)行“MS-DOS方式”?
,按??
下Control+D激活??
???
??Softice,然后敲入指令:??
???
??:vm??
???
???
??VM?Handle?Status?High?Addr?VM?ID?Client?Regs??
???
??C8D200E8?00000802?C8C00000?00000002?C0F5FF70??
???
??C39200E8?00005A62?C3800000?00000001?C0F06F70??
???
???
??從Softice的輸出可以看到這時(shí)系統(tǒng)中存在兩個(gè)VM,其中一個(gè)就是我們剛才看到?
的??
???
??System?VM(VM?ID=1),另外,又多了一個(gè)ID=2的VM,這個(gè)VM就是DOS?VM,??
???
??也就是說剛才的那個(gè)“MS-DOS方式”就是運(yùn)行在這個(gè)DOS?VM中的。??
???
???
??按Control+D返回Windows桌面,從“開始選單”中再運(yùn)行幾個(gè)“MS-DOS方式”?
??
???
??,按下Control+D激活Softice,敲入VM指令,你會(huì)發(fā)現(xiàn)VM增多了,其數(shù)量等于?
所??
???
??有的“MS-DOS方式”的數(shù)目加1。??
???
???
??現(xiàn)在您信了吧??所有的DOS應(yīng)用程序都是運(yùn)行在各自的DOS?VM中,而所有的??
???
??Windows?應(yīng)用程序都運(yùn)行在同一個(gè)System?VM中。這是非常重要的概念。??
???
???
???
???
???
******************************************?
**??
***************************??
???
??VxD世界——Windows的保護(hù)模式??
???
???
??一般來說,80x86(80386及其以后的各代CPU)可以在三種模式下運(yùn)轉(zhuǎn):實(shí)模式?
,??
???
??保護(hù)模式,V86模式。實(shí)模式就是古老的MS-DOS的運(yùn)行環(huán)境。Win95只利用了兩?
??
???
??種模式:保護(hù)模式和V86模式。??
???
???
??為什么要進(jìn)入保護(hù)模式??
???
??保護(hù)模式有許多優(yōu)越性。其中最最直接的好處就是:你的程序可以利用更多的內(nèi)?
存了??
!??
???
???
??不要以為這是什么大不了的問題,我相信每一個(gè)曾在MS-DOS下寫程序的人都有?
一??
???
??個(gè)苦惱:怎樣在程序中開個(gè)足夠大的數(shù)組?動(dòng)不動(dòng)就會(huì)堆棧溢出,許多事都不能?
做??
???
??了。不要怨Turbo?C、MS?Fortran、Turbo?Pascal,它們也是心有余而力不足。?
這些??
???
???
??煩惱都源自“你的程序是運(yùn)行在實(shí)模式下的”。運(yùn)行在實(shí)模式下的16位程序最多?
只??
???
??能存取1M的內(nèi)存。你也許會(huì)問:我的機(jī)器上不是有64M內(nèi)存嗎?是啊,如果說你?
是??
???
??在MS-DOS下運(yùn)行程序(或者說CPU運(yùn)轉(zhuǎn)在實(shí)模式下),那你只利用了1M內(nèi)存,??
?
???
??其余的內(nèi)存都“下崗”了,在這種情況下,你的386/486/586/PⅡ只相當(dāng)于一個(gè)?
跑得??
???
???
??快的8086。??
???
???
??但是保護(hù)模式給了我們一個(gè)驚喜。理論上,在保護(hù)模式下,CPU可以尋址4096M(?
??
???
??即4GB)內(nèi)存。這就是說,只需把你的程序編譯成32位的可執(zhí)行程序(當(dāng)然得借?
助??
???
??32位編譯器),你就可以在程序中充分利用內(nèi)存了,這樣做的直接結(jié)果是:你可?
以??
???
??不用再為堆棧溢出或開不出5000×5000的數(shù)組而吃不下飯了。??
???
???
??正是4GB內(nèi)存存取的實(shí)現(xiàn),使得操作系統(tǒng)有了更加智能化的物質(zhì)基礎(chǔ),多任務(wù)的?
實(shí)??
???
??現(xiàn)才可以提到日程上來考慮了。??
???
???
??再深入一些??
???
???
??從硬件結(jié)構(gòu)上說,386由三個(gè)寄存器CR0、CR1、CR2控制著CPU的運(yùn)轉(zhuǎn)。比如說??
???
??,CR0的第0位就是用來判斷當(dāng)前CPU是工作在保護(hù)模式還是實(shí)模式下。學(xué)過??
???
??8088/8086匯編語言的人一定熟悉AX、BX、CX、DX、SI、DI、SP、BP這些16位??
???
??的寄存器,在80386中,這些寄存器被擴(kuò)展到了32位,即EAX、EBX、ECX、EDX??
???
??、ESI、EDI、ESP、EBP,如果CPU是運(yùn)轉(zhuǎn)在實(shí)模式下,那你只能利用這些32位寄?
??
???
??存器的前16位,而后面的16位就浪費(fèi)了。??
???
???
??段的概念是我們理解保護(hù)模式的關(guān)鍵所在。在實(shí)模式下,段寄存器中存放著16位?
的??
???
??段地址,這時(shí),段地址是參與尋址的:把段地址左移4位,加上偏移地址,就是?
20位??
???
???
??的物理地址了。在保護(hù)模式下,段寄存器中存放著16位的段選擇器(Segment??
???
??Selector),這個(gè)值是不直接參與尋址的,而只是一個(gè)指向段描述表(?
Segment??
???
??Descriptor?Table)的索引。段描述表(Segment?Descriptor?Table)中存放著?
段描??
???
???
??述符(Segment?Descriptor)。段描述符中有關(guān)于段的描述,比如:段在內(nèi)存中?
的??
???
??位置、段的大小、段的類型(是數(shù)據(jù)段還是代碼段)等等。??
???
???
??當(dāng)CPU運(yùn)行在保護(hù)模式下時(shí),內(nèi)存中往往有至少三張段描述表:全局描述表(??
???
??Global?Descriptor?Table,簡稱GDT)、局部描述表(Local?Descriptor,簡稱?
LDT)??
???
???
??、中斷描述表(Interrupt?Descriptor?Table,簡稱IDT)。說到這里,我想提?
醒讀者??
???
???
??注意:記住GDT、LDT、IDT這三個(gè)詞的含義,我們?cè)诤竺鏁?huì)經(jīng)常用到。??
???
???
??段描述表不可能超過64K(為什么?如果回答不上來,那就再看看前面的講解)?
,??
???
??每個(gè)段描述符(也就是段描述表中的一項(xiàng))都是8byte長,所以說,每個(gè)段描述?
表最??
???
???
??多只能包含8192個(gè)段描述符。??
???
???
??在今后的“走進(jìn)VxD世界”中,我們將對(duì)段描述表、段描述符以及分頁機(jī)制作進(jìn)?
一??
???
??步的講解。??
???
???
???
???
*************************?
**??
***************************??
???
??VxD世界——關(guān)于“描述表”??
???
???
??前面我們提到了在保護(hù)模式下,內(nèi)存中往往至少有三張表:GDT,LDT,IDT。聰?
明??
???
??的你可能要問:這幾張表都在內(nèi)存的什么地方呢???
???
???
??圖1?幾個(gè)重要的寄存器的示意圖??
???
???
??這三張表的位置是由三個(gè)寄存器記錄的。這三個(gè)寄存器分別是:GDTR,LDTR,??
?
???
??IDTR。我們還要補(bǔ)充講解一個(gè)寄存器,那就是TR(Task?Register),這個(gè)寄存?
器??
???
??與保護(hù)模式的任務(wù)管理有關(guān)。在386中,這幾個(gè)寄存器如圖1所示。??
???
???
??我們可以看到GDTR和IDTR都分別包含32位的物理地址和16位的權(quán)限級(jí)別,總共48?
??
???
??位。GDTR和IDTR中的32位地址是線性地址,不是段:偏移(Seg:Offset)的組合?
??
???
??形式,它表明了段開始的地方,如果說系統(tǒng)還沒有啟動(dòng)內(nèi)存分頁管理機(jī)制的話,?
那??
???
??這個(gè)線性地址就是物理地址,可是一旦系統(tǒng)啟動(dòng)了內(nèi)存分頁管理機(jī)制,GDTR和??
?
???
??IDTR中的32位線性地址就不再指向物理地址了。??
???
???
??CPU保留了GDT中的第一個(gè)描述符,任何試圖通過GDT中的第一個(gè)描述符來訪問內(nèi)?
??
???
??存的操作都是非法的(還記得Win95下那可怕的藍(lán)屏嗎?)。如果指向GDT的段選?
??
???
??擇器的Index域?yàn)?的話,那就指向空的段選擇器。段選擇器的示意如圖2:??
???
???
??TI:Talbe?Indicator??
???
??RPL:Requestor?Privilege?Level??
???
???
??圖2?段選擇器??
???
???
??這就是說,在保護(hù)模式下,far?NULL指針是非法的。而在實(shí)模式下,NULL指針卻?
是有??
意義的。??
???
???
??在內(nèi)存中(當(dāng)然是指CPU工作在保護(hù)模式下啦),GDT和IDT都只有一份,也就是?
??
???
??說,它們是全局的,任何一個(gè)任務(wù)改變了這兩張表,都會(huì)對(duì)別的任務(wù)產(chǎn)生影響。?
??
???
???
??下面我們談?wù)処DT、IDT中的每一項(xiàng),也就是每一個(gè)描述符,都定義了256個(gè)中斷?
中??
???
??的一個(gè)。還記得實(shí)模式下MS-DOS環(huán)境中的中斷向量表吧?在保護(hù)模式下,中斷?
描??
???
??述表IDT代替了中斷向量表。雖說中斷描述表可以容納8192個(gè)中斷描述符,可是?
??
???
??CPU能利用的只有處于前面的256個(gè)。所以中斷描述表的長度限制應(yīng)該是7FFh(23?
??
???
??×28-1)。??
???
???
??T=0:Interrupt?gate描述符??
???
??1:Trap?gate描述符??
???
???
??圖3?Trap/Interrupt?gate描述符??
???
???
??其實(shí)中斷描述表(IDT)中可以有兩種描述符:Interrupt?gate描述符、Trap??
gate描??
???
???
??述符。圖3顯示了Trap/Interrupt?gate描述符的結(jié)構(gòu)。這里提到了gate這個(gè)詞,?
一般??
???
???
??譯作“門”。?“中斷門”形像地直接表示了中斷調(diào)用的過程:中斷調(diào)用就像經(jīng)?
過一??
???
???
??扇門一樣,這個(gè)門就是中斷描述符,因?yàn)橹袛嗝枋龇杏蠨PL等權(quán)限盤查的標(biāo)志?
,??
???
??所以要想通過這扇門調(diào)用相應(yīng)的中斷服務(wù)程序是需要一定的資格的。??
???
???
??Trap和Interrupt?gate非常相似,一般來說Trap?gate是用來捕獲系統(tǒng)異常,而?
??
???
??Interrupt?gate用來響應(yīng)中斷。在具體的實(shí)現(xiàn)上,只有一點(diǎn)不同:Interrupt??
gate會(huì)??
將??
???
??IF置為0,這樣可以屏蔽硬件中斷。但是Trap?gate不會(huì)改變IF的值。??
???
???
??寄存器LDTR中存有LDT的位置。與GDT不同的是,內(nèi)存中可以有多份LDT。每一個(gè)?
??
???
??任務(wù)都可以有自己的LDT。從圖1中我們可以看到,LDTR不包含“地址?/?權(quán)限”?
位??
???
??。LDTR中所包含的是一個(gè)段選擇器。這個(gè)段選擇器指向GDT中的一項(xiàng),但不是普?
??
???
??通的一項(xiàng),這一項(xiàng)是指向某一LDT的描述符。你可能馬上意識(shí)到,GDT中可以包含?
??
???
??指向不同LDT的描述符,不錯(cuò),正是這樣的。在Windows保護(hù)模式下,每一個(gè)MS-?
??
???
??DOS應(yīng)用程序都有自己的LDT,而所有的Windows應(yīng)用程序都共享一份LDT。是不??
?
???
??是想起些什么來了?對(duì)了,這與Windows中VM(虛擬機(jī))的概念多少類似!??
???
???
???
???
???
**********************************
**??
***************************??
???
??VxD世界——分頁機(jī)制??
???
???
??關(guān)于分頁機(jī)制??
???
???
??在這種機(jī)制下,內(nèi)存被劃分為固定長度的“頁面”。在保護(hù)模式下,“頁面”是?
受??
???
??到保護(hù)的,并可以被“虛擬”(說穿了,“虛擬”的東西就是說,本來沒有的,?
而??
???
??應(yīng)用程序卻誤以為有。比如說,你只有64MB內(nèi)存,而你的程序卻傻乎乎地認(rèn)為它?
可??
???
??以有4GB的內(nèi)存用,這就是“虛擬”)。??
???
???
??還記得前面講過的保護(hù)模式下“段”的概念嗎?在保護(hù)模式下,段的長度是可以?
變??
???
??化的,而這里,“頁面”的大小是不能變的,雖然它倆都受到保護(hù)模式的“保護(hù)?
”??
???
??和“虛擬”。那么“頁面”的大小是多少呢?答案是4KB。??
???
???
??假如現(xiàn)在有個(gè)32位的線性地址,我們來看一下怎么由這個(gè)線性地址獲得物理地址?
。??
???
???
??圖1?線性地址通過頁面映射為物理地址??
???
???
??請(qǐng)記住圖1表示內(nèi)容,因?yàn)樗鼘?shí)在是太重要了。圖中的CR3是指寄存器CR3的值。?
如??
???
??果你裝了Softice?for?Win95,那就按下Ctrl+D激活Softice,然后敲指令:??
???
???
??CPU;這時(shí)會(huì)看到CR3的值。??
???
???
??線性地址轉(zhuǎn)換為物理地址的例子??
???
???
??假設(shè)現(xiàn)有線性地址8000DD88h,我們來看一下它到底指向何處物理地址。性線地?
址??
???
??8000DD88h應(yīng)作如下解析:??
???
???
??800?0D?D88??
???
??Page?Table?Index?Page?Index?Page?Offset??
???
??(頁面表索引)?(頁面索引)?(頁面偏移地址)??
???
???
??現(xiàn)在我們需要知道頁面表目錄的起始地址。于是我們查看寄存器CR3。假設(shè)寄存?
器??
???
??CR3=891000h,那么891000h?+?200h?4?=?891800h(想一想為什么要?4,答案?
??
???
??在文章后注釋[1]處),現(xiàn)在我們要查看一下線性地址891800h處的值,在?
Softice中??
???
???
??,敲如下的指令:??
???
???
??:?d?891800??
???
???
??假設(shè)得到的是493227h,這個(gè)值與0FFFFF000h作“與”運(yùn)算,就得到了我們要找?
??
???
??的Page?Table的起始物理地址493000h,那么493000h?+?4?0Dh?=?49302Ch(想?
??
???
??一想為什么要?4,見注釋[2]),然后我們要知道物理地址49302Ch處的值,但?
是在??
???
???
??Softice中,我們無法直接獲得存放在物理地址處的值,只能通過其對(duì)應(yīng)的線性?
地址??
???
???
??來查看。在Softice中,敲如下指令:??
???
???
??:?phys?49302C??
???
???
??假設(shè)得到的是線性地址89302Ch(有時(shí)你會(huì)得到兩個(gè)不同的值,我們?nèi)〉谝粋€(gè)值?
。??
???
??想一想為什么會(huì)有兩個(gè)不同的值?答案在注釋[3]),現(xiàn)在我們查看一下線性地?
址??
???
??89302Ch處的值,這也是物理地址49302Ch處的值。在Softice中,敲如下指令:?
??
???
???
??:?d?89302C??
???
???
??假設(shè)得到的是3F5000h,這就是我們要找的Page(頁面)的物理地址。然后,??
???
??3F5000h?+?0D88h?=?3F5D88h,這就是線性地址8000DD88h對(duì)應(yīng)的物理地址。我?
??
???
??們想在Softice中查看物理地址3F5D88h處的值,那就得找到其相應(yīng)的線性地址。?
在??
???
??Softice中,敲如下指令:??
???
???
??:?phys?3F5D88??
???
???
??假設(shè)我們得到線性地址7F5D88h,讓我們看一下這個(gè)線性地址7F5D88h處的值。在?
??
???
??softice中,敲如下指令:??
???
???
??:?d?7F5D88??
???
???
??讓我們記下結(jié)果,然后再看一下線性地址8000DD88h處的值。??
???
???
??:?d?8000DD88??
???
???
??你會(huì)發(fā)現(xiàn)線性地址7F5D88h與線性地址8000DD88h所指向的值是完全一樣的。??
???
???
??一般來說,為了提高地址轉(zhuǎn)換的效率,在CPU里都會(huì)有一個(gè)頁面轉(zhuǎn)換緩沖區(qū)(TLB?
??
???
??),里面存放著最近頁面轉(zhuǎn)換的信息。??
???
???
??MMU(Memory?Management?Unit)??
???
???
??從386開始,CPU都帶有一個(gè)內(nèi)存管理單元(Memory?Management?Unit,簡稱??
???
??MMU)。??
???
???
??MMU負(fù)責(zé)提供的功能:虛擬內(nèi)存、重組段、進(jìn)程分隔、頁面保護(hù)、地址轉(zhuǎn)換。??
???
???
??我們?cè)谏厦娴睦又兴M(jìn)行的線性地址到物理地址的轉(zhuǎn)換就是由MMU來完成的。?
??
???
???
??模式轉(zhuǎn)換??
???
???
??我們簡單提一下保護(hù)模式與實(shí)模式之間的切換過程,有個(gè)概念就可以了。??
???
???
??由實(shí)模式切換到保護(hù)模式:檢測一下當(dāng)前CPU是否有能力運(yùn)行于保護(hù)模式下;檢?
測??
???
??保護(hù)模式環(huán)境(DPMI或VCPI);建立IDT;建立GDT;禁止中斷,包括NMI;加載?
??
???
??GDTR;設(shè)置IDTR;設(shè)置CR0的bit?0;清空指令隊(duì)列;加載段寄存器;允許中斷。?
??
???
???
??由保護(hù)模式切換到實(shí)模式:禁止中斷,包括NMI;禁止頁面轉(zhuǎn)換;設(shè)置數(shù)據(jù)段寄?
存??
???
??器的值為準(zhǔn)實(shí)模式下的選擇器;重置CR0的bit?0;清空指令隊(duì)列;設(shè)置?
IDTR=0000??
???
??:03FF;允許中斷。??
???
???
??[1]因?yàn)樵赑age?Table?Directory中,每一個(gè)表項(xiàng)占4個(gè)字節(jié)。??
???
???
??[2]因?yàn)樵赑age?Idex?Table中,每一個(gè)表項(xiàng)占4個(gè)字節(jié)。??
???
???
??[3]因?yàn)榫€性地址到物理地址的映射關(guān)系不是一對(duì)一的,這就是說同一處物理地?
址,??
???
???
??可能有多處線性地址指向它。??
???
???
???
???
???
???
********************************?
**??
***************************??
???
??VxD世界——Win95?的線性地址分配??
???
???
??圖1是一張描述Win95線性地址空間的圖。下面我們對(duì)這張圖加以詳細(xì)說明。??
???
???
??圖1?Windows?95線性地址分配圖??
???
???
??0~4MB:??
???
???
??這部分在圖上標(biāo)的是DOS內(nèi)存區(qū),其實(shí)這是不確切的。我們知道16位的DOS應(yīng)用程?
??
???
??序只能存取0~1MB的內(nèi)存空間,那為什么還要把1MB~4MB的3MB內(nèi)存也算作??
???
??DOS內(nèi)存區(qū)呢?答案就在我們前面講過的分頁機(jī)制中。我們?cè)贉亓?xí)一下:一個(gè)頁?
面??
???
??(Page)是4kB,一個(gè)頁面表(Page?Talbe)有1024個(gè)頁面,一個(gè)頁面表目錄(?
??
???
??Page?Table?Directory)有1024個(gè)頁面表。那么一個(gè)頁面表目錄項(xiàng)就可以映射?
1024×??
???
???
??4k=4MB的線性地址。其實(shí)DOS只能利用到0MB~1MB的內(nèi)存空間,那1MB~4MB??
???
??的地址空間留給誰了呢?關(guān)于這個(gè)問題,筆者曾經(jīng)問過Karen?Hazzah、Walter??
?
???
??Oney和Geoff?Chappell,他們的回答是:這一部分是空的。Win95為了圖省事,?
就??
???
??把1MB~4MB的線性地址空間也當(dāng)作DOS內(nèi)存區(qū),這樣Win95在DOS?VM之間切換??
???
??時(shí),就可以頁面表目錄項(xiàng)(Page?Table?Directory?Entry)為單位來進(jìn)行。這樣?
雖說??
???
???
??浪費(fèi)了3MB的地址,卻換來了DOS?VM切換的高效率。??
???
???
??那圖1中標(biāo)出的①又是指的什么呢?呵呵,Win95有趣得很,為了使系統(tǒng)、Win16?
應(yīng)??
???
??用程序能與DOS應(yīng)用程序互相協(xié)作,于是在0~1MB之間,其實(shí)是緊挨著1MB的下??
?
???
??面,放了一個(gè)Win16全局堆(其實(shí)是Win16全局堆很小的一部分)。說到這里,筆?
者??
???
??想起了一個(gè)深受大家喜愛的DOS下的編輯器Quick?Edit?4.0,這個(gè)編輯器有一個(gè)?
非常??
???
???
??有趣的功能:能與Windows共享剪貼板。當(dāng)時(shí)我們猜想它一定用到了未公開的?
DPMI??
???
??調(diào)用,現(xiàn)在從圖1來看,肯定是①部分的Win16全局堆幫了它的忙啦。??
???
???
??同時(shí)請(qǐng)注意圖1中還有一個(gè)②,這部分我們稱作Win16全局堆的高端部分。為什么?
要??
???
??在這里安置一個(gè)Win16的全局堆?它是用來作什么的呢???
???
???
??這個(gè)問題的答案是:為了高效率地切換DOS?VM。??
???
???
??每一個(gè)DOS?VM在大于3GB的地址空間都有一個(gè)備份,Win95在DOS?VM之間進(jìn)行??
???
??切換時(shí),只是簡單切換一下頁面表目錄的第一項(xiàng)就可以了。所以說,如果一個(gè)?
VxD??
???
??想訪問某個(gè)DOS?VM,沒有必要一定要等到該DOS?VM成為當(dāng)前VM才能訪問,它可??
?
???
??以直接去②訪問那個(gè)DOS?VM的備份。這個(gè)DOS?VM備份的地址我們稱作High-??
???
??linear?address。??
???
???
??后面的文章中,我們將詳細(xì)講到如何在VxD中訪問DOS?VM。??
???
???
???
???
???
***********************?
**??
***************************??
???
??VxD世界——Win95?內(nèi)存揭秘??
???
???
??上期“走進(jìn)VxD世界”中我們談到了Win95中0~4MB線性內(nèi)存空間分配情況。下面?
??
???
??我們接著講余下的4MB~4GB線性內(nèi)存空間的分配。??
???
???
??4MB~2GB??
???
??Win32應(yīng)用程序的代碼、數(shù)據(jù)和資源都存放在這段內(nèi)存中了,這部分內(nèi)存,對(duì)于?
每??
???
??個(gè)Win32應(yīng)用程序來說都是私有的。這里是最能體現(xiàn)保護(hù)模式分頁機(jī)制作用的地?
方??
???
??。兩個(gè)Win32應(yīng)用程序,對(duì)相同的線性地址(4MB~2GB范圍內(nèi))進(jìn)行讀寫,實(shí)際?
??
???
??上,它們是在對(duì)不同的物理地址進(jìn)行讀寫。讓我們算一下,這段內(nèi)存對(duì)應(yīng)多少個(gè)?
??
???
??Page?Directory?Entry。我們知道一個(gè)Page?Directory?Entry對(duì)應(yīng)4MB線性內(nèi)存?
,那??
???
???
??4MB~2GB的內(nèi)存就對(duì)應(yīng)于1024?/?2?-?1?=?511個(gè)Page?Directory?Entry。也就?
是說??
???
???
??Win95通過操縱這511個(gè)Page?Directory?Entry實(shí)現(xiàn)了Win32應(yīng)用程序“獨(dú)立”的?
線性??
???
???
??地址空間。打個(gè)比方來說吧,現(xiàn)在有511個(gè)抽屜,上帝告訴A說:這些抽屜里都是?
金??
???
??幣,同時(shí)告訴B說:這些抽屜里都是銀幣。并規(guī)定只有上帝能打開抽屜。其實(shí)抽?
屜里??
???
???
??可能只有一枚銅板,也可能什么都沒有。這時(shí),A想看看某個(gè)抽屜里到底是不是?
金幣??
???
???
??,于是上帝就背地里臨時(shí)往那個(gè)抽屜中放一個(gè)金幣,然后打開抽屜讓A看,于是?
A就??
???
??信了。這個(gè)伎倆同樣作用于B,B也相信了那511個(gè)抽屜里都是他想要的銀幣。保?
護(hù)??
???
??模式下的操作系統(tǒng)(這里當(dāng)然指Win95)就相當(dāng)于上帝,而被騙的A和B就相當(dāng)于?
運(yùn)??
???
??行于保護(hù)模式下的Win32應(yīng)用程序。那只操縱抽屜的上帝之手就是分頁機(jī)制。??
???
???
??2GB~3GB??
???
??這部分內(nèi)存空間我們稱之為“應(yīng)用程序共享內(nèi)存區(qū)”,這里存放著Ring?3級(jí)應(yīng)用?
程??
???
??序需要共享的數(shù)據(jù)和代碼。其中包括Win95系統(tǒng)DLL(如User32.dll,Kernel32.?
dll等??
???
???
??)、內(nèi)存映射文件、Win16應(yīng)用程序以及DPMI調(diào)用分配的內(nèi)存。??
???
???
??通過把要共享的數(shù)據(jù)映射到2GB~3GB之間的線性內(nèi)存空間,可以實(shí)現(xiàn)Win32應(yīng)用?
??
???
??程序間的數(shù)據(jù)共享。??
???
???
??Win16應(yīng)用程序是需要共享線性地址空間的,這是Windows?3.1的歷史遺留問題。?
為??
???
??了使以前運(yùn)行于Windows?3.1的Win16應(yīng)用程序能在Win95下有同樣的運(yùn)行效果,?
于??
???
??是Microsoft決定把Win16應(yīng)用程序放到這段共享內(nèi)存區(qū)來運(yùn)行。應(yīng)該說這是比較?
合??
???
??理的決策:既省時(shí)省力,又保證了對(duì)上一代產(chǎn)品的良好兼容性。??
???
???
??再從分頁機(jī)制的角度上來思考一下這段“共享內(nèi)存區(qū)”是如何實(shí)現(xiàn)的。2GB~3GB?
??
???
??的線性空間對(duì)應(yīng)著256個(gè)Page?Directory?Entry。無論誰在運(yùn)行,Win95都不會(huì)改?
變這??
???
???
??256個(gè)Page?Directory?Entry,也就是說2GB~3GB的線性地址空間對(duì)應(yīng)的物理地?
址??
???
??是一樣的。這樣,Win95什么也不用做就實(shí)現(xiàn)了2GB~3GB線性地址空間的內(nèi)存共?
??
???
??享。??
???
???
??3GB~4GB??
???
??這部分內(nèi)存空間稱為“系統(tǒng)內(nèi)存區(qū)”。只有Ring?0級(jí)的VMM和VxD可以訪問這部分?
??
???
??內(nèi)存空間。這部分內(nèi)存也是共享的。雖說Ring?3的應(yīng)用程序無法直接共享這部分?
內(nèi)??
???
??存空間(也就是說SDK中講述的方法無法做到),但是我們還是稱之為共享內(nèi)存?
區(qū)??
???
??,至少從分頁機(jī)制的角度上說,對(duì)應(yīng)于這部分內(nèi)存的Page?Directory?Entry是不?
變的??
???
???
??。其實(shí)Win32應(yīng)用程序還是有辦法訪問這部分內(nèi)存空間的。一般作法是,在VxD中?
分??
???
??配一塊內(nèi)存,然后把指向那塊內(nèi)存的32位地址指針傳給Win32應(yīng)用程序,這樣就?
可??
???
??以在Win32應(yīng)用程序中直接訪問那塊內(nèi)存了。前面我們?cè)谥v0~4MB內(nèi)存空間時(shí),?
提??
???
??到High-linear?address,即DOS?VM備份的地方,就在3GB~4GB內(nèi)存空間中。??
?
???
???
??對(duì)于Windows應(yīng)用程序開發(fā)者來說,實(shí)現(xiàn)內(nèi)存共享有時(shí)是非常重要的。對(duì)于VxD開?
??
???
??發(fā)者來說,還應(yīng)注意,對(duì)于經(jīng)常需要存取的共享內(nèi)存頁面,必須調(diào)用VMM的??
???
??_LinPageLock服務(wù)進(jìn)行鎖定,否則會(huì)出現(xiàn)Out-Of-Context?Memory?Reference?
。??
???
???
???
???
********************?
**??
***************************??
???
??VxD世界——硬件虛擬與虛擬設(shè)備驅(qū)動(dòng)程序??
???
???
??·硬件虛擬·??
???
???
?
??回憶一下,在實(shí)模式DOS下,實(shí)模式的MS-DOS應(yīng)用程序調(diào)用runtime?library中?
的??
???
??fgets或—kbhit函數(shù),這些函數(shù)就會(huì)直接通過軟中斷int?21h調(diào)用MS-DOS服務(wù)(?
MS??
???
??-DOS服務(wù)會(huì)最終通過調(diào)用軟中斷int?16h調(diào)用BIOS服務(wù)),或者通過軟中斷?
int?16h??
???
???
??調(diào)用BIOS服務(wù)。BIOS通過IN?/?OUT指令來直接操縱鍵盤或中斷控制器。??
???
???
??我們通過下面這張圖來理解一下什么是硬件虛擬的實(shí)現(xiàn)(見圖1)。??
???
???
??兩個(gè)不同的MS-DOS應(yīng)用程序可能要同時(shí)訪問鍵盤,它們都感到自己在直接操縱?
著??
???
??硬件。其實(shí)從全局看,這兩個(gè)MS-DOS應(yīng)用程序?qū)︽I盤的訪問被VKD串行化了。??
?
???
??這兩上MS-DOS應(yīng)用程序其實(shí)是在操縱“虛擬的硬件”。??
???
???
??硬件虛擬的一個(gè)很關(guān)鍵的基礎(chǔ)是:80386芯片的“port?trapping”功能,這使得?
VKD??
???
???
??可以捕獲ring?3應(yīng)用程序?qū)︽I盤的訪問。我們想起前面講保護(hù)模式的內(nèi)存管理時(shí)?
,提??
???
???
??到“虛擬內(nèi)存”的概念,其時(shí)“虛擬內(nèi)存”的實(shí)現(xiàn)也是因?yàn)?0386芯片具有“??
???
??paging?trap?”功能。??
???
???
??·虛擬設(shè)備驅(qū)動(dòng)程序·??
???
???
??Windows系統(tǒng)中,是VMM和VxDs實(shí)現(xiàn)了硬件虛擬(VMM本身就是一些VxD的集合??
???
??)。在Win95中,有兩種VxD:static?VxD(靜態(tài)加載的VxD)和dynamic?VxD(動(dòng)?
??
???
??態(tài)加載的VxD)。在Windows?3.1中,只有一種VxD:static?VxD。Static?VxD的?
加載??
???
???
??需要把VxD放在SYSTEM.INI或注冊(cè)表中。比如說,你寫了一個(gè)文件名為Fool.VxD?
的??
???
??static?VxD,那么你可以在SYSTEM.INI中的如下位置加上一句:??
???
???
??……??
???
??[386Enh]??
???
??device=Fool.VxD??
???
??……??
???
???
??或是在注冊(cè)表的如下位置加入如下一項(xiàng):??
???
??\HKEY—LOCAL—MACHINE\System\CurrentControlSet\services\VxD\Fool.VxD??
?
???
???
??這樣Win95在啟動(dòng)時(shí)就會(huì)自動(dòng)加載Fool.VxD。??
???
??相對(duì)于Windows?3.1而言,Win95又增加了dynamic?VxD(動(dòng)態(tài)加載的VxD)。在??
?
???
??Win95中,主要操縱dynamic?VxD的是configuration?Manager和Input/Output??
???
??Supervisor這兩個(gè)功能模塊(這兩個(gè)模塊自己卻是static?VxD)。??
???
?
???
??圖1?鍵盤的虛擬??
???
???
??VKD:Virtual?keyboard?device?VPICD:Virtual?PIC?device??
???
???
???
???
???
*****************************??
***************************??
???
??VxD世界——VxD文件格式??
???
???
?
??我們知道,MS-DOS下可執(zhí)行文件.EXE是MZ格式,也就是說.EXE文件的前兩個(gè)??
???
??字節(jié)是字符串“MZ”。而Windows?3.1的.EXE是NE(New?Executable)格式,??
???
??Win95和WinNT的.EXE是PE(Portable?Executable)格式,VxD則是LE(Linear??
?
???
??Executable)格式。但是有一點(diǎn)需要注意,在NE、PE和LE的頭部,總嵌有一小段?
??
???
??DOS程序,它的作用是:當(dāng)你在DOS下運(yùn)行這幾種.EXE文件時(shí),它會(huì)提示你“This?
??
???
??program?cannot?be?run?in?DOS?mode”。??
???
???
??DEBUG?TEST.VXD??
???
???
??LE文件格式最早出自O(shè)S/2?2.0。這種格式的文件可以同時(shí)包含16位和32位代碼,?
這??
???
??正是VxD需要的,因?yàn)閂xD在加載的初始化階段,需要進(jìn)行一些實(shí)模式的操作,這?
??
???
??需要16位代碼,而VxD的主要運(yùn)行階段是在32位環(huán)境中,這又需要32位代碼,所?
以??
???
??LE文件格式正好適合于VxD。??
???
???
??VxD不僅有16位和32位兩種代碼,而且,它把數(shù)據(jù)段和代碼段攪和在一起,只是?
通??
???
??過段前的標(biāo)識(shí)來表明該段在運(yùn)行時(shí)的特性。VxD之所以這樣,是因?yàn)閂xD所用的?
Flat??
???
??mode的代碼和Data?selector有同樣的基本地址和限制,這樣當(dāng)VxD想訪問數(shù)據(jù)或?
代??
???
??碼時(shí),用哪個(gè)段寄存器都可以。VxD中常用的Segment?Class見表1。??
???
???
??在VxD中,LCODE、PCODE和PDATA段包含了主要的數(shù)據(jù)和代碼。LCODE段所包??
???
??含的數(shù)據(jù)和代碼必須總在內(nèi)存中,我們?cè)赩xD中處理硬件中斷的代碼和相關(guān)數(shù)據(jù)?
必??
???
??須位于LCODE段中,否則,在處理硬件中斷時(shí)就會(huì)出現(xiàn)可怕的Page?fault。??
???
???
??ICODE段包含的是VxD初始化時(shí)要完成的工作,當(dāng)VxD完成初始后,ICODE段中的??
?
???
??代碼和數(shù)據(jù)將被VMM拋棄。??
???
???
??RCODE中包含的是16位代碼和數(shù)據(jù),用作實(shí)模式初始化階段。??
???
???
??SCODE中包含Static?Code和Data,一般來說,SCODE對(duì)于動(dòng)態(tài)加載的VxD尤其有??
?
???
??用。試想一下,如果可動(dòng)態(tài)加載的VxD包含了一個(gè)回調(diào)函數(shù),當(dāng)你卸載這個(gè)VxD后?
??
???
??,又需要這個(gè)回調(diào)函數(shù)繼續(xù)發(fā)生作用,那你就得把這個(gè)回調(diào)函數(shù)放到SCODE中。?
再??
???
??者,如果你需要知道某個(gè)動(dòng)態(tài)加載的VxD被加、卸載了幾次,那可以在SCODE中放?
??
???
??個(gè)記數(shù)器,每次該VxD被加載時(shí)都把該記數(shù)器加一。??
???
???
??由于VxD的文件格式比較特殊,所以你必須使用可以產(chǎn)生LE格式的鏈接器(?
Linker??
???
??)。如果你要開發(fā)Windows?3.1的VxD,那得用Windows?3.1?DDK帶的鏈接器。但?
是??
???
??如果開發(fā)Win95的VxD,那用MSVC?2.0及其以后版本的鏈接器就可以了。有一點(diǎn)需?
??
???
??要注意,MSVC?4.1的鏈接器由于存在一些小BUG,不能用于生成VxD。??
???
???
??表1??
???
??Segment?Class?描?述??
???
??LCODE?Page-locked?code?and?data??
???
??PCODE?Pageable?code??
???
??PDATA?Pageable?data??
???
??ICODE?Initialization-only?code?and?data??
???
??SCODE?Static?code?and?data??
???
??RCODE?Real-mode?initialization??
???
???
???
???
???
???
**********************************??
***************************??
???
??VxD世界——VxD開發(fā)的利器SoftIce/VToolsD??
???
???
??SoftIce的安裝??
???
???
??對(duì)于從事Windows系統(tǒng)開發(fā)的人來說,SoftIce是必不可少的利器。目前SoftIce?
的最??
???
???
??新版本是3.24,有Win?95的版本,也有Win?NT的版本。SoftIce?3.24?for?Win??
95可以??
???
???
?
??從國內(nèi)的一些FTP站下載。??
???
???
??在SoftIce的安裝過程中,有一步是很重要的,那就是對(duì)顯卡的測試。新版本的?
??
???
??SoftIce提供對(duì)更多種顯卡的支持。如果說顯卡不被SoftIce支持,那就意味著??
?
???
??SoftIce將無法正常工作。??
???
???
??在安裝過程中,如果Test通不過,那就試著選一下Universal?Video?Driver或者?
Use??
???
???
??monochrome?card/monitor。如果還通不過的話,那就在Display?Adapter??
Selection??
???
???
??列表框中選擇Stand?VGA再試。如果還不行的話,那就試著去下載一份new??
SoftIce??
???
??video?driver(在國內(nèi)的FTP站上也可以找到),如果運(yùn)氣好的話,你的顯卡會(huì)?
被??
???
??SoftIce支持。??
???
???
??安裝過程結(jié)束后,重新啟動(dòng)計(jì)算機(jī),按下Ctrl+D進(jìn)入SoftIce,如果SoftIce能?
正常??
???
???
??工作,那我們的安裝就成功了。你可以敲入help來看一下SoftIce的簡要幫助,?
或者??
???
???
??,按下Ctrl+D返回Windows桌面。??
???
???
??VToolsD的安裝??
???
???
??在VToolsD出世之前,VxD的開發(fā)者面對(duì)DDK浩如煙海的古怪的asm代碼,能忍受下?
??
???
??來的人不多。VToolsD就是把幸福帶給VxD開發(fā)者的天使。就憑這一點(diǎn),VToolsD?
就??
???
??令VxD開發(fā)者趨之若鶩。VToolsD是Vireo公司的作品,目前國內(nèi)的FTP站上有??
???
??VToolsD?2.03?for?Win95下載(如果運(yùn)氣好的話,還可以找到2.04、2.05b)。?
從國??
???
???
??內(nèi)FTP站下載的VToolsD在安裝時(shí)有一些需要注意的地方。??
???
???
??首先,在安裝過程中會(huì)遇到對(duì)話框,詢問你是否需要MASM6.11c。VToolsD并不包?
??
???
??含MASM?6.11c,但是,可以從DDK?for?Win95中找到MASM?6.11c。當(dāng)你的程序中?
??
???
??需要嵌入?yún)R編代碼時(shí),MASM?6.11c就不可缺少了(如果你只用C語言開發(fā)VxD,那?
??
???
??就用不著了)。??
???
???
??圖1所示是對(duì)調(diào)試器的選擇,請(qǐng)選擇SoftIce。??
???
???
??圖1?調(diào)制器的選擇??
???
???
??在SoftIce的路徑設(shè)置對(duì)話筐中,請(qǐng)選擇SoftIce的Util16子目錄。??
???
???
??再者,在安裝過程中,圖2所示的兩個(gè)選項(xiàng)是不能選的,否則,安裝過程將無法?
正常結(jié)??
束。??
???
???
??圖2?不要選擇的兩個(gè)選項(xiàng)??
???
???
??在VToolsD安裝完成之后,重新啟動(dòng)計(jì)算機(jī),然后,進(jìn)到VToolsD安裝目錄下的??
?
???
??examples\c\simple\下,敲如下的命令:??
???
???
??nmake-f?simple.mak??
???
???
??如果一切正常的話,將生成simple.vxd。??
???
???
??如果不行的話,那就在DOS提示符下敲set命令,檢查一下環(huán)境變量的設(shè)置。下面?
是??
???
??我的系統(tǒng)中相應(yīng)環(huán)境變量的設(shè)置,你需要根據(jù)自己系統(tǒng)的實(shí)際情況調(diào)整一下路徑?
設(shè)置??
:??
???
???
??VTOOLSD=E:\VTD95??
???
??PATH=?%PAH%;C:\MSDEV\BIN;?E:\VTD95\BIN??
???
??INCLUDE=C:\MSDEV\INCLUDE;?E:\VTD95\INCLUDE??
???
??LIB=C:\MSDEV\LIB;E:\VTD95\LIB??
???
???
??把這些環(huán)境變量的設(shè)置加到autoexec.bat中去,以使其每次開機(jī)都自動(dòng)設(shè)置。??
?
???
???
???
???
???
*********************************?
**??
*******************************??
???
??VxD世界——用VToolsD開發(fā)一個(gè)簡單的VxD??
???
???
??這一次,我們講一下如何用VToolsD開發(fā)一個(gè)最簡單的VxD,以及用SoftIce進(jìn)行?
源程序??
級(jí)的調(diào)試。??
???
???
??VToolsD的使用??
???
???
??在VtoolsD中,有一個(gè)最重要的VxD開發(fā)工具:QuickVxD。QuickVxD可以為我們自?
??
???
??動(dòng)生成VxD源程序框架,而且QuickVxD提供了許多VxD的特性選項(xiàng),例如可以選擇?
??
???
??要生成的VxD是動(dòng)態(tài)加載的或是靜態(tài)加載的,要使用的編程語言是C還是C++等?
等。??
???
???
???
??我們要利用QuickVxD自動(dòng)生成的是一個(gè)可動(dòng)態(tài)加載的、基于C語言的VxD框架。之?
??
???
??所以選用動(dòng)態(tài)加載的VxD,是為了調(diào)試VxD的方便。每次修改代碼,重新編譯連接?
??
???
??之后,要使VxD重新生效,如果采用靜態(tài)加載的VxD,那就不得不重新啟動(dòng)電腦,?
??
???
??而若采用了動(dòng)態(tài)加載的VxD,那只須使用VToolsD帶的另一個(gè)開發(fā)工具VxDLoad就?
??
???
??可以卸出或重新加載內(nèi)存中的VxD。之所以采用C語言而不是C++,是因?yàn)槠浜?
潔??
???
??易懂。請(qǐng)按照如圖1~圖4進(jìn)行選擇。按下Generate?Now按鈕,我們就獲得了動(dòng)態(tài)?
加??
???
??載的、基于C語言的VxD的源程序。??
???
???
??如果您是按照上一篇文章中講過的VToolsD的編譯環(huán)境設(shè)置系統(tǒng),那我們就可以?
編??
???
??譯剛才生成的這個(gè)最簡單的VxD了。在DOS提示符下輸入指令:??
???
???
??nmake?-f?myfirst.mak??
???
???
??看一下當(dāng)前目錄下是否生成了myfirst.vxd,如果有,那我們下面準(zhǔn)備對(duì)這個(gè)?
VxD進(jìn)行??
???
???
??源程序級(jí)的調(diào)試。如果沒有,那么很可能是您的編譯環(huán)境沒有正確配置,請(qǐng)找來?
上??
???
??一篇文章好好讀讀。??
???
???
??用VxDLoad加載myfirst.vxd(見圖5)??
???
???
??按下Load按鈕,會(huì)出現(xiàn)VxD?load?successfully消息框。??
???
???
??用SoftIce調(diào)試VxD??
???
???
??對(duì)于SoftIce選單作如下選擇:??
???
??(1)File→Open?Module選擇我們剛才生成的myfirst.vxd。??
???
??(2)Module→Translate,如果Symbol?Loader提示無法加載一些asm文件,那就?
跳過??
所有的asm文件。??
???
??(3)Module→Load。??
???
???
??按下Ctrl+D,進(jìn)入SoftIce運(yùn)行環(huán)境中(如果您還沒有按照上一篇文章中安裝??
?
???
??SoftIce的話,那就無法再進(jìn)行下面的測試)。輸入如下指令:??
???
??:file????
???
???
??myfirst.c??
???
??:file?myfirst.c??
???
???
??這時(shí),在SoftIce中,您將會(huì)看到myfirst.c的源程序。??
???
???
??圖1選項(xiàng)頁面之一??
???
??圖2選項(xiàng)頁面之二??
???
??圖3選項(xiàng)頁面之三??
???
??圖4可以生成VxD源程序了??
???
??圖5用VxD?Load加載myfirst.vxd??
???
???
???
???
???
*********************************
**??
*******************************??
???
??VxD世界——VxD的結(jié)構(gòu)??
???
???
??在上一次“走進(jìn)VxD”世界中,我們用VToolsD生成了一個(gè)最簡單的可以動(dòng)態(tài)加載?
的??
???
??VxD——MYFIST程序。我們以這個(gè)例子為基礎(chǔ),不斷地豐富其功能,并以此講解?
一些V??
xD的基本技術(shù)。??
???
??下面是MYFIRST主要組成之一:MYFIRST.C。??
???
???
??//?MYFIRST.c?-?main?module?for?VxD?MYFIRST??
???
??#define?DEVICE_MAIN??
???
??#include?"myfirst.h"??
???
??#undef?DEVICE_MAIN??
???
??Declare_Virtual_Device(MYFIRST)??
???
??VOID_cdecl?V86_Api_Handler(VMHANDLE?hVM,?PCLIENT_STRUCT?pcrs)?{?}??
???
??VOID?_cdecl?PM_Api_Handler(VMHANDLE?hVM,?PCLIENT_STRUCT?pcrs)?{?}??
???
???
??DefineControlHandler(SYS_DYNAMIC_DEVICE_INIT,??
???
??OnSysDynamicDeviceInit);??
???
???
??DefineControlHandler(SYS_DYNAMIC_DEVICE_EXIT,??
???
??OnSysDynamicDeviceExit);??
???
???
??DefineControlHandler(W32_DEVICEIOCONTROL,?OnW32Deviceiocontrol);??
???
?
???
??BOOL?_cdecl?ControlDispatcher(??
???
???DWORD?dwControlMessage,??
???
???DWORD?EBX,?DWORD?EDX,??
???
???DWORD?ESI,?DWORD?EDI,?DWORD?ECX)??
???
???{?START_CONTROL_DISPATCH??
???
????ON_SYS_DYNAMIC_DEVICE_INIT(OnSysDynamicDeviceInit);??
???
????ON_SYS_DYNAMIC_DEVICE_EXIT(OnSysDynamicDeviceExit);??
???
????ON_W32_DEVICEIOCONTROL(OnW32Deviceiocontrol);??
???
???END_CONTROL_DISPATCH??
???
???return?TRUE;}??
???
???
??BOOL?OnSysDynamicDeviceInit()??
???
??{?return?TRUE;?}??
???
??BOOL?OnSysDynamicDeviceExit()??
???
??{?return?TRUE;?}??
???
???
??DWORD?OnW32Deviceiocontrol(PIOCTLPARAMS?p)??
???
??{?return?0;?}??
???
???
??記得在前面的文章中提到過,VxD可以與應(yīng)用程序?qū)崿F(xiàn)相互通信。我們?cè)谟??
???
??QuickVxD生成這個(gè)例子時(shí),又選中了支持動(dòng)態(tài)加載和Real/V86?Mode?API及??
???
??Protected?Mode?API等選項(xiàng)。上面程序中,函數(shù)V86_Api_Handler用來實(shí)現(xiàn)VxD與?
??
???
??16位的DOS應(yīng)用程序通信,函數(shù)PM_Api_Handler用來實(shí)現(xiàn)VxD與16位的Windows??
???
??應(yīng)用程序或DOS-Extended(DPMI)應(yīng)用程序通信,函數(shù)OnW32Deviceiocontrol用?
來??
???
??實(shí)現(xiàn)VxD與32位的Windows應(yīng)用程序通信。函數(shù)OnSysDynamicDeviceInit和??
???
??OnSysDynamicDeviceExit自然是用來控制VxD動(dòng)態(tài)加載和卸載啦。??
???
???
??上面的代碼中有兩個(gè)宏DefineControlHandler和ControlDispatcher,用來把這?
些函數(shù)??
???
???
??與VxD的消息機(jī)制聯(lián)系起來。好像我們搞清楚了,不,再仔細(xì)看一下,宏??
???
??DefineControlHandler和ControlDispatcher都只是定義了三個(gè)函數(shù)??
???
??OnW32Deviceiocontrol、OnSysDynamicDeviceInit和OnSysDynamicDeviceExit的?
消??
???
??息映射關(guān)系。我們很自然地想到,函數(shù)V86_Api_Handler和PM_Api_Handler呢??
???
??,為什么能肯定VxD一定用這兩個(gè)函數(shù)與16位應(yīng)用程序通信呢???
???
???
??讓我們?cè)赩ToolsD的include子目錄下找一找,我們會(huì)發(fā)現(xiàn)VToolsC.h中有這兩個(gè)?
函數(shù)??
???
???
??的定義。下面的代碼摘自VToolsC.h。??
???
???
??#define?Declare_Virtual_Device_Ex(VName,?RefData)?\??
???
???
??extern?_C_?void?_cdecl?V86_Api_Handler(VMHANDLE?hVM,?PCLIENT_??
???
??STRUCT?pRegs);?\??
???
??extern?_C_?void?_cdecl?PM_Api_Handler(VMHANDLE?hVM,?PCLIENT_??
???
??STRUCT?pRegs);?\??
???
??extern?_C_?void?(?VXD_SERVICE_TABLE[])();?\??
???
??_EXC_?DDB?The_DDB?=?{?0,?DDK_VERSION,?VName##_DeviceID,?VName??
???
??##_Major,?\??
???
??VName##_Minor,?0,?{′?′,′?′,′?′,′?′,′?′,′?′,′?′,′?′},?
?\??
???
??VName##_Init_Order,?(DWORD)?LocalControlDispatcher,?\??
???
??(DWORD)?LocalV86handler,?\??
???
??(DWORD)?LocalPMhandler,?0,?0,?RefData,?(DWORD)?VXD_SERVICE_TABLE,?\??
???
??0,?\??
???
??0,?\??
???
??_SIG_}?;??
???
???
??//?This?is?the?standard?macro?for?declaring?a?DDB,?using?all?default??
value??
s.??
???
???
??#define?Declare_Virtual_Device(VName)?Declare_Virtual_Device_??
???
??Ex(VName,0)??
???
???
??從上面的代碼中,我們可以看到,函數(shù)V86_Api_Handler和PM_Api_Handler被??
???
??宏Declare_Virtual_Device聲明已在DDB(Device?Descriptor?Block)中,自然?
不??
???
??用再在MYFIRST.C中進(jìn)行消息映射了。??
???
???
???
???
???
???
****************************************?
**??
*******************************??
???
??VxD世界__VxD的設(shè)備描述塊與VxD?API??
???
???
??VxD設(shè)備描述塊??
???
???
??用匯編語言描述MYFIRST.VxD的設(shè)備描述塊(DDB?Device?Descriptor?Block)如下?
(??
???
??其實(shí),如果是用DDK來開發(fā)VxD,那我們?cè)诿總€(gè)VxD的源程序中都會(huì)見到這些代碼?
??
???
??,只是VToolsD替我們封裝了這些費(fèi)解的東西):??
???
???
??Declare_Virtual_Device?MYFIRST,1,0,MYFIRST_Control,MYFIRST_??
?
???
??Device_ID,MYFIRST_Init_Order,MYFIRST_V86_API_Handler,??
???
??MYFIRST_PM_API_Handler??
???
???
??對(duì)于DDB的8個(gè)入口來說,只有前面4個(gè)是必須的,后面4個(gè)的缺省值為0,如果我?
們??
???
??的MYFIRST.VxD不輸出V86?API,那么上面的代碼應(yīng)這樣寫:??
???
???
??Declare_Virtual_Device?MYFIRST,1,0,MYFIRST_Control,MYFIRST_??
???
??Device_ID,MYFIRST_Init_Order,,MYFIRST_PM_API_Handler??
???
???
??一般來說,MYFIRST_Init_Order是可以設(shè)為缺省值0的,因?yàn)槲覀円话悴恍枰?
??
???
??殊的初始化順序。??
???
???
??你一定會(huì)奇怪MYFIRST_Control是怎么回事。讀一下下面的代碼,大概就明白了?
。??
???
???
??BeginProc?MYFIRST_Control??
???
???
??Begin_Control_Dispatch?MYFIRST_Control??
???
???
??Control_Dispatch?Sys_Dynamic_Device_Init,?OnSysDynamicDeviceInit??
???
???
??Control_Dispatch?Sys_Dynamic_Device_Exit,?OnSysDynamicDeviceExit??
???
???
??.........??
???
???
??End_Control_Dispatch?MYFIRST_Control??
???
???
??EndProc?MYFIRST_Control??
???
???
??對(duì)比一下VToolsD為我們生成的C程序:??
???
???
??BOOL?_cdecl?ControlDispatcher(??
???
???DWORD?dwControlMessage,??
???
???DWORD?EBX,DWORD?EDX,??
???
???DWORD?ESI,?DWORD?EDI,??
???
???DWORD?ECX)??
???
???{?START_CONTROL_DISPATCH??
???
???ON_SYS_DYNAMIC_DEVICE_INIT(OnSysDynamicDeviceInit);??
???
???ON_SYS_DYNAMIC_DEVICE_EXIT(OnSysDynamicDeviceExit);??
???
???END_CONTROL_DISPATCH??
???
???return?TRUE;}??
???
???
??Windows是基于消息機(jī)制的操作系統(tǒng),這一點(diǎn)在VxD中也體現(xiàn)了出來。MYFIRST_??
?
???
??Control就是接收Windows消息的入口點(diǎn)。Windows發(fā)給MYFIRST_Control的消息??
?
???
??與發(fā)給Windows應(yīng)用程序的消息不完全一樣,前者包含了一些系統(tǒng)信息。MYFIRST?
??
???
??_Control在收到消息后,調(diào)用相應(yīng)的控制過程。??
???
???
??VxD?API??
???
???
??在前面的文章中,我們說MYFIRST.VxD將支持Real/V86?Mode?API及Protected??
???
??Mode?API,這使得MYFIRST.VxD可以與V86應(yīng)用程序或Win16應(yīng)用程序通信。??
???
??MYFIRST.VxD輸出的V86?API和PM?API就是??
???
???
??VOID?_cdecl?V86_Api_Handler(VMHANDLE?hVM,?PCLIENT_STRUCT?pcrs);??
???
???
??VOID?_cdecl?PM_Api_Handler(VMHANDLE?hVM,?PCLIENT_STRUCT?pcrs);??
???
???
??一個(gè)問題很快就擺在我們面前:如何在我們的應(yīng)用程序中調(diào)用到這兩個(gè)API???
???
???
??讀一下這段代碼:??
???
???
??DWORD?NEAR?PASCAL?GetAPIEntry(WORD?VxD_ID)??
???
??{DWORD?Entry_Point;??
???
???
??_asm{??
???
???mov?AX,?1684h??
???
???mov?BX,?WORD?PTR?SS:?[VxD_ID]??
???
???sub?DI,?DI??
???
???mov?ES,?DI??
???
???int?2Fh??
???
???mov?WORD?PTR?SS:?[Entry_Point][0],?DI??
???
???mov?WORD?PTR?SS:?[Entry_Point][2],?ES??
???
????????????}?return?Entry_Point;}??
???
???
??這段代碼可以用在MS_DOS應(yīng)用程序或是Win16應(yīng)用程序中,函數(shù)GetAPIEntry將分?
??
???
??別返回V86_Api_Handler的地址或PM_Api_Handler的地址。??
???
???
??等一下,函數(shù)GetAPIEntry的入口參數(shù)VxD_ID是怎么回事?嗯,問得好。如果你?
一??
???
??直在讀我的文章,那你會(huì)發(fā)現(xiàn)我們?cè)谇懊嬗幸粋€(gè)失誤:在用QuickVxD生成??
???
??MYFIRST.VxD的源程序時(shí),把MYFIRST.VxD的DeviceID置成了UNDEFINED_??
???
??DEVICE_ID。通過在VToolsD\include\Vmm.h中查找,可以看到:??
???
???
??#define?UNDEFINED_DEVICE_ID?0x00000??
???
???
??也就是說所有UNDEFINED_DEVICE_ID的VxD的DeviceID都置成了0。如果我們??
???
??向函數(shù)GetAPIEntry傳遞MYFIRST_DeviceID,那我們很可能無法獲得??
???
??MYFIRST.VxD中的API的地址,因?yàn)槲覀兊腄eviceID不是惟一的,Windows無法在?
??
???
??眾多DeviceID為0的VxD中找到我們的MYFIRST.VxD。那怎么辦呢???
???
???
??解決方案有兩個(gè):??
???
???
??方案一:??
???
??再用QuickVxD重新生成MYFIRST.VxD的源程序。記著在Device?Parameters頁中填?
??
???
??寫Device?ID為某個(gè)值,這個(gè)值盡量大一些,因?yàn)楸容^小的DeviceID都讓?
Microsoft或??
???
???
??是別的硬件開發(fā)商注冊(cè)了(注冊(cè)是需要銀子的),為了保證不與系統(tǒng)中現(xiàn)存的?
VxD??
???
??的DeviceID發(fā)生沖突,我們只好把DeviceID設(shè)得大一些,比如說0xAAAA。??
???
???
??方案二:??
???
??編輯一下MYFIRST.H,把MYFIRST_DeviceID改了,改過之后的MYFIRST.h如下??
???
??:??
???
???
??#include?〈vtoolsc.h〉??
???
??#define?MYFIRST_Major?1??
???
??#define?MYFIRST_Minor?0??
???
??#define?MYFIRST_DeviceID?0xAAAA??
???
??#define?MYFIRST_Init_Order?UNDEFINED_INIT_ORDER??
???
???
??好了,我們已經(jīng)準(zhǔn)備好與我們的MYFIRST.VxD通信了。??
評(píng)論