Windows NT保護子系統
▓初識
諸位Windows NT的玩家,應該對保護子系統這個名詞不漠生,剛開始接觸Windows NT時,對於它的架構也是充滿了好奇,曾在Windows NT上Trace Windows CE的模擬器,覺得這些能將不同環境下開發的程式整合在一起的技術滿有趣,透過這次的文章,我將對Windows NT的保護子系統做一個介紹,在Windows NT中保護子系統扮演了重要的角色,從登入系統到啟動各個應用程式,保護子系統都在幕後掌控大局,。
在此我先簡述一下Windows NT的開機流程,安裝Windows NT後,Boot磁區會被改寫,Partition的磁區並不會被動到。不過,Windows 9X會動到Partition的磁區,使用Linux Lilo的玩家,應該在重灌Windows 9X後,會遇到原來裝在硬碟Lilo所更改的Partition磁區被動過了。如下圖(一),是我硬碟Boot磁區的部份資料,在開機時,會由Boot磁區啟動NTLDR,我們可以看到,其中包括了如果Boot磁區未能順利找到NTLDR這個檔案時,所發出的警告訊息。
在Windows NT中,NTLDR除了負有提供多重開機的能力外,還肩負了把許多Windows NT系統檔案載入的重要使命。在NTLDR載入以後,同時也將系統由真實模式切入保護模式。如下圖(二),是我在NTLDR執行檔中所找到的一些滿有趣的訊息,像我們一開機時所看到的 ” NTDETECT V4.0 正在檢查硬體” 便是由NTLDR所秀出的。除此之外NTLDR也負責把NTDETECT.COM所偵測的資料傳給NTOSKRNL.EXE(此檔可說是NT真正的核心),並把NTOSKRNL.EXE 載入記憶體執行。在圖(三),是NTLDR執行檔中所包含的開機選單的訊息,看到這訊息被包在NTLDR執行檔中,就知道它是開機選單及流程最初的控制者了。
當然,NTLDR本身也提供了基本的檔案系統,可以在啟動NT的過程中,讀取FAT16 及 NTFS 格式的檔案系統,。在圖(四),便是Windows NT啟動的一個簡圖。
圖(一)
|
圖(二) | ||
|
圖(三) | ||
|
圖(四)
▓子系統?
提到保護子系統,首先,我要先介紹一下在Win32的PE檔案格式中所提供的一個欄位 “SUBSYSTEM”,如圖(五),是在VC的線上文件所記載有關SUBSYSTEM的資訊,
|
圖(五)
既然提到了SUBSYSTEM,我就舉幾個我們常見到的例子,如下圖(六),就是我在Windows NT中利用快速檢視(如果你有裝”快速檢視”的話,選擇檔案後,按下右鍵,就會在POPUP MENU中看到它了)來查看\WINNT\SYSTEM32\*.SYS的檔案,在NT中Device Driver檔案的副檔名為SYS,我們可以在Subsystem的欄位中看到”Image doesn’t require a subsystem”,同理。在圖(七),則是一個Win32 使用到GUI界面的應用程式在”快速檢視”下的結果。圖(八)為Win32 Console Mode的應用程式。
圖(六)
圖(七)
圖(八)
說到這兒,我想到在Inside NT Second Edition 中有一個Creating Process的流程圖,我也畫了一個簡圖如圖(九)。在第一部份,開啟EXE檔後,.會判斷這個檔案所屬的子系統,並開啟所選擇的物件。第二部份,產生Windows NT 的Executive Process Object,並產生所需的資料結構,及配置記憶體空間。第三部份,產生新的執行序及程式堆疊。第四部份,把新產生的行程通知所屬的子系統。第五部份,開始執行新產生的執行序。第六部份,執行新產生的行程。
其實,在這我只把部份的內容做一個說明,在Inside Windows NT Second Edition中對一個行程的啟始有滿不錯的說明。在此我就不再累述,這兩期的文章,這本書給了我不少Hint(如本篇文章的圖(九),(十),(十一)),也讓我可以省去不少尋找一些細節資料的時間,如果讀者對這方面有興趣的話,我相信那決對是一本不錯的好書。
|
圖(九)
如下圖(十),是NT中各子系統所使用的虛擬機器的執行檔名,我們可以發現像
(1)CMD.EXE:主要用於*.BAT,及我們一般常用的DOS Command(如:DIR..etc)。所以,如果我們把CMD.EXE改名的話,再透過檔案總管去執行AUTOEXEC.BAT便會得到如下的結果。讀者可能會懷疑,為何要透過檔案總管,而不啟動DOS BOX呢?那是因為在NT中的DOS BOX就是透過CMD.EXE來模擬的,因為我們把CMD.EXE改名了,所以原來的DOS BOX捷徑所指的檔案已不存在。其實,我覺得CMD.EXE的角色如同是以前DOS下的COMMAND.COM,扮演了COMMAND INTERPRETER 的角色。
|
(2)NTVDM.EXE:當我們在DOS BOX中啟動一個DOS的程式時,系統會透過NTVDM.EXE這個DOS的虛擬機器,來把這個DOS的程式放入記憶體中執行,如果我們把NTVDM.EXE改名後。再啟動DOS的應用程式便會產生如下的錯誤
|
由於DOS的應用程式與Win16的應用程式是使用同一個虛擬機器,
以在NTVDM.EXE改名的情況下,執行Win16的應用程式會得到如下的錯誤結果
以在NTVDM.EXE改名的情況下,執行Win16的應用程式會得到如下的錯誤結果
(3)Win 32的應用程式,是Windows NT系統在一啟動後首先提供的子系統,其它的保護子系統都是需要透過Win32子系統的協助才有可能完成所需的工作,筆者在此就不個別介紹POSIX及OS/2子系統了,在本文的稍後我會有一個相關的說明。
如圖(十一),裡面有一些關於子系統的重要檔案名稱,我們可以發現子系統常常都是一個EXE 檔與一個DLL檔,我並沒實地製作一個子系統的經驗,不過稍後,我會針對目前已存在的子系統做一個探索。
|
圖(十一)
▓Win32子系統
在Windows NT的登錄畫面出現以前,Win32子系統便被建立了,在Win32子系統初始化時,系統中只存在4個Process分別為
Process
|
PID
|
Pri
|
System
|
0x02
|
8
|
Smss
|
0x19
|
B
|
Csrss
|
0x21
|
D
|
Idle
|
0x00
|
0
|
既然,Win32是Windows NT所啟動的第一個子系統,那Win32子系統CSRSS.EXE執行檔,是如何完成的呢? 相信讀者應該還記得,Device Driver 是屬於Kernel Mode的程式,因此,在Driver的Subsystem欄位會顯示這個執行檔不需要子系統,那CSRSS.EXE呢?
如下圖(十二),我們可以發現CSRSS.EXE不同於一般的Win32程式,它並不需要一個子系統來維持它。有趣的是,在Import Table中我們看到CSRSRV.DLL這個Win32子系統的動態連結函式庫,同樣的,在它們Load到記憶體前,系統還沒有任何一個子系統形成,因此這個CSRSRV.DLL的Subsystem欄位也是顯示不需要子系統。
在圖(十三)中,我們可以在CSRSS.EXE的Import Table中看到CSRSRV.DLL所提供的CsrServerInitialization函式,這是CSRSS.EXE在初始化Win32環境的過程中所會呼叫的一個必備函式。
讀者可以觀察其它Win32的應用程式,會發現它們相關於子系統的一些有趣的事情。尤其,子系統往往都是一個EXE檔伴隨著DLL檔所建立起的一個架構,透過子系統的DLL檔,可以把許多環境所必需的基本函式給實作在子系統的DLL中。
圖(十四) –(十六)分別是CSRSRV.DLL的Subsystem資料,Import Table及Export Table,眼尖的讀找應該可以從圖(十六)的Export Table中看到這個CSRSRV.DLL提供了許多與Win32行程管理及引線呼叫的函式。在圖(十六)中,我們也看到如Kernel32.dll一般,CSRSRV.DLL也是會去使用到許多NTDLL.DLL所提供的系統函式(讀者應該還記得上期文章所提到NTDLL.DLL的2E中斷吧!。。。。^_^),所以囉!其實許多的子系統功能都是這樣一點一滴的用許多系統比較低階的函式來逐一構成的。尤其,Win32子系統是NT中最重要的一個子系統了。從系統一初始,到系統關機都會存在使用者的電腦中。
|
圖(十二)
|
圖(十三)
|
圖(十四)
|
圖(十五)
|
圖(十六)
▓Win16子系統
|
說到Win16,是這篇文章中我最喜歡的部份了,因為我覺得它非常的有趣,過去Windows3.1時代Win16的應用程式是共用一個虛擬的記憶體空間,同樣的情況在Windows NT中也是如此,如果我們在NT中啟動一個以上的Win16應用程式,我們會發現它們都會在同一個NTVDM.EXE之中(NT Virtual DOS Machine),也就是說目前系統中的Win16應用程式是活在一個DOS虛擬機器中,不過NT也不是這樣的不通人情的喔!由於Win16應用程式預設是共用一塊記憶體空間,且只分到一個CPU時間,所以如果要讓Win16應用程式得到較公平的對待的話,可以考慮在啟動Win16應用程式時,如下圖,把”在個別的記憶體空間執行”的選項勾起來。
圖(十七)
如下圖,是在NT中執行一個以上的Win16應用程式
|
圖(十八)
其實,讀者一定跟我一樣好奇,那一個Win16的應用程式除了使用NTVDM.EXE外,是如何模擬Win16的使用環境呢? 請看圖(十九),就是一個Win16應用程式在執行時所會一併執行的檔案。此時,CPU由Protect Mode切到V86 Mode,還有,別忘了KRNL386.EXE可是個16bit 的DPMI Client喔!
如下圖,是我在Windows NT中啟動Win16應用程式時,攔截系統的動作,所得到的一些資料。我們不難看出A3W.EXE 這個Win16的應用程式在執行前,系統會把許多Win16環境的模組載入到系統中。當模擬的Win16環境完成後,才把A3W.EXE給真正載入到系統中,讀者可以看到包括KEYBOARD.DRV 及 MOUSE.DRV等Win16系統基本的驅動程式,不過這一切對使用者來說是不自覺的,複雜的過程都被包在NT之中。
|
圖(十九)
在圖(十九)中所列的Win16程式啟動的檔案中,我們可以觀查這些程式的檔頭,如下圖為System.drv的檔頭部份
如果再看Win16 A3W.EXE應用程式啟動後,從Windows NT的System32目錄,所載入Memory的COMMDLG.DLL,如下圖
筆者在Trace NTVDM.EXE時,發現一些滿有趣的字串。如下圖,看起來有點像是Source Code的目錄位置,不過這可是我隨便猜的喔!如果有讀者知道這些字串的意思的話,可以寫封信跟我說一下,說真的,我也想知道這些字串所代表的意思呢!我並不是微軟的工程師,所以囉,這就留給各位讀者來猜想這些字串的涵意好了。
D:\CHT\nt\private\mvdm\softpc.new\host\src\nt_hosts.c
D:\CHT\nt\private\mvdm\softpc.new\host\src\nt_sec.c
D:\CHT\nt\private\mvdm\softpc.new\host\src\x86_emm.c
D:\CHT\nt\private\mvdm\softpc.new\host\src\nt_timer.c
D:\CHT\nt\private\mvdm\softpc.new\host\src\nt_eoi.c
D:\CHT\nt\private\mvdm\softpc.new\host\src\nt_com.c
D:\CHT\nt\private\mvdm\softpc.new\host\src\nt_event.c
D:\CHT\nt\private\mvdm\softpc.new\host\src\nt_det.c
|
圖(二十)
▓其它子系統
附帶一提,保護子系統一旦被使用者啟動後,就不會再從記憶體中被釋放掉,除非使用者重新開機。
在此我將為各位介紹一下Windows NT中最屬於Unix類的保護子系統POSIX,不過Windows NT並未能支援非常完整的POSIX環境,我們可以在圖(二十一),中看到保護子系統PSXSS.EXE及PSXDLL.DLL的檔頭。比較特殊的一點是PSXSS.EXE是屬於Win32的應用程式,而PSXDLL.DLL則是必須在Posix子系統下執行的程式。透過圖(二十二),相信對Unix熟悉的讀者應該面露微笑了,因為我們可以在PSXDLL.DLL的Export Table中看到它所提供的許多系統函式,包括了 mkdir,pipe,read………等等,在Unix環境中所會使用到的函式。
不過在NT中的POSIX子系統只支援符合POSIX 1003.1規格的Console Mode應用程式。
我並沒有在文章中提到Windows NT的OS/2子系統,主要也是因為筆者對OS/2系統所知比較有限。過去會使用OS/2也是抱著玩玩的心態,所以一直未能有機會把它給搞的很熟。希望諸位OS/2的玩家們不要見怪。
|
圖(二十一)
|
圖(二十二)
▓結語
現在當紅的Java VM所架構的程式環境,與NT的保護子系統比較起來,算是比較低階一點了。NT中Win32以外的子系統是透過Win32的API及NT呼叫來模擬出來的,讀者可以從PSXDLL.DLL中使用到大量的Win32 API來得知一二,如此則不若Java VM從應用程式所用的ByteCode來的低階許多。當然囉,我自己並不是一個Java的行家,如果讀者有不同的看法的話,可以來信與我討論一下,謝謝各位了。
沒有留言:
張貼留言