windows啓動以及exe文件的加載簡介

http://blog.163.com/jing0352@126/blog/static/34921313201092572126767/

 先來看這樣一個過程(非VISTA啓動):CPU復位->傳統BIOS->MBR->引導扇區->NTLDR->NTOS->SMSS->1:CSRSS 2:WinLogon->1:LSRSS 2:Services 3:LogonUI->2:Services->Svchost  3:LogonUI->USERINT->1:StartUp App 2:Shell

     這是非 VISTA 的啓動過程,是傳統 Windows 的啓動,這裏有幾處必要提到,首先 NTLDR 是一個非常重要的啓動文件,在 C 盤下,相關的還有 boot.ini, pagefile.sys, NTDETECT.COM,我們按 F8 或者 F5 時進入安全模式的界面也是它產生的。然後是 NTOSKEL 這就是產生滾動條界面的,這是啓動最漫長的過程!我曾經看到過有“高手”說過可以改掉滾動條滾動次數的註冊表位置,其實這是不能改的,在這個界面下的過程非常漫長非常複雜,不提。然後是 SMSS 進程,這是第一個真正意義上由 .EXE 產生的進程。然後建出 CSRSS 子系統服務器進程和 WinLogon 進程。最後建出 Shell:Explorer.exe 進程。和本文最相關的就是這個 Shell 了,Shell “命令解釋器”它的經典就是 Explorer.exe 。每一個窗口其實就是它創建的一個線程!這是一個非常厲害的多線程設計了!比如我們點擊桌面上的圖標啓動一個程序,就是由它來加載創建的,好了,有了這些就開始來講本文的其中一個內容:.EXE 的加載過程,然後再由此擴充開。

      雙擊一個 .EXE 圖標(操作系統怎麼定位哪一個圖標不是本文的內容),Shell 調用 CreateProcess 函數,系統找出在調用 CreateProcess 函數時的 .exe 文件,如果文件不在則返回 FALSE 進程創建失敗。成功的話則爲該進程創建一個新進程內核對象,這個內核對象是由系統內核管理的,關於內核對象也是一個很長的話題,詳細敘述的話我寫到明天恐怕都寫不完這篇文章了,只要知道這個時候如果 CreateProcess 成功的話系統爲這個進程創建了一個使用記數爲1的進程內核對象,值得一提的是有一個進程內核對象句柄表,這裏紀錄了所有在該進程中所有創建出來的進程內核對象,但這個東西 Microsoft 沒有提供相關文檔,我的偶像 Jeffrey Richter 也只是簡單的提了一提,接下來系統爲這個新進程創建了一個私有地址空間,這就是我們很清楚的 4GB 地址空間! 寫到這裏先停住,我發現了一個比較大的問題,Shell 調用 CreateProcess 這個函數時其中的參數是哪裏來的?我根據 Jeffrey Richter 的一句話也就是系統找出 EXE 文件,如果存在的話則創建成功,那麼我進一步推論,那其中的參數很有可能是來自 PE 格式中的信息,可以繼續推論下去,研究一下 CreateProcess 的參數再對照一下 PE 格式各個段的包含信息,那應該可以研究出某些東西來,這個細節我是還沒有深入對比過,如果有哪位看官知道的話還請賜教!在這裏先謝過了!接下來系統會保留一個足夠大的區域來存放.exe 文件,默認的話是保存在從OXOO4OOOOO開始的位置,而這個數值是在 exe 這個 PE 結構中的信息,用 /BASE 是可以改的。這裏就牽涉到內存映射文件了,不提。我們來研究一下 0X00400000 在內存中的什麼區域,看一下 Win32 內存結構中4GB的劃分(不再提 98 那破爛了)0x00000000 - 0x0000FFFF 這64KB用於 NULL 指針分配,舉一個 Richter 的例子:int *pnSomeInteger = (int*)malloc(sizeof(int)); *pnSomeInteger = 5; 如果 malloc 不能找到足夠的內存來分配的話那它就返回 NULL 就是保存在這裏了,接下來 0x00010000 - 0x7FFEFFFF 這一段就是 Win32 進程私有的地址空間,剛纔的.exe 加載就在這一段空間中,接下來繼續加載程序執行所必須的 DLL 文件也是在這個段裏,當然在這裏還有一些數據需要加載,和爲線程開闢的堆棧區,所以進程的這個用戶區其實分成了3個部分:文本區包括指令和可讀的數據,通常這個段是標記爲可讀,數據區,這個段對應 PE 中的 DATA_BASS 包含以初始化和未初始化的數據,靜態變量也存放在這個區中,最後就是堆棧區,這是爲線程分配的默認爲1MB,當然是可以改的,在這裏包含了函數參數和局部變量,當然也有現場保護時的信息,很關鍵的一點是 IP 指針也在這裏,緩衝區溢出攻擊就是在這個區域做文章,俗稱:踐踏堆棧。好!因爲 Win32 中進程是一個惰性的,它什麼也不執行,除了 EXE 和 DLL 還有它們所需的數據加載到進程地址空間外每個進程還擁有別的資源,這裏只要記住:窗口和鉤子是屬於線程的外其他都是進程的,所以進程必須有一個線程來執行它的代碼,這時候系統就爲進程創建一個主線程,但它是調用 C 運行時庫函數,這裏又有區分 CUI 和 GUI,ANSI 和 UNIODE 的差別,如果以 GUI 和 UNICODE 來講,它調用的是 wWinMainCTRStartup 這個可執行文件的啓動函數。這個函數的功能不多講,它會進行一系列初始化工作,完了後它將調用我們編寫的主函數入口函數比如 wWinMain();最後 exit 調用調用操作系統的ExitProcess 函數,將 nMainRetVal 傳遞給它,這使得操作系統能夠撤銷進程並設置它的 exit  代碼。到這裏啓動過程結束!

     回顧上面的內容,就這一個啓動過程實在複雜!複雜!牽涉到進程,線程,PE 結構,Win32 內存結構!而這些我看其實就是操作系統原理的核心部分了!上面的分析只是非常簡單的提了個大概,裏面的每一個內容我看都可以寫成一本書了...再回顧一下 Windows 的啓動過程,這兩者之間的複雜程度何其的相似!有興趣的可以去深入研究 Windows 的啓動過程,單單就那個滾動條界面的時候, Windows 做了一大堆大堆的工作!想要用一篇短短的文章是不可能寫完這些的。比如 PE 格式的有效性,Win32 內存管理,當然,很精彩的是我剛纔提到的緩衝區溢出攻擊,真佩服這個創始人!好了,寫代碼去了。

 

 

本文來自CSDN博客,轉載請標明出處:http://blog.csdn.net/idy_10000/archive/2011/03/05/6225613.aspx

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章