標籤:簡單 desire 階段 還需 i386 服務 exce object 試題
之前有聽到別人的面試題是問系統建立進程的具體過程是什麼,首先想到的是CreateProcess,但是對於具體過程卻不是很清楚,今天整理一下。
從作業系統的角度來說
建立進程步驟:
1.申請進程塊
2.為進程分配記憶體資源
3.初始化進程塊
4.將進程塊鏈入就緒隊列
課本上的知識。。。
從CreateProcess的具體流程來說:
CreateProcess它首先建立一個執行體進程對象,即EPROCESS 對象,然後建立一個初始線程,為初始線程建立一個棧,並設定好它的初始執行環境。完成這些工作以後,該線程就可以參與系統的線程調度了。然而,通過Windows API 函數建立的進程也要接受Windows 子系統的管理,在這種情況下,僅僅核心部分的工作還不夠,系統在建立進程過程中,還需要跟子系統打交道。另外,還需建立起獨立的記憶體位址空間。
CreateProcess通過核心建立進程的步驟,大致分為六個階段:
NtCreateProcess,它只是簡單地對參數稍作處理,然後把建立進程的任務交給NtCreateProcessEx 函數,所以我們來看NtCreateProcessEx 的原型及其流程。
NTSTATUS NtCreateProcessEx( __out PHANDLE ProcessHandle, __in ACCESS_MASK DesiredAccess, __in_opt POBJECT_ATTRIBUTES ObjectAttributes, __in HANDLE ParentProcess, __in ULONG Flags, __in_opt HANDLE SectionHandle, __in_opt HANDLE DebugPort, __in_opt HANDLE ExceptionPort, __in ULONG JobMemberLevel );
NtCreateProcessEx 函數的代碼只是簡單地檢查ProcessHandle 參數代表的控制代碼是否可寫,然後把真正的建立工作交給PspCreateProcess 函數,所以,PspCreateProcess 才是真正建立進程的函數。
PsCreateSystemProcess 可用於建立系統進程對象,它建立的進程都是PsInitialSystemProcess 的子進程。所以,PspCreateProcess函數負責建立系統中的所有進程,包括System 進程。下面介紹此函數的基本流程。
第一階段:開啟目標映像檔案
第二階段:建立核心中的進程對象
第三階段:建立初始線程
第四階段:通知windows子系統進程csrss.exe進程來對新進程進行管理
第五階段:啟動初始線程
第六階段:使用者空間的初始化和Dll串連
具體內容:
在Windows中,CreateProcess要先通過系統調用NtCreateProcess建立進程,成功以後就立即通過系統調用NtCreateThread建立其第一個線程。
第一階段:開啟目標映像檔案
首先用CreateProcess(實際上是CreateProcessW)開啟指定的可執行映像檔案,並建立一個記憶體區對象。注意,記憶體區對象並沒有被映射到記憶體中(由於目標進程尚未建立起來,不可能完成記憶體映射),但它確實是開啟了。
第二階段:建立核心中的進程對象
實際上就是建立以EPROCESS為核心的相關資料結構,主要包括:
調用核心中的NtCreateProcessEx 系統服務,實際的調用過程是這樣的:kernel32.dll 中的CreateProcessW調用ntdll.dll 中的存根函數NtCreateProcessEx,而ntdll.dll的NtCreateProcessEx 利用處理器的陷阱機制切換到核心模式下;在核心模式下,系統服務分發函數KiSystemService 獲得控制,它利用當前線程指定的系統服務表,調用到執行體層的NtCreateProcessEx 函數。然後,執行體層的NtCreateProcessEx 函數執行前面介紹的進程建立邏輯,包括建立EPROCESS 對象、初始化其中的域、建立初始的進程地址空間、建立和初始化控制代碼表,並設定好EPROCESS 和KPROCESS 中的各種屬性,如進程優先順序、安全屬性、建立時間等。到這裡,執行體層的進程對象已經建立起來,進程的地址空間已經初始化,並且EPROCESS 中的PEB 也已初始化。
第三階段:建立初始線程
這個階段是通過調用NtCreateThread()完成的,主要包括:
現在,雖然進程對象已經建立起來,但是它沒有線程,所以,它自己還不能做任何事情。接下來需要建立一個初始線程,在此之前,首先要構造一個棧以及一個可供啟動並執行環境。初始線程的棧的大小可以通過映像檔案獲得,而建立線程則可以通過調用ntdll.dll 中的NtCreateThread 函數來完成。
建立和設定目標線程的ETHREAD資料結構,並處理好與EPROCESS的關係(例如進程塊中的執行緒計數等等)。
在目標進程的使用者空間建立並設定目標線程的TEB。
將目標線程在使用者空間的起始地址設定成指向Kernel32.dll中的BaseProcessStart()或BaseThreadStart(),前者用於進程中的第一個線程,後者用於隨後的線程。
使用者程式在調用NtCreateThread()時也要提供一個使用者級的起始函數(地址), BaseProcessStart()和BaseThreadStart()在完成初始化時會調用這個起始函數。
ETHREAD資料結構中有兩個成份,分別用來存放這兩個地址。
調用KeInitThread設定目標線程的KTHREAD資料結構並為其分配堆棧和建立執行環境。
特別地,將其上下文中的斷點(返回點)設定成指向核心中的一段程式KiThreadStartup,使得該線程一旦被調度運行時就從這裡開始執行。
系統中可能登記了一些每當建立線程時就應加以調用的“通知”函數,調用這些函數。
第四階段:通知windows子系統
每個進程在建立/退出的時候都要向windows子系統進程csrss.exe進程發出通知,因為它擔負著對windows所有進程的管理的責任,
注意,這裡發出通知的是CreateProcess的調用者,不是建立出來的進程,因為它還沒有開始運行。
至此,CreateProcess的操作已經完成,但子進程中的線程卻尚未開始運行,它的運行還要經曆下面的第五和第六階段。
第五階段:啟動初始線程
在核心中,新線程的啟動常式是KiThreadStartup函數,這是當PspCreateThread 調用KeInitThread 函數時,KeInitThread 函數調用KiInitializeContextThread(參見base\ntos\ke\i386\thredini.c 檔案)來設定的。
KiThreadStartup 函數首先將IRQL 降低到APC_LEVEL,然後調用系統初始的線程函數PspUserThreadStartup。這裡的PspUserThreadStartup 函數是PspCreateThread 函數在調用KeInitThread 時指定的,。注意,PspCreateThread函數在建立系統線程時指定的初始線程函數為PspSystemThreadStartup 。線程啟動函數被作為一個參數傳遞給PspUserThreadStartup,在這裡,它應該是kernel32.dll 中的BaseProcessStart。
PspUserThreadStartup 函數被調用。邏輯並不複雜,但是涉及非同步函數調用(APC)機制。
新建立的線程未必是可以被立即調度啟動並執行,因為使用者可能在建立時把標誌位CREATE_ SUSPENDED設成了1;
如果那樣的話,就需要等待別的進程通過系統調用恢複其運行資格以後才可以被調度運行。否則現在已經可以被調度運行了。至於什麼時候才會被調度運行,則就要看優先順序等等條件了。
第六階段:使用者空間的初始化和Dll串連
PspUserThreadStartup 函數返回以後,KiThreadStartup 函數返回到使用者模式,此時,PspUserThreadStartup 插入的APC 被交付,於是LdrInitializeThunk 函數被調用,這是映像載入器(image loader)的初始化函數。LdrInitializeThunk 函數完成載入器、堆管理器等初始化工作,然後載入任何必要的DLL,並且調用這些DLL 的入口函數。最後,當LdrInitializeThunk 返回到使用者模式APC 分發器時,該線程開始在使用者模式下執行,調用應用程式指定的線程啟動函數,此啟動函數的地址已經在APC 交付時被壓到使用者棧中。
DLL串連由ntdll.dll中的LdrInitializeThunk()在使用者空間完成。在此之前ntdll.dll與應用軟體尚未串連,但是已經被映射到了使用者空間
函數LdrInitializeThunk()在映像中的位置是系統初始化時就預先確定並記錄在案的,所以在進入這個函數之前也不需要串連。
涉及到了Windows核心的知識,細節處還有待理解。。。
參考資料:
http://www.cnblogs.com/csyisong/archive/2010/10/22/1858115.html
http://www.cnblogs.com/Gotogoo/p/5262536.html
http://book.51cto.com/art/201011/235767.htm
《Windows核心原理與實現》潘愛民
關於Windows建立進程的過程