Windows核心

weixin_34391854發表於2014-09-29
每天我們都在使用Windows系統學習、程式設計、聽音樂、玩遊戲,Windows的操作想來是非常熟練了,但是你又對Windows究竟瞭解多少呢?本系列的目的,就是讓你對Windows系統有個更直觀、更清楚、更徹底的認識。儘管我們大多數人看不到Windows的原始碼,對其記憶體排程演算法這樣的最深層次的技術內幕不能明窺,但是我們能夠做到比方今知道的很多其它,瞭解這些之後你會發如今Windows上面開發會輕車熟路,不論什麼木馬病毒到了你機器上只是僅僅會成為你的試驗品。
鑑於Windows 9X核心早已淘汰,技術過時,在此不予討論。主要是針對Windows2000(Windows 5.0)以後版本號,尤以2000為主。要知道xp是Windows 5.1版本號,2003也才是5.2版本號。那麼,對於本系列提到Windows OS技術,統指Windows 5.X技術。
 一、直觀認識Windows
分析一個軟體,最easy的入手方法就是先搞清楚它的每一個檔案都是幹嘛的。我們先來讓大家對自己正在使用的Windows 作業系統有個直觀認識。請在你使用的Windows 2000或Windows XP上,於WINNT/system32或Windows/system32資料夾(系統資料夾)下,找到下面幾個檔案:HAL.DLL、NTOSKRNL.EXE、NTDLL.DLL、KERNEL32.dll、GDI32.DLL、USER32.DLL。這幾個是Windows系統賴以執行的關鍵,僅僅要你能在圖形介面下操作Windows,這幾個檔案就肯定在發揮作用。值得一提的是Windows的圖形介面子系統是在核心實現的(知道為什麼Linux的圖形介面怎麼著都沒Windows好看好用了吧)。
對這幾個檔案的功用給出簡單介紹例如以下:
HAL.DLL:Hardware Abstraction Layer,硬體抽象層。
Windows 2000也是一個軟體系統,與我們平時從事的專案開發工作一樣,專案初期須要確定開發目標。而Windows2000開發當初制定的開發目標之中的一個就是要可以在多種硬體平臺上移植(Windows2000支援單處理器、多處理器、Compaq SystemPro),不同的硬體平臺上有不同的硬體抽象層實現。在我們通常使用的標準PC上這個檔案就是HAL.DLL(在Compaq SystemPro上是HALSP.DLL,滿足不同硬體平臺的硬體抽象層檔案在Windows安裝盤上都有,安裝時依據計算機的平臺型別僅僅複製對應的檔案)。
HAL是可載入的核心模式模組(DLL動態連結庫檔案),它為Windows系統所執行的硬體平臺提供低階介面。它隱藏硬體相關的細節,如I/O介面、中斷控制器和多處理器通訊機制等這些與特定硬體結構機密相關的內容,而向作業系統核心提供統一的硬體介面函式。
 NTOSKRNL.EXE:NT OS Kernel,毋庸置疑,這就是Windows系統的核心,確切說核心是在這裡面實現的,僅僅有1.6兆,與眼下Linux2.4版本號核心編譯後的大小差點兒相同。
這個檔案實際上提供兩部分的基本的功能:
一是系統核心,這在硬體抽象層之上,提供系統的基本機制(執行緒排程和同步、記憶體分配等等一切你在作業系統原理書上能夠看到的最複雜的那一部分,假設你認為作業系統課程學得太抽象又有點跟自己過不去,試著把這個NTOSKRNL.EXE反彙編了讀一讀吧,不多,也就300多萬行彙編碼,僅僅是找不著確切的入口點)。同一時候核心還提供硬體支援,實際上是將驅動程式等上層程式的呼叫對硬體進行詳細化,反過來講就是硬體抽象層再抽象一次,暴露給上層一個統一的介面,寫過Windows驅動程式或是看過DDK的同學一定對Windows WDM驅動的固定編寫模式有非常深的印象。
 二是執行程式(稱為Executive)。這個執行程式的東東可真是多啊,我在搗騰的時候都有點讓它搞得暈暈的,只是如今來看呢事實上也就一句話:執行程式是開發人員與Windows之間互動的窗體,再直觀點說執行程式對外暴露Windows開發函式,經過幾次封裝後供開發人員使用。我們先無論這些函式的功能分類,按功能分類的話東西有點多有點亂,easy讓人puzzled。按開發人員的角度來看,有這麼幾類:Win32 API函式,這是做應用開發用的,我們常說的MFC、ATL是對其進行的物件導向化及封裝;DDK API函式和IFS kit函式,這是供驅動開發用的,DDK還耳熟些,只是假設你瀏覽過DDK而且夠細心的話就會認為奇怪為啥OS非常重要的一部分——檔案系統驅動的開發沒有提供,IFS(Installable File System) Kit就是做這個的啦。
 我們前面說過Windows把圖形介面處理放在了核心態來執行,因此不得不提一個比較特殊的驅動:Win32k.sys,你看到的美麗的Windows桌面就是這個檔案畫出來的。
 說到這裡,前述內容是Windows系統在核心態執行的基本功能,也就是說,這是執行於CPU ring0級別的(不懂什麼是ring的話趕緊去Intel的站點download Intel CPU的系統開發參考看,甭翻你手頭的微機原理課本了,那上面沒有)。另一大堆驅動也是執行在這個級別。在核心級別上,元件之間功能的呼叫等等與使用者態不同,經常使用的是LPC,這個我們以後慢慢再講。
 繼續以下的內容之前,要先說明一點事實:Windows的功能比我們平時所見的要強大的多。通常我們講Win32,實際上這僅僅是Windows的一個子系統而已,Windows還有另外的兩個子系統:POSIX和OS/2。這麼一說的話似乎Linux上的程式能夠在Windows上執行了,事實上沒那麼簡單,還須要移植庫以及又一次編譯連線,終於還得依賴Win32子系統的實現來完畢其功能,意義不大,基本上算是被使用者們喀嚓掉了吧,我們也是僅僅講Win32子系統。點明一點:不同的子系統有專門的子系統支援環境,POSIX子系統是POSIX.EXE,Win32子系統是Csrss.EXE(全稱是Client/Server Run-time SubSystem)。所以,你的機器上總有Csrss.exe這樣一個程式在執行,別無聊的以為它是木馬沒事就Kill著玩。
 以下是使用者級別的內容。為了方便理解,核心級別的分層介紹我們是從下往上(由硬到軟)開始,在使用者級別,我們從上往下開始介紹,這樣更直觀些。
我們先舉一個應用程式的樣例(雖然使用者級別的程式遠不止應用程式這麼多),從IE講起。假設你裝了VC,而且順帶安裝了Depends這個工具,用它開啟IE(或是不論什麼一個windows可執行檔案都可),你會發現IE主程式(IEXPLORE.EXE)呼叫了Kernel32.DLL,而Kernel32.DLL又呼叫了NTDLL.DLL,同一時候,IE主程式還呼叫了USER32.DLL,USER32.DLL又有對GDI32.DLL、KERNEL32.DLL、NTDLL.DLL的呼叫,期間還有迴圈呼叫。
 去繁從簡,Win32應用程式要呼叫Win32 API函式,這些函式正是有KERNEL32.DLL提供的,而KERNEL32.DLL這個檔案事實上並不實現詳細的功能,僅僅是做了一個簡單的地址指標轉換,把函式入口點又跳到NTDLL.DLL裡去了,相應到了相應的本機API(NATIVE API)函式上,NTDLL.DLL也不做詳細的處理,通過系統功能呼叫將使用者級的函式呼叫轉換成核心模式的真正的系統功能呼叫,由核心執行完成後返回應用程式程式。或許有人要問Windows為什麼要通過Kernel32.DLL和NTDLL.DLL對執行程式Executive暴露的程式設計介面做兩次封裝,事實上這也是Win32 API和NATIVE API的差別。Win32 API又稱為存檔的API,是供使用者使用的,必須保持一致性和相容性,不能隨隨便便改動函式命名,新函式的新增�必須保持對老函式的相容,否則使用老版本號的Win32 API開發(直觀的就是我們使用win32 SDK或MFC開發)的程式在新版本號的系統上可能就要執行出錯。而NATIVE API則是在系統更新時可能須要進行改動的函式,比方函式名、函式引數的型別和個數等,都有可能隨著系統升級而變更,因此是留給MS自己人來用的,當然不能直接給使用者使用。但這不是說就我們作為開發人員就不能使用NATIVE API,假設你自己定位NTDLL.DLL中的函式並進行呼叫,僅僅要這個函式未被MS改動,能夠肯定這樣的呼叫是成功的,你的程式執行也沒有不論什麼問題。與KERNEL32.DLL相似的另一個ADVAPI32.DLL,提供一些比較高階的應用程式設計函式。
GDI32.DLL和USER32.DLL提供存檔的Win32圖形程式設計介面,它們也是通過NTDLL.DLL來完畢對系統畫圖功能(在win32k.sys中實現)的呼叫。
KERNEL32.DLL、ADVAPI32.DLL、USER32.DLL和GDI32.DLL統稱為Win32子系統DLL。Win32子系統DLL將存檔的Win32 API函式“翻譯”為對應的對本機API函式呼叫,NTDLL.DLL將本機API“翻譯”為NTOSKRNL.EXE和Win32k.sys的核心模式系統服務呼叫,來完畢使用者級別功能需求的實現。
 講過應用程式之後,再看看使用者級別的其他程式。環境子系統(Win32子系統、POSIX子系統、OS/2子系統),這個前面提過了;服務程式,也就是你在服務管理器裡能夠看到的那一堆東東,包含Services.EXE這個比較特殊的服務程式、svchost.exe等等,這些以後慢慢談;再就是系統支援程式,如SMSS.EXE(會話管理器)、WINLOGON.EXE(登陸程式)、LSASS.EXE(本機安全許可權子系統)等,這些都是專門的內容,有機會將做專題研究。在這裡提到的程式都是Windows系統正常執行必要的一些程式,也就是說它們是安全的,大家不必對其有疑心(當然了,有漏洞那是例外)。大部分使用者級別應用程式的執行要呼叫KERNEL32.DLL,然後再間接呼叫NTDLL.DLL,系統支援程式等程式有的是直接呼叫NTDLL.DLL。
系統機制:
 windows2000為執行體、核心、裝置驅動程式等核心態部分提供了一些基礎機制。先讓我們看看都有哪些:
    (1)陷阱排程:包含中斷、延遲過程呼叫(DPC)、非同步過程呼叫(APC)、異常處理、系統服務排程。
    (2)執行體物件管理
    (3)同步機制:自旋鎖、核心排程物件以及等待是怎樣實現的
    (4)系統執行緒
    (5)多種系統機制如windows2000全域性標誌
    (6)本地過程呼叫
以下我們就來逐個分析:
 
陷阱排程
 
中斷和異常的實質是使CPU不依照正常的步驟來工作,硬體和軟體都可以察覺到它們。陷阱是當異常或者中斷髮生時可以儲存當前執行緒狀態並轉向對應處理的一種系統機制。在windows2000中,處理器將控制交給陷阱處理程式--一些專門來處理中斷、異常的程式。
核心通過下面方式來分辨中斷和異常:中斷是一個非同步事件(能夠在不論什麼時間產生),無論處理器在執行什麼程式。中斷典型地由I/O裝置、時鐘、定時器產生,必要時我們能夠遮蔽中斷。而異常是一個同步事件,它是由正在執行的特定程式碼產生的,又一次執行同樣的程式碼會反覆產生特定的異常。比方訪問非法記憶體、除數為0等。系統把系統服務也作為異常來處理。
不管是硬體或者是軟體都能產生中斷和異常,比方說,一個匯流排異常是由硬體引起的,而除數為0顯然是軟體中的BUG導致的;相同,I/O裝置能夠產生中斷,核心本身也能產生軟中斷(APC,DPC)。
當一個硬體中斷或者異常發生時,處理器收集足夠的狀態資訊以保證當異常或中斷處理完成後能夠正確返回到當前執行點。處理器通過在當前執行緒的核心棧區建立一個陷阱框架(用來儲存現場)來實現。陷阱框架通常時執行緒整個上下文環境的一部分。而把軟中斷當成硬中斷的一部分來處理,或者是呼叫核心中對應的處理程式。
在大多數情況下,當有陷阱發生時核心負責尋找對應的處理程式而且在處理程式返回時負責恢復中斷執行緒的繼續執行。
    中斷排程
硬體中斷是由I/O裝置產生以求獲得CPU服務的,這樣的中斷機制使得CPU的利用率提高非常多。軟體也能夠產生中斷,比方說,核心能夠發起一箇中斷來進行執行緒排程。核心在必要的時候能夠關中斷,這樣CPU就能夠遮蔽掉不論什麼中斷-----這在有些時候是必要的,比方執行緒對於臨界區的訪問,異常處理等。
硬體中斷處理
在X86家族裡,外部中斷在中斷控制器裡進行排隊,控制器依次中斷CPU的執行。當CPU被中斷時,它要求中斷控制器提交中斷請求,中斷控制器將中斷請求翻譯為中斷請求號,而且把這個號碼當成索引來查詢中斷排程表(IDT),而且將控制權交給對應的中斷處理程式。中斷排程表(IDT)在系統啟動的時候就已經初始化了,裡面包含中斷號和對應處理程式的對應。
 中斷請求登等級IRQL:
中斷是有等級的,這對於軟、硬中斷都是適用。核心將中斷為0---31共32個等級,等級高的許可權高。核心負責將軟中斷相應到相應的等級上,HAL負責將硬體中斷相應到相應的等級上。例如以下圖所看到的:
中斷處理是按等級來執行的,而且是搶佔式的,高等級的能夠堵塞低等級的執行。當執行中斷處理程式時,CPU把自己的IRQL設定為要執行的中斷的IRQL,然後執行.
那麼系統是怎樣把硬體中斷對映到對應的IRQL的呢?答案是HAL,在WINDOWS2000中,匯流排驅動可以得知全部連線到匯流排上的裝置,以及每一個裝置能發出何種中斷,緊接著匯流排驅動把所得到的情況彙報給PNP(即插即用管理器),它做出抉擇。最後呼叫HAL函式HalpGetSystemInterruptVector來實現對映。
注:該文章是認識Windows系統核心的入們文章,轉載至此希望對想深入學習Windows的朋友有所幫助,起一個拋磚引玉的作用,有對此感興趣的朋友能夠交流下。僅僅可惜此篇文章沒有找全,非常是遺憾,有朋友找到的請通知一聲。。再次感謝下該文作者。。
 
 

相關文章