windows載入PE檔案的流程

wenli7363發表於2024-09-08
  1. 讀取PE檔案
    當一個PE檔案被執行時,Windows的建立程序函式(CreateProcess)首先被呼叫,負責為新程序建立虛擬地址空間。
    作業系統從磁碟讀取PE檔案,將其頭部內容(DOS頭、PE頭和節表)載入記憶體,以獲取該檔案的結構和裝載資訊。

  2. 檢查PE檔案有效性
    作業系統首先會檢查PE檔案的合法性,比如驗證DOS頭中的 "MZ" 簽名,接著檢查PE頭中的 "PE\0\0" 簽名。
    如果檔案不符合PE格式要求,作業系統會中止載入並返回錯誤。

  3. 分配虛擬地址空間
    根據PE頭部的資訊,作業系統會為程序分配所需的虛擬地址空間。其中包括程式的程式碼段、資料段、堆疊等。
    裝載基地址:PE檔案頭中包含一個“裝載基地址”(ImageBase),指明程式希望被載入到哪個虛擬地址。如果該地址不可用(例如,衝突),則需要重定位。
    作業系統使用分頁記憶體管理機制來為程式分配虛擬記憶體區域,但此時並不會將所有PE檔案的內容都立即載入到實體記憶體中。

  4. 載入各個段到虛擬記憶體
    根據節表(Section Table)的描述,作業系統會將PE檔案中的不同段(如程式碼段、資料段等)對映到程序的虛擬地址空間中:
    程式碼段(.text)通常是隻讀和可執行的。
    資料段(.data)是讀寫區域,存放全域性變數和已初始化的資料。
    未初始化資料段(.bss)通常被作業系統初始化為0。
    匯入表(.idata)、匯出表(.edata)等特殊段也會對映到記憶體中,用於動態連結庫的管理。
    作業系統在載入時會將這些段對映到虛擬地址空間中,並且可能使用惰性載入(Lazy Loading)策略,即只有在段被實際訪問時才會將其載入到實體記憶體中。

  5. 動態連結庫(DLL)的載入與解析
    如果PE檔案有匯入表(Import Table),它會列出該可執行檔案所依賴的DLL檔案及其函式。
    作業系統會讀取匯入表中的每一個DLL名稱,並嘗試載入這些DLL檔案。未載入的DLL檔案將被作業系統載入到當前程序的虛擬地址空間中。
    接著,作業系統會解析匯入表中所引用的每個函式符號,並將它們對映到正確的記憶體地址上。如果函式是延遲繫結的(如使用 LoadLibrary 和 GetProcAddress 動態載入),則它們會在第一次被呼叫時載入。

  6. 地址重定位(Relocation)
    如果PE檔案的裝載基地址被作業系統佔用,作業系統會將PE檔案載入到不同的地址空間。此時需要進行重定位,即調整PE檔案中的指標和地址,使其指向新的基地址。
    重定位資訊儲存在PE檔案中的重定位表(Relocation Table)中,作業系統會根據該表修正所有與基地址相關的地址。

  7. 執行TLS回撥函式
    如果PE檔案使用了執行緒區域性儲存(TLS),在載入過程中,作業系統會呼叫TLS回撥函式。這些回撥函式通常用於在程序或執行緒初始化時執行特定的任務,如全域性變數初始化等。

  8. 設定初始棧和堆
    作業系統為程序分配堆疊和堆。堆疊用於儲存函式呼叫資訊和區域性變數,堆用於動態記憶體分配。
    棧空間初始分配較小,隨著函式呼叫的深入,棧空間會動態增加。

  9. 跳轉到入口點執行
    PE檔案的PE頭中有一個入口點(Entry Point),它是程式的主執行程式碼的起始地址。
    作業系統透過載入器跳轉到入口點並開始執行程式。對於普通應用程式,入口點通常是 main() 函式;對於DLL檔案,則是 DllMain() 函式。

  10. 執行程式的主邏輯
    從入口點開始,程式的執行邏輯正式執行,執行程式碼、訪問資料,並與作業系統、其他程序或裝置進行互動。
    如果程式請求記憶體或與外部裝置互動,會透過系統呼叫來請求作業系統的服務。
    三、程序結束和解除安裝
    當程序完成後,程式會透過系統呼叫 ExitProcess() 或 exit() 通知作業系統結束執行。
    作業系統會清理該程序分配的虛擬地址空間,釋放實體記憶體,並將該程序的所有資源(包括檔案控制代碼、記憶體等)返還給系統。
    如果是DLL檔案,作業系統會根據需要呼叫 FreeLibrary() 函式解除安裝不再使用的DLL,並清理與該DLL相關的資源。

相關文章