進(jìn)程(Process)是具有一定獨(dú)立功能的程序關(guān)于某個(gè)數(shù)據(jù)集合上的一次運(yùn)行活動(dòng),是系統(tǒng)進(jìn)行資源分配和調(diào)度的一個(gè)獨(dú)立單位。程序只是一組指令的有序集合,它本身沒有任何運(yùn)行的含義,只是一個(gè)靜態(tài)實(shí)體。而進(jìn)程則不同,它是程序在某個(gè)數(shù)據(jù)集上的執(zhí)行,是一個(gè)動(dòng)態(tài)實(shí)體。它因創(chuàng)建而產(chǎn)生,因調(diào)度而運(yùn)行,因等待資源或事件而被處于等待狀態(tài),因完成任務(wù)而被撤消,反映了一個(gè)程序在一定的數(shù)據(jù)集上運(yùn)行的全部動(dòng)態(tài)過程。
線程(Thread)是進(jìn)程的一個(gè)實(shí)體,是CPU調(diào)度和分派的基本單位。線程不能夠獨(dú)立執(zhí)行,必須依存在進(jìn)程中,由進(jìn)程提供多個(gè)線程執(zhí)行控制。從內(nèi)核角度講線程是活動(dòng)體對(duì)象,而進(jìn)程只是一組靜態(tài)的對(duì)象集,進(jìn)程必須至少擁有一個(gè)活動(dòng)線程才能維持運(yùn)轉(zhuǎn)。當(dāng)某個(gè)應(yīng)用程序調(diào)用一個(gè)創(chuàng)建進(jìn)程的函數(shù)比如CreateProcess或者用戶執(zhí)行某一個(gè)程序(其實(shí)windows下用戶執(zhí)行一般普通程序是由explorer.exe調(diào)用CreateProcess來完成),操作系統(tǒng)把這個(gè)過程分成以下步驟來完成:
1.打開將要在該進(jìn)程中執(zhí)行的映像文件。
2.創(chuàng)建Windows執(zhí)行體進(jìn)程對(duì)象。
3.創(chuàng)建初始線程(棧、堆執(zhí)行環(huán)境初始化及執(zhí)行線程體對(duì)象)。
4.通知Windows子系統(tǒng)新進(jìn)程創(chuàng)建了(子系統(tǒng)是操作系統(tǒng)的一部分它是一個(gè)協(xié)助操作系統(tǒng)內(nèi)核管理用戶態(tài)/客戶方的一個(gè)子系統(tǒng)具體的進(jìn)程為Csrss.exe)。
5.開始執(zhí)行初始線程(如果創(chuàng)建時(shí)候指定了線程的CREATE_SUSPENDED狀態(tài)則線程暫時(shí)掛起不執(zhí)行)。
6.在新進(jìn)程和線程環(huán)境中完成地址空間的初始化(比如加載必須的DLL和庫),然后開始到進(jìn)程入口執(zhí)行。
到這里操作系統(tǒng)完成一個(gè)新進(jìn)程的創(chuàng)建過程。
下面來看下具體每一步操作系統(tǒng)所做的工作:
1.打開將要在該進(jìn)程中執(zhí)行的映像文件。
首先操作系統(tǒng)找到執(zhí)行的Windows映像然后創(chuàng)建一個(gè)內(nèi)存區(qū)對(duì)象,以便后面將它映射到新的進(jìn)程地址空間中。
2.創(chuàng)建Windows執(zhí)行體進(jìn)程對(duì)象。
接下來操作系統(tǒng)調(diào)用內(nèi)部的系統(tǒng)函數(shù)NtCreateProcess來創(chuàng)建一個(gè)Windwos執(zhí)行體進(jìn)程對(duì)象。具體步驟是:
(1)建立EPROCESS
*分配并初始化EPROCESS結(jié)構(gòu)塊
*從父進(jìn)程處繼承得到進(jìn)程的親和性掩碼
*分配進(jìn)程的最大最小工作集尺(由兩個(gè)參數(shù)決定PsMinimumWorkingSet PsMaximumWorkingSet)
*降新進(jìn)程的配額塊設(shè)置為父進(jìn)程配額塊地址,并遞增父進(jìn)程配額塊的引用計(jì)數(shù)
*繼承Windows的設(shè)備名字空間
*將父進(jìn)程進(jìn)程ID保存在新進(jìn)程對(duì)象的InheritedFormUniqueProcessId中
*創(chuàng)建該進(jìn)程的主訪問令牌
*初始化進(jìn)程句柄表
*將新進(jìn)程的退出狀態(tài)設(shè)置為STATUS_PENDING
(2)創(chuàng)建初始的進(jìn)程地址空間
*在適當(dāng)?shù)捻摫碇袆?chuàng)建頁表項(xiàng),以映射初始頁面
*從MmresidentAvailablePage算出進(jìn)程工作集大小
*系統(tǒng)空間的非換頁部分和系統(tǒng)緩存的頁表被映射到進(jìn)程
(3)初始化內(nèi)核進(jìn)程塊KPROCESS
(4)結(jié)束進(jìn)程地址空間的創(chuàng)建過程
(5)建立PEB
(6)完成執(zhí)行體進(jìn)程對(duì)象的創(chuàng)建過程
3.創(chuàng)建初始線程(棧、堆執(zhí)行環(huán)境初始化及執(zhí)行線程體對(duì)象)。
這時(shí)候Windows執(zhí)行體進(jìn)程對(duì)象已經(jīng)完全建立完成,但它還沒有線程所以無法執(zhí)行,
接下來系統(tǒng)調(diào)用NtCreateThread來創(chuàng)建一個(gè)掛起的新線程它就是進(jìn)程的主線程體。
4.通知Windows子系統(tǒng)新進(jìn)程創(chuàng)建了(子系統(tǒng)是操作系統(tǒng)的一部分它是一個(gè)協(xié)助操作系統(tǒng)內(nèi)核管理用戶態(tài)/客戶方的一個(gè)子系統(tǒng)具體的進(jìn)程為Csrss.exe)。
接下來操作系統(tǒng)通過客戶態(tài)(Kernel32.dll)給Windows子系統(tǒng)(Csrss)發(fā)送一個(gè)新進(jìn)程線程創(chuàng)建的數(shù)據(jù)消息,讓子系統(tǒng)建立自己的進(jìn)程線程管理塊。當(dāng)Csrss接收到該消息時(shí)候執(zhí)行下面的處理:
*復(fù)制一份該進(jìn)程和線程句柄
*設(shè)置進(jìn)程優(yōu)先級(jí)
*分配Csrss進(jìn)程塊
*把新進(jìn)程的異常處理端口綁定到Csrss中,這樣當(dāng)該進(jìn)程發(fā)生異常時(shí),Csrss將會(huì)接收到異常消息
*分配和初始化Csrss線程塊
*把線程插入到進(jìn)程的線程列表中
*把進(jìn)程插入到Csrss的線程列表中
*顯示進(jìn)程啟動(dòng)光標(biāo)
5.開始執(zhí)行初始線程(如果創(chuàng)建時(shí)候指定了線程的CREATE_SUSPENDED狀態(tài)則線程暫時(shí)掛起不執(zhí)行)。到這里進(jìn)程環(huán)境已經(jīng)建立完畢進(jìn)程中開始創(chuàng)建的主線程到這里獲得執(zhí)行權(quán)開始執(zhí)行線程
6.在新進(jìn)程和線程環(huán)境中完成地址空間的初始化(比如加載必須的DLL和庫),然后開始到進(jìn)程入口執(zhí)行。到這步實(shí)質(zhì)是調(diào)用ldrInitializeThunk來初始化加載器,堆管理器NLS表TLS數(shù)組以及臨界區(qū)結(jié)構(gòu),并且加載任何必須要DLL并且用DLL_PROCESS_ATTACH功能代碼來調(diào)用各DLL入口點(diǎn),最后當(dāng)加載器初始化例程返回到用戶模式APC分發(fā)器時(shí)進(jìn)程映像開始在用戶模式下執(zhí)行,然后它調(diào)用線程啟動(dòng)函數(shù)開始執(zhí)行。
到這里操作系統(tǒng)完成了所有的創(chuàng)建工作,我們寫的程序就這樣被操作系統(tǒng)調(diào)用運(yùn)行起來了。