Windows 98核心介紹

Windows 98核心介紹


▓概觀
記得在自己電腦裝上Windows 95,逛書局時我看到了Andrew Schulman
所寫的Unauthorized Windows 95 Developer’s Resource Kit,當時對它裡面的內容感到非常的驚訝,也非常欽佩作者對Windows作業系統了解之深,這一陣子自己在Windows 98上面的學習過程,也有著一點心得希望可以藉此機會跟大家分享一下,相信在經過這些對Windows 98系統的介紹之後,可以有這個機會讓讀者們更認識它一點,當然,Windows 98Windows NT或未來將會出現的Windows 2000(架構由NT而來)在核心寫作上相差非常多,因此,這次文章所提的一些對Windows 98運作方式,並不適用於Windows NT或將會出現的Windows 2000
首先,Wnidows 98的架構來說如圖(),我把它給分為四個層次,首先是
最下層VMM32.VXD及其它所Load進來的VXD,這部份是位於系統Ring 0的位置,其中最重要的當然是VMM32.VXD這個檔案了,它可說是整個Windows 98(95)最重要的一個Ring 0的核心,不過它並不是一個單純的VXD,….或是應該這樣說,它個檔案格式並不是一個VXD(LE格式),不過它卻是多個VXD的合體(稍後將會對這部份作個說明),再來便是第二層,這一層中的krnl386.exe與最下面一層VMM32.VXD是屬於DPMI Client  DPMI Server的關係,首先VMM32.VXD會在啟動的過程中去執行krnl386.exe(不過 krnl386.exeNE格式的執行檔,也就是說它是個16-bit的程式),Andrew Schulman也以command.comkrnl386.exe給置換掉,而產生了一個在v86 模式下的DOS,此法我在Windows 98中一樣可行,有趣的是如果你有執行WinICE的話,你將會得到一個沒有Windows界面的DOS V86操作環境下之WinICE,你可以在”C:\”的情況下以Ctrl+D進入WinICE,在圖()<Step 1>我以EXEHDR這個微軟的工具軟體來查看krnl386.exe,krnl386.exe在記憶體當中的模組名稱為Kernel,在圖()<Step 2>中我秀出了krnl386.exe的檔頭,以證明它是個NE格式的事實,最後在圖()<Step 3>我把krnl386.exe中的EXITKERNEL函式給部份反組譯出來,很明顯的krnl386.exe是個在V86模式下的16 bit程式,當然,同層的亦包括了Kernel32.dll(Windows System Programming SECRECTS<Matt Pietrek>第六章對VWIN32.vxd ,Kernel32.dll,krnl386.exe有非常不錯的說明),再上面一層便是我們使用者在Windows 98中所看到的Shell(system.iniShell = explorer.exe),這部份提供了我們每天所看到的工作列,開始功能表選單….等等友善的介面,當然,Andrew Schulman書中也以WinFile.exeExplorer.exe取代掉,換了一個Shell,Windows 98(95)所呈現出來的使用者介面便沒有原本的Explorer.exe這樣的便捷,連原本存在下方的工作列都不見了,有興趣的讀者也可以自行更改,在最上面一層便是Win 32應用程式所在的部份,在這部份的程式所要執行的許多呼叫都會透過下面各層次的通力合作才有可能完成,尤其是最後的兩層,更是Win32應用程式執行時不可缺少的

(一)

圖(二)
Driver所呼叫的VXD Service
Windows 98中對核心的系統呼叫是由20號中斷來實現的如下圖(三),在圖(三)<Step 1>我們可以看到
VMMCall _Allocate_Device_CB_Area, <<SIZE VwatchD_CB_STRUCT>, 0>
再經過DDK(Device Driver Kit)編譯後,我們把該行反組譯回來會看到以下的組合語言程式碼
6A 00 push 0
6A 04 push 4
CD 20 int 20h
A7 00 01 00 dd 000100A7
83 C4 08 add ESP,08
前兩個Push的動作是分別把函式_Allocate_Device_CB_Area引數由右而左推入堆疊,接下來的20號中斷便是在Windows 98(95)系統中用來呼叫VXD Service,20號中斷之後的000100A7 ,0001為提供該VXD ServiceDevice ID(可由DDKvmm.inc該檔取得Windows系統所提供之VXDDevice ID資料),00A7代表我們所呼叫的為該VXDService Table中第幾號的Service(可在各inc檔中找到相關資料),:Device ID 0001我們得知此服務由VMM所提供,因此在VMM.inc中我們找到的第00A7Service(0開始)_Allocate_Device_CB_Area,筆者在寫這篇文章時也製作了一個工具軟體,可以幫大家看看所使用的VXD呼叫了那些VXD Service,並附上原始碼,這隻程式我把許多的inc檔中的Device IDService名稱等資料放在裡面了,不過有一小部份沒有全部置入,但目前來說對各位應該是滿夠用了,如果讀者有其它需要的話可以自行加以擴充,其它有關VXD的資料可自行參閱DDK或寫作VXD的專業書籍,當然,如果手邊有Windows 95 System Programming Secrects這本書的讀者,也可以翻閱一下在第9章中Matt PietrekVXD的介紹
()<Step 2>為我以VTOOLD為開發工具,其中以下這行程式碼
return (IFSMgr_RegisterCFSD(Mount, IFSMGRVERSION, DeviceNames) != -1);
經過編譯的一個例子,而圖()<Step 3>為編譯後所產生的機械碼與經過反組譯後的組合語言碼,其中我要提醒的一點為這是該VXD未載入記憶體前所反組譯的結果,在圖()<Step 4>中我們便可以看到這段Code在載入記憶體後,相關資料的值便被載入器給填入了,其中
0028:C0148990 E8 C7 0A 00 00 call C014945C
這行會去呼叫圖()<Step 5>
0028:C014945C CD 20 int 20h
0028:C014945E 62 80 40 00 DD 00408062
而在查過VMM.inc後得知Device ID=0040IFSMgr,因此我們再去查IFSMgr.inc
便可以得知Service編號為62的函式名稱為IFSMgr_RegisterCFSD,Service編號的最高位元若被設為1(8062) ,則此VXD Service呼叫會被修補為VxDJmp的指令

圖(三)
VMM32.VXD?
()<Step 1>,我們可以看到其實VMM32.VXD是多個VXD的合體,它不但是一個DMPI Server,也提供了記憶體管理,強制多工的能力,Windows 98(95)系統中很重要也很常見的VMM這個VXD便是由它所提供
可是VMM32.vxd並不是一個標準的VXD格式,由圖() <Step 2>我把VMM32.VXD改名為VMM32.exe再透過Visual CDumpbin工具程式,以如下的指令執行
C:\>dumpbin vmm32.exe
所得到的訊息得知在微軟的工具檢測之下VMM32.VXD竟然是個DOS下的程式,這樣的結果倒是與它的檔名有點不一致,不過VMM32.VXD是在DOS下被啟動而進入保護模式載入Windows整個系統的,若以Borland C的所附的Tdump程式
c:\>tdump vmm32.exe
Turbo Dump Version 5.0.16.4 Copyright (c) 1988, 1998 Borland International
Display of File VMM32.EXE
Old Executable Header
DOS File Size E29B1h (928177. )
Load Image Size F800h ( 63488. )
Relocation Table entry count 0034h ( 52. )
Relocation Table address 0040h ( 64. )
Size of header record (in paragraphs) 0020h ( 32. )
Minimum Memory Requirement (in paragraphs) 1400h ( 5120. )
Maximum Memory Requirement (in paragraphs) FFFFh ( 65535. )
File load checksum 0000h ( 0. )
Overlay Number 0000h ( 0. )
Initial Stack Segment (SS:SP) 0F71:0400
Program Entry Point (CS:IP) 0000:1625
都可以證明VMM32.VXDDOS執行檔的MZ格式,而非VXDLE格式,若讀者們有興趣也可以利用以前DOS下用的反組譯工具來反組譯VMM32.VXD相信一定會有不少意外的驚喜,不過目前的VMM32.VXD如果用Andrew Schulman所寫的w3map程式來測試的話,並不會得到VMM32.VXD中所釋出的正確資料,有關這部份的問題我會在文章的結尾處把我觀察所得與各位做一個說明,最後,Unauthorized Windows 95 Developer’s Resource Kit 這本書中對VMM32.VXD有著非常精彩徹底的介紹很值得對Windows 9X系統有興趣的讀者一探究竟,Windows 98VMM32.VXD多出了一個名為NTKERNVXD,NTKERN包含在VMM32.VXD,而它正是Windows 98可以同時支援VXDWDM兩種Driver的重要關鍵

(四)
之前,我曾說過VMM32.VXD可以由過去DOS下的反組譯工具來處理,由圖(各位可以看到VMM32.VXD中部份反組譯的結果,首先圖()<Step 1>VMM32.VXD進入保護模式的一小段Code,當然,如果在VMM32.VXD之前已有其它程式先切入保護模式的話(:EMM386.exe),則會有一些協調的過程來讓VMM32.VXD可以順利取得保護模式的控制權,而圖()<Step 2>則是VMM32.VXD退出保護模式的一段Code,()<Step 3>是對圖()<Step 2>最後一行LIDT指令所會用到的IDTR 暫存器在Microsoft’s 80386/80486 Programming Guide中所提到的說明,如果各位曾經寫過切入保護模式程式的話,相信對圖()<Step 1>中切入保護模式的動作一定不感到陌生,如果讀者們需要這方面資料可話,也可以去網路上(像一些BBS站中有關程式設計板的精華區)找到許多有用的資料,筆者當年初次接觸到保護模式的程式設計時也是在網路上找到許多不錯的文章,在讀了這些資料後自己再親手去寫作驗證,透過這些過程相信各位一定可以對保護模式有初步的了解,在此我就不再多做說明了…^_^

圖(五)
Windows 98支援兩種格式的Driver
Windows 98 DDK中有不少有用的範例 可以供大家參考,在此我將針對WDM(Win32 Driver Model)的函式是如何在Windows 98中被實現來做個說明,希望可以對各位有所幫助,首先由圖()<Step 1>我們編譯一個WDMDriver,而這以下一小段程式碼
ntStatus = IoCreateDevice(DriverObject,
sizeof(DEVICE_EXTENSION),
&deviceNameUnicodeString,
FILE_DEVICE_UNKNOWN,
0,
FALSE,
DeviceObject);
則是我們所要觀察的對象,在圖()<Step 2>,是我把這段程式碼經過編譯後產生的執行檔反組譯後的結果
首先,Windows 98WDMDriver並不像原本VXD所用的LE檔案格式,WDMPE檔案格式,因此我們可以透過反組譯PE檔的工具軟體來把WDM Driver反組譯回來,接著我們看到這行
FF1578020100 CALL DWORD PTR [NTOSKRNL=>IoCreateDevice]
PE檔格式中,我們可以由Import Table得知這個PE檔案在執行時會呼叫那些檔案所提供的函式(當然,Win32的程式中,如果透過LoadLibrary..,動態的方式來載入的話,Import Table中並不會記錄),我們可以發現在Windows 98中編譯過的WDM Driver它在Import Table中是把IoCreateDevice這函式記錄了由NTOSKRNL.EXE來提供,可是在Windows 98中並沒有這樣一個實際的檔案存在,因此,在圖()<Step 1>我們可以看到在把這個Driver載入到記憶體後,我們發現
FF15380000FF CALL [FF000038]
FF000038是在Import Table,而該處則記錄IoCreateDevice函式在記憶體的位址,由圖()<Step 2>我們可以看到
0028:FF000038 DC 98 29 C0
C02998DC正是在Windows 98IoCreateDevice函式所在的記憶體位址,接著我們在()<Step 3>看到這個位址的內容,而這個記憶體位址正是在NTKERN這個VXD所在的記憶體位址中,由此,我們也可以驗證在Windows 98NTKERN這個VXD可用來替代NTOSKRNL.EXEWindows NT中提供對等函式的能力,以達到兩個OS可以共用同一種格式Driver的目的,199711 Microsoft System Journal的一篇文章“Surveying the New Win32 Driver Model for Windows 98 and Windows NT 5.0”中所提到的Unfortunately,drivers for standard Windows-based devices must fit into an older architecture that’s incompatible with this new kernel-mode support. ……….”,由此我們可以得知在Windows 98中對於標準的驅動裝置(如鍵盤,磁碟機等的驅動程式),將無法透過新架構的Driver來充份實現,而需透過以往VXD所直接使用的VXD Service
此外,在圖()<Step 1>我們以這一小段程式碼為例子
pPHist->timeStamp = KeQueryPerformanceCounter(NULL);
在圖()<Step 2>我們看到編譯後的結果,其中KeQueryPerformanceCounterImport Table中可以查得是由HAL.DLL(HAL.DLLNT所擁有的檔案)所提供的函式,但在圖()<Step 3>可以看到這段程式碼被置入記憶體後的結果,同樣的在圖()<Step 4>可以得知KeQueryPerformanceCounterWindows 98中所對應的處理函式記憶體位址,()<Step 5>為我們追進這個記憶體後發現此函式是存在於VTD這個VXD所在的記憶體空間(屬於VTD_Get_Date_And_Time 這個函式的記憶體空間),其實由這些例子我們可以了解到WDMDriver雖然是PE檔案格式,透過Import Table來得知所要使用的系統服務函式,不同於過去VXD透過20號中斷來取得VXD Service的方式,但是WDMWindows 98中所提供的服務仍是透過Windows 98中其它的VXD來完成這些任務,也因此,WDM中如果我們直接透過20號中斷來取得服務的話,雖然在Windows 98中可以順利的執行,但相對的由於在Windows NT中取得系統的服務並非是透過20號中斷,所以用這種方式所寫好WDM Driver將會不易享受到WDM可在Windows 98  Windows NT 5.0(或該說是Windows 2000)通用的便利性,如果日後,可以多Support更多相關的WDM函式,而這些函式可以在Windows 98中以其它的VXD來合力完成的話,相信WDM在寫作上的能力將會更為強大

()

()

()
▓檢示
之前我曾說過,我會提供一個用來檢示一個VXD使用了那些VXD Service的程式,這個程式寫作起來原理很簡單,比較花時間的部份是要從那些inc檔中整理這些Service的資料,如圖(),我分別展示了對幾種不同的檔案測試的結果,意外的是我發現在Windows 98所提供的wdmfs.sys中竟也透過20號中斷來執行IFSMgr_Ring0_FileIORing 0讀取磁碟,這樣的行為不是不能在Windows NT 5.0中使用了嗎?,Windows NT並不像Windows 98一樣是透過20號中斷來提供系統服務的(或許,這個Driver原本就不打算與Windows NT 5.0互相使用..^_^)
此外,wsock.vxd讀者們也可以藉由它所使用的函式來得知一些滿有用的資訊,而在圖()cdfs.vxd有用到Device ID41VCDFSDVXDService,但是我在那些*.inc檔中並沒有找到有關VCDFSD提供的Service的資料,因此也就沒能順利的把它們給包含在這隻程式之中,基本上,我把許多的Service資料都加到這程式之中了,如果有一些資料是讀者們所需要的,可是我沒能加入的話,讀者也可以由Source Code來加以擴充

(九)
▓後記
有一個部份我一直覺得是個遺憾,我把NTKERN這個VXD在記憶體中的Machine Code抄錄下來,Windows的目錄中找尋有那個執行檔是有相同的Machine Code,可是我沒有找到我所希望得到的結果,這是讓我有點懷疑的部份,我甚至懷疑VMM32.VXD是個被局部編碼過的檔案,使得我無法透過比對Machine Code的方式來找到我的答案,但我想我還需要一些更有力的資料來證明這一點….~_~
這次,為各位介紹了一些Windows 98的資訊,有關我所提到的一些資料,在能力範圍內可以證明的,我都把Trace的結果給列出來了,以驗證我所提到的資訊,如果讀者們看了文章後,有任何的問題,歡迎與我討論,非常謝謝各位