Windows API 提供了多個建立進程的函數,最簡單的是CreateProess()
,該函數建立一個和當前進程具備相同用戶Token的進程。css
若是想要建立和當前進程具備不一樣用戶Token的進程,則須要使用CreateProcessAsUser()
,該函數能夠接受一個Token句柄做爲參數,並建立一個具備該Token的進程。html
其餘建立進程的函數還包括CreateProcessWithTokenW()
以及CreateProcessWithLogonW()
(都是advapi.dll
的導出函數)。CreateProcessWithTokenW()
和函數CreateProcessAsUser()
很類似,可是二者對當前進程Token的權限要求不一樣。CreateProcsssWithTokenW()
須要當前進程中的用戶Token具備 SE_IMPERSONATE_NAME 權限,CreateProcessWithLogonW()
則須要當前進程中具備 SE_INCREASE_NOT_HELD 權限。shell
CreateProcessWithLogonW()
是經過用戶憑證登陸並建立具備對應用戶Token的進程的便捷方式。api
這兩個函數都要經過 RPC 來調用位於 Svchost.exe 中的 SecLogon.dll 來實現實際的進程建立。SecLogon 調用位於內部的SLrCreatePrcoessWithLogonW()
函數,若是該過程順利進行,最終會調用CreateProcssAsUser()
函數。安全
SecLogon 服務被默認配置爲手動啓動,因此當第一次調用 CreateProcessWithTokenW()
以及 CreateProcessWithLogonW()
時,該服務會被啓動。若是該服務啓動失敗,則這兩個函數也沒法執行。經常使用的命令runas
,就調用了這兩個函數。ide
用戶態建立進程函數調用流程圖:函數
上面所描述的4個函數都只能對一個具備的PE文件結構的文件(不須要有.exe拓展)、批處理文件或者16位COM應用進行處理。命令行
對於除了這三種文件外的其餘類型的文件,上述的這些函數不知道如何根據文件拓展名來定位到能夠執行的應用程序 ( 好比:不能根據.txt擴展定位到,能夠啓動 Notepad 來打開該txt文件。調試
可是Windows Shell 提供了這種定位功能,就是對於函數ShellExecute()
以及ShellExecuteEx()
來講,其能夠接受一個非可執行文件做爲輸入,而且能夠根據其拓展名以及位於HKEY_CLASSES_ROOT
中的設置來定位合適的可執行程序來打開這些文件。最後,這兩個函數會經過具備合適的命令行參數的CreateProcess()
函數實現用戶須要的意圖。code
CreateProcess()函數會首先找到咱們指定的可執行文件映像,並建立一個內存區域,稍後會調用其餘函數將該文件映像映射到進程的地址空間中。此外,固然,根據不一樣的文件映像名和參數,該函數還會啓動其餘程序來支持指定文件類型的運行,並從新執行CreateProcess()函數。
以後,如上圖所述,CreateProcess()
函數會調用 CreateProcessInternel()
。該函數完成建立一個用戶模式進程的實際工做。
-->CreateProcessInternel()首先會對傳入的參數進行一些判斷,並將參數或者結構體中的ANSI格式的字符串轉化爲Unicode字符串. -->再作一些初始化和判斷後,會調用NtOpenFile()獲得映像文件句柄,並調用NtCreateSection()來獲得內存區句柄,即咱們所說的進程用戶空間的虛擬地址空間會在這一步完成建立。 -->接着會調用BaseplsProcessAllowed()函數來判斷應用程序是否在受權文件列表中,該函數經過調用 NtOpenKey()函數打開註冊表的 HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Option鍵 -->獲得進程對應的內存區對象句柄後,調用NtQuerySection()函數,返回獲得的節的基本信息(基址、大小、屬性) -->而後對映像文件信息的有效性進行判斷,判斷是否包含DEBUG_PROCESS或者DEBUG_ONLY_THIS_PROCESS,檢查機器類型、子系統版本號、控制檯、GUI等,並經過BaseIsImageVersionOk()判斷鏡像文件版本是否合法。 -->若是建立標誌中包含DEBUG_PROCESS或者DEBUG_ONLY_THIS_PROCESS(即當前處於調試模式中),就加載advapi32.dl並獲取CreateProcessAsSecure()函數的地址。 -->而後調用BaseFormatObjectAttrubutes()將安全屬性結構(關於進程安全、權限方面的信息)格式爲NT對象屬性結構(獲得了對象屬性)。 -->接着調用_DbgUiConnectToDbg()實現經過調用NtCreateDebugObject()函數來建立調試對象,調用DbgUiGetThreadObject()來得到調試對象。
而最終,CreateProcessInternel()
會調用位於NTdll.dll中的NtCreateUserProcess()
來轉換到位於內核模式的執行體模塊中的同名函數中,完成進程建立過程內核部分的行爲。
此外,內核中的 執行體模塊還支持必須繞過Windows API的進程 的建立。例如:native processes,minimal processes,以及 Pico processes 。
像 Smss(the Session Manager) 就是一個 native process,其直接被內核建立,顯然不會使用CreateProcess()
接口,而是直接調用進入執行體模塊的NtCreateUserProcess()
函數中。一樣的,當 Smss 建立 Autochk(檢測磁盤組件) 或者 Csrss (Windows subsystem process) 時,Windows API 也是不可用的。此外,native processes 也不能做爲 Windows應用程序 被建立,由於CreatePrcoessInternel()
會拒絕具備 native subsysem 映像類型的內存映像。而爲了減輕上訴的複雜性Ntdll.dll中存在一個封裝於NtCreateUserProcess()
的函數RtlCreateUserProcess()
。
對於一些內核模式的進程,好比 System process 以及 Memory Compression processes(minimal processes) 以及被 Windows Subsystem for Linux 管理的 Pico procsses 。這些進程的建立經過調用NtCreateProcessEx()
函數(僅僅能被內核態進程調用)實現。
對於被 Pico providers 管理的進程,在建立時,Pico providers會調用一個幫助函數 PspCreatePicoProcess()
,該函數不只能夠建立 minimal process,也會初始化 Pico provider上下文環境。該函數並未導出,僅僅可以被 Pico providers 經過其特殊接口調用。
最後,雖然NtCreateProcessEx()
以及函數NtCreateUserProcess()
是不一樣的系統調用,但這兩個函數最後會調用相同的內部子例程[PspAllocateProcess()以及PspInsertProcess()
] 來實現建立進程的工做。而且,全部的你能舉出來的建立進程的方式,從WMI Powershell cmdlet到 內核驅動,都會在這兩個函數處終止。