Posts

Showing posts from 2016

Intel IA-32 / Intel 64 指令架構 之 指令解碼

Image
引言: ------------------------------------- IA-32 到 Intel 64 架構中 每一條匯編指令也由特定的格式給CPU的指令解碼器,或調試器的反匯編器(disassembler)解析,因而我們可以直觀地知道這些指令,第一層人類有能力看得懂的語言,其中每條指令由以下組件組成: 1. Instruction prefixes( 指令前輟) : ------------------------------------- 指令前輟分為4組: Group 1 : - Lock/repeat prefix : F0h : LOCK prefix F2h : REPNE/REPNZ F3h : REP or REPE/REPZ , F3h prefix 更預設用在POPCNT,LZCNT,ADOX指令上 - Bound prefix : Group 2: - Segment override prefix: 2Eh - CS segment override 36h - SS segment override 3Eh - DS segment override 26h - ES segment override 64h - FS segment override 65h - GS segment override - Branch hints(分支) 2Eh - 分支沒效,只有jcc指令使用 3Eh - 分支有效,只有jcc指令使用 Group 3 : 66h - Operand-size override Group 4 : 67h - address-size override LOCK prefix - 強制向cpu發送LOCK#信號,確保原子操作 Repeat prefix - 重覆執行指定指令 比如movs, cmps, scas, lods, stos, ins, outs Branch hint prefix - 用於提醒CPU,最有可能的執行路徑(分支) Operand/address-size override prefix - 用於尋址時,operand/內存的16bit / 32bit大小切換 2. Opcode

硬件虛擬化 之VMCS結構

/* VMCS結構: * 1. Guest-state area: //客戶機狀態域(如vmware) , 進入VMM時保存 離開VMM時恢復 Cr0, Cr3, Cr4 Dr7 Rsp, Rip 或對應的32位寄存器 所有段選擇子(包括16位選擇子號,段基址,訪問權限,段大小) GDTR,LDTR 以下MSR: IA32_DEBUGCTL IA32_SYSENTER_CS IA32_SYSENTER_ESP & EIP IA32_PERF_GLOBAL_CTRL IA32_PAT IA32_EFER SMBASE寄存器 Activity State(32bit) //CPU活動狀態 0: Active //活動中 1: HLT //正在執行HLT指令 2: ShutDown //由於3次錯誤,導致關機 3: Wait-for-SIPI //等待主虛擬CPU,發送啟動Startup-IPI Interruptibility State(32bit) //可中斷性狀態 bit[0]: Blocking by STI //表示STI屏蔽目前生效中 bit[1]: Blocking by mov SS //表示MOV SS屏蔽目前生效中 bit[2]: Blocking by SMI //表示SMI屏蔽目前生效中 bit[3]: Blocking by NMI //表示NMI屏蔽目前生效中 bit[31:4]: 0 //保留位, 非零會錯誤 Pending debug Exceptions(64/32bit) bit[3:0]: B3-B0 // 每一位表示對應的斷點狀態, DR7沒有設置為會陷入VMM狀態 bit[11:4]: 保留位 // 清零, 非零則VM entry失敗 bit[12]: enabled bp // 表示最小有一個或多個數據斷點或I/O斷點 斷下 並且他已在DR7激活 bit[14

虛擬化技術(VT) 之 內存虛擬化(待續...)

Image
內存虛擬化 -------------------------------------------- 傳統ia-32 cpu只能支持單次的虛擬地址到物理地址的轉換 但在虛擬機中, 虛擬機的虛擬地址->虛擬機的物理地址(其實也算是虛擬地址)->真正的物理地址 EPT -------------------------------------------- 在原有的CR3頁表地址映射的基礎上, EPT引入了EPT頁表來實現另一次映射 這樣GVA->GPA->HPA就能由硬件實現, 提高效率 為什麼要兩次轉換 如下圖所示... 最重點是因為客戶機的物理地址也是虛擬出來的 1. Guest World GVA -+ | CR3 -+-> PD -> PT -> GPA ------------------------------------- 2. Then when EPT is enabled GPA -+ | EPTP-+-> EPT PML4 -> EPT PDPT -> EPT PDT -> EPT PT -> HPA

虛擬化技術(VT) 之 CPU中斷虛擬化

中斷虛擬化 --------------------------------------------------- 物理CPU外部中斷流程: - I/O設備通過I/O APIC 或PIC 發出中斷請求 - 中斷請求經由PCI總線發送到系統總線, 最後目標CPU的Local APIC 接收中斷 - 最後判斷是否處理中斷 虛擬CPU的模疑流程: - 每個VCPU有對應的虛擬Local APIC用於接收中斷, 及虛擬I/O APIC, 虛擬PIC 用於發送中斷(由VMM維護) - 虛擬設備調用 I/O APIC發送中斷, 挑選出目標的虛擬Local APIC - Local APIC 利用事件注入,將其注入到相應的VCPU 虛擬PIC --------------------------------- IA-32 PIC的ICW1~4 和OCW1~3 都是通過I/O 端口訪問, 即I/O操作, 那vt-x 可以很容易實現虛擬化 具體而言,這些接口是通過I/O端口 0x20 0x21 0xA0 0xA1 來訪問, 因此VMM可以設置VMCS I/O Bitmap相應的位, 使客戶機訪問端口時陷入vmm 陷入VMM後, 按照PIC硬件規範 對這些接口的定義,實現相應的邏輯 例如: OCW1 的功能是用於操作IMR寄存器, 控制指定中斷是否被屏蔽 因此VMM可以分析客戶機的OCW1命令, 判斷出是對哪個中斷進行屏蔽 或者解除屏蔽 VMM繼而在內部邏輯中記錄指定中斷是否被屏蔽, 那下一次虛擬中斷就不會被提交 物理上I/O設備與PIC 是電氣連線 , 但虛擬環境中由於設備和PIC都是虛擬的因而兩者的交互為直接的函數調用 虛擬I/O APIC ------------------------------------------------- PIC是用於單核CPU的, 對於多核CPU 必須通過I/O APIC發送中斷 因此對於多CPU平台, 必須實現I/O APIC 與物理上類似, 虛擬I/O APIC 最後也是提交LAPIC 提交對應中斷 虛擬LAPIC ------------------------------------------------- LAPIC 是CPU上一個內部部份, 負責接受中斷, 此外還

虛擬化技術(VT) 之 虛擬CPU結構VCPU 詳解

CPU虛擬化的實現: 硬件虛擬化使用VCPU描述符來描述虛擬CPU(客戶機, 類似操作系統的PCB) 是一個struct (1) VCPU標示信息: 用於標示VCPU的一些基本屬性,如ID號, 這VCPU屬於哪一個客戶機 (2) 虛擬寄存器信息:虛擬的寄存器資源, 在使用intel VT-x 的情況下, 這些內容包括在vmcs中 (3) VCPU狀態信息: 類似進程狀態信息, 標示vcpu當前所處的狀態 , 例如睡眠,運行, 供調度器使用 (4) 額外寄存器或部件信息: 主要指未包含在VMCS的一些寄存器或CPU部件,如浮點寄存器, LAPIC (5) 其他信息: 用於vmm進行優化,或存儲其他信息 由此可見VCPU可以劃分成兩部份,一個是以VMCS為主由硬件使用和刷新部份, 主要是虛擬寄存器部份, 另一個是除VMCS外,由VMM使用和更新的部份 當VMM創建客戶機時, 首先要為他創建VCPU, 整個客戶機的運行實際上可以看作是VMM調度不同的VCPU運行 VCPU的創建: ---------------------------------------------------------------------------- 由於VCPU實際上是一個結構體, 那它的創建實際上就是分配相應大小的內存空間 VCPU涉及很多信息, 通常為多級結構 如第一級可以是各平台通用的內容, 中間包含一個指針指向第二級 物理CPU被供電以後, 硬件會自動將CPU初始化為指定狀態, VCPU的初始化也是一個類似的過程 將VCPU描述符的各個部份分置成可用的狀態, 通常初始化包含如下內容: (1) 分配VCPU標示: 首先標示VCPU屬於哪個客戶機 (唯一標示) (2) 初始化虛擬寄存器: 指初始化VMCS相關域,通常指CPU當前的值 (3) 初始化VCPU 狀態信息: 設置VCPU在調度前需要配置的必要標誌位 (4) 初始化額外部件: 將未被VMCS包含的虛擬寄存器初始化為物理CPU的值,並配置虛擬LAPIC等部份 (5) 始化化其他信息: 根據VMM的實現初始化VCPU的私有數據 VMCS的創建與初始化: ------------------------------------------------------

虛擬化(VT)技術 之 CPU虛擬化探討

VMX運行模式 只有以下兩種: vmx root狀態 -> vmm運行時的狀態 vmx non-root -> 離開vmm後, 普通CPU的狀態 VMEXIT: 引發VMM的時侯 VMENTRY: 離開VMM的時侯 VMCS: VMCS是指一塊4KB內存, 用於VMEXIT 及VMENTRY切換時 更換CPU狀態 一個CPU只可以綁定一個VMCS 使用VMPTRLD 可以將當前運行這一句的CPU 綁定到對應的VMCS 使用VMCLEAR , 解除綁定現在CPU的VMCS VMCS的變換過程: (1) CPU1 上執行VMCLEAR解除綁定 (2) CPU2 上執行VMPTRLD 綁定新的VMCS VMCS主要偏移: (1) 偏移0 : 是VMCS版本標誌 表示VMCS的數據格式的版本 (2) 偏移4 : VMX中止指示, VMEXIT不成功的時侯產生VMX中止, CPU會在此處存入VMX意外中止的原因 (3) 偏移8 : VMCS數據域,該域的格式是隨著CPU不同而有所變化->具體用偏移0判斷哪一種格式 x86 CPU 提供兩條新引入的匯編指令: VMREAD : 讀取VMCS中 指定的域 VMWRITE : 寫入 中指定的域 VT-x 為VMCS數據域每一個字段也定義了相應的 因此令以上兩條指令成立 具體VMCS數據域包含以下六大信息 (1)客戶機狀態域: 進入VMM時保留, 離開VMM時取回 (2)宿主機狀態域: 進入VMM時取回, 離開VMM時保留 (3)VM-Entry控制域: 控制VM-Entry的過程 (4)VM-Execution控制域: 控制處理器在vmx non-root模式時的行為 (5)VM-Exit控制域: 控制vm-exit的過程 (6)VM-Exit數據域: 提供vm-exit的原因及相關信息, 注意這是只讀(read-only)的 (1) 客戶機狀態域: 用於保存CPU在NON-ROOT模式下的CPU上下文(Context) VM-Entry時會提取恢復到CPU, VM-Exit時會保留 它保存了段寄存器, CR3, IDTR, GDTR等寄存器 CPU通過他們來切換實現客戶機地址空間與VMM地址空間的切換 客戶機狀態域並不包

Windows內核安全之 線程調度

Image
線程一個比較重要的概念是, CPU中永遠調度的是線程, 而不是進程, 而進程的切換完全是源於是否同一個CR3寄存器, 詳見SwapContext的實現 以下先列出KTHREAD對象 內核中對線程優先級(priority) 分別使用0~31表示 實時(Real-time)類別: 16~31 動態(Dynamic)類別: 1~15 系統(System)類別: 0 線程在內核的執行體層(Executable Layer)中 使用以下6種優先級 實時(Realtime) 高(High) 普通之上(Above normal) 普通(normal) 普通之下(Below normal) 低(Low) 執行體層透過一個數組PspPriorityTable 轉換成真正的表示 以下是他們的對應關係 實時(Realtime) 24 高(High) 13 普通之上(Above normal) 10 普通(normal) 8 普通之下(Below normal) 6 低(Low) 4 進程的對象EPROCESS結構中 BasePriority 指定一個進程中所有線程的預設優先級 可以通過KeSetPriorityAndQuantumProcess 或 KeSetBasePriorityThread 函數設置優先級 KTHREAD中的Priority域記錄一個線程當前實際優先級, 他一般是在BasePriority基礎上提升到某個增量 Priority不會超過0~15 內核通過調用KiComputeNewPriority計算並調整非實時的線程優先級 我們可以使用NtSetInformationProcess為進程的基礎優先級進行微調, 所以一條線程在執行體中的值並非數組中指定的值 優先級的提升: ------------- 由於每個線程優先級都有對應的鏈表維護著相同優先級的線程 方便調度 所以優先級的提升, 一定是在加入鏈表之前 內核中不小函數的參數使用KPRIORITY Increment進行提升 如: KeInsertQueueApc KePulseEv

Windows安全 之 內存映射文件(Section對像)MmCreateSection與MmMapViewOfSection 流程分析

Image
MmCreateSection 內存區(Section)內核對像有兩種,但都是基於分頁內存的: 一種是基於頁面文件的 一種是基於其他文件,以文件空間作為基礎的 如EXE在硬盤上的空間 MmCreateSection主要目的: 1. 填充CONTROL_AREA對像 2. 填充SEGMENT對像 3. 調用ObCreateObject創建Section內核對像 4. 返回Section內核對像 SEGMENT是真正描述映射區域的對像 , 內核函數MmCreateSection中有三種創建方式: 1. MiCreatePagingFileMap //以PageFile(頁面文件)為基礎的文件共享 2. MiCreateImageFileMap //以可執行映像作文件共享 3. MiCreateDataFileMap //以普通數據文件作為基 p.s. 後兩者雖表面內核文件對像, 從函數內部邏輯可發現, 如果映射同一個文件時, Section對像會共用同一個Segment對像 由於Section對像的創建完全是建基於SEGMENT對像, 因此探討SEGMENT對像才是正確方向 了解共享實現 SEGMENT(段對像,分配在分頁內存): 1. 分配的共享空間頁面總數量大小的MMPTE陣列緊隨著SEGMENT對像(用於建立映射視圖時) 2. 指向CONTROL_AREA指針(CONTROL_AREA, 分配在非分頁內存,即物理內存, 它亦會指向SEGMENT對像, 建立互指的關係) 3. 記錄對應節中的所有頁面的數量 4. 全部MMPTE最終指向節的起始地址 建數內部會再次創建真正的: CONTROL_AREA(控制區對象,分配在分頁內存) 1. 指向文件對像指針 2. 尾隨著多個SUBSECTION對像 (指PE中各個節的起始地址,使用Segment的MMPTE進行初始化->再讓VAD中會使用SubSection) 3. SUBSECTION形成鏈表,其中一個指針會指回CONTROL_DATA SubSection結構如下: typedef struct _SUBSECTION { PCONTROL_AREA ControlArea; PMMPTE SubsectionB

軟件調試(12) - Win32堆,CRT堆簡介及堆溢出攻擊及系統檢測溢出方案

Win32堆與CRT堆 ------------------------------------------------ 堆分配函數: malloc / HeapAlloc/ new 堆的基本運作: 內存管理器(Memory Manager)把一塊較大的內存空間,委托給堆管理器(Heap Manager)來管理,堆管理器將大塊內存分割成不同大小的很多個小塊來滿足應用程序的需要 而實現內存委托的一系列函數,稱為池管理器(Pool Manager) Windows在創建進程時,加載器函數執行進程用戶態初始化階段會調用RtlCreateHeap函數為新的進程創建第一個堆 稱為默認堆 默認堆: 由LdrpInitializeProcess所調用RtlCreateHeap建立 此時新進程中只有EXE模塊和NTDLL模塊,EXE模塊中的用戶代碼還未執行,創建好的堆句柄會存放在PEB中ProcessHeap字段, 與棧類似也有HeapSegmentReserve和HeapSegmentCommit兩個字段來決定默認堆的保留大小和提交大小 分配私有Win32堆: 用戶透過HeapCreate函數創建自己的堆 函數原型: HANDLE WINAPI HeapCreate( _In_ DWORD flOptions, _In_ SIZE_T dwInitialSize, _In_ SIZE_T dwMaximumSize ); 刪除則是調用: BOOL WINAPI HeapDestroy( _In_ HANDLE hHeap ); 堆列表: 每個進程的PEB結構以列表方式記錄當前進程的所有堆句柄: NumberOfHeap 是堆總數 ProcessHeaps 每個堆的句柄,它是一個數組 MaximumNumberOfHeaps 可分配堆總數 如果NumberOfHeap == MaximumNumberOfHeaps 堆管理器則增大MaximumNumberOfHeaps 的值並重新分配ProcessHeaps 分配堆空間: 使用HeapAlloc可以在指定堆中分配空間 函數原形: LPVOID WINAPI HeapAlloc( _In_ HANDLE hHeap, _In_ DWORD dwFlags,

軟件調試(11) - 棧安全檢查,溢出及緩沖區溢出

用戶態及內核態棧 -------------------------------------------- TSS會記錄了不同優先級所使用的棧的基本信息 TSS+0x4 到 TSS+0x28的24字節是用來記錄棧的段信息和棧指針ss:esp 每個Win32線程都有兩個棧: 一是用戶態棧,記錄在_TEB->_NT_TIB 一是內核態棧,記錄在_KTHREAD 他們記著線程棧的詳細資料 用戶態棧- 1MB x86內核態棧-12KB x64內核態棧-24KB 考慮到gui線程在調用gdi服務時通常需要更大的棧段空間,所以在一個線程被轉為GUI線程後,內核態棧一般會被替換成一個更新的新棧 -------------------------------------------- 內核棧的創建: PspCreateThread是Windows內核態用於創建線程的一個重要內部函數 不論是PspCreateSystemThread或NtCreateThread 由PspCreateThread創建內核態棧,大小總是默認大小的內核態棧 但Windows線程在第一次調用Win32子系統服務時,將其轉變為GUI線程->轉化後系統的PsConvertToGuiThread函數會為該線程重新建立一個棧,然後使用KeSwitchKernelStack切換到新的棧,新的棧是可以改變大小的,稱為大內核態棧(Large Kernel Stack) 棧大小的最大值記錄在MmLargeStackSize 在一個線程被轉變為GUI線程 其KTHREAD結構的LargeStack會改為1 同時其Win32Thread字段會由0變為非0 棧段不會立即增大,在需要增大時調用MmGrowKernelStack函數來增長棧 ------------------------------------------------------- 用戶態棧的創建 初始線程: CreateProcess->NtCreateProcess->BaseCreateStack(調用NtCreateThread前)初始化用戶態棧 初始線程外: CreateThread / CreateRemoteThread->BaseCreateSt

軟件調試(10) - 棧和函數調用

用戶態及內核態棧 -------------------------------------------- TSS會記錄了不同優先級所使用的棧的基本信息 TSS+0x4 到 TSS+0x28的24字節是用來記錄棧的段信息和棧指針ss:esp 每個Win32線程都有兩個棧: 一是用戶態棧,記錄在_TEB->_NT_TIB 一是內核態棧,記錄在_KTHREAD 他們記著線程棧的詳細資料 用戶態棧- 1MB x86內核態棧-12KB x64內核態棧-24KB 考慮到gui線程在調用gdi服務時通常需要更大的棧段空間,所以在一個線程被轉為GUI線程後,內核態棧一般會被替換成一個更新的新棧 -------------------------------------------- 內核棧的創建: PspCreateThread是Windows內核態用於創建線程的一個重要內部函數 不論是PspCreateSystemThread或NtCreateThread 由PspCreateThread創建內核態棧,大小總是默認大小的內核態棧 但Windows線程在第一次調用Win32子系統服務時,將其轉變為GUI線程->轉化後系統的PsConvertToGuiThread函數會為該線程重新建立一個棧,然後使用KeSwitchKernelStack切換到新的棧,新的棧是可以改變大小的,稱為大內核態棧(Large Kernel Stack) 棧大小的最大值記錄在MmLargeStackSize 在一個線程被轉變為GUI線程 其KTHREAD結構的LargeStack會改為1 同時其Win32Thread字段會由0變為非0 棧段不會立即增大,在需要增大時調用MmGrowKernelStack函數來增長棧 ------------------------------------------------------- 用戶態棧的創建 初始線程: CreateProcess->NtCreateProcess->BaseCreateStack(調用NtCreateThread前)初始化用戶態棧 初始線程外: CreateThread / CreateRemoteThread->BaseCreateSt

軟件調試(9) - 深入探討Windows結構化異常(SEH)底層實現

r3/r0一樣, FS:[0] 保存著SEH的鏈表頭 應用層: TEB與TIB結構 TEB中的起始處是指向TIB的地址,TIB第一個字段位exceptionList即為鏈表表頭 內核層 KPCR與TIB結構 KPCR->TIB TIB的ExceptionList字段 ------------------------------------------------------- 該字段位於TIB的起始處 typedef struct _EXCEPTION_REGISTERATION_RECORD{ struct _EXCEPTION_REGISTERATION_RECORD *next; //0xFFFFFFFF代表最後一個節點 ULONG handler; //異常處理器的地址(需符合seh函數原形) } EXCEPTION_DISPOSITION SehHandler(_EXCEPTION_RECORD *exceptionRecord, //處理的異常 void * EstablisherFrame, //異常函數的EBP _CONTEXT *contextRecord, //線程上下文 void * DispatcherContext //分發函數 ) TIB自身不在棧中,而SEH鏈表則是存在棧中 登記異常函數 ------------------------------------------------------- push seh_handler //處理函數地址 棧空間: push FS:[0] //舊的鏈表節點處理器地址 FS:[0] move FS:[0],ESP //登記新結構 SEH_HANDLER ..... mov esp,dword ptr fs:[0] //保存下一個結構地址 pop dword ptr fs:[0] //將下一個結構的地址變成鏈表頭 用戶態版本RtlDispatchException ------------------------------------------------------- (內核中的異常分發:修改EIP到R3的KiUserExceptionDispatcher->)RtlD

軟件調試(8) - 探討從應用層到內核層的中斷與異常管理

硬件異常 IDT 在idtr讀取idt表基址 ------------------------- 門描述符: 任務門 - 用於任務切換 里面包含用於選擇任務狀態段(tss)的段選擇子 中斷門 - 用於描述中斷處理例程入口 陷阱門 - 用於描述異常處理例程入口 任務門: 描述的是一個TSS段->CPU要做的是切換到這個TSS段所代表的線程,然後開始執行這個線程,TSS段是用來保存任務信息的一段內存區,其格式由CPU定義 Windows會為每個CPU創建3-4個tss 1: 處理NMI 2: 處理#DF(double fault) 異常中再異常 3: 處理機器檢查異常 軟件異常 -------------------------- EXCEPTION_RECORD 結構 typdef struct _EXCEPTION_RECORD{ DWORD ExceptionCode //異常代碼 DWORD ExceptionFlags //異常標志 struct _EXCEPTION_RECORD* ExceptionRecord; //相關的另一個異常 PVOID ExceptionAddress; //異常發生地址 DWORD NumberParameters; //參數數組元素 ULONG_PTR ExceptionInformation[EXCEPTION_MAXIMUM_PARAMETERS]; //參數數組 }EXCEPTION_RECORD, *PEXCEPTION_RECORD; #define EXCEPTION_BREAKPOINT STATUS_BREAKPOINT #define EXCEPTION_SINGLE_STEP STATUS_SINGLE_STEP 登記CPU異常 --------------------------- KiTrapXX例程在完成針對本異常的動作後,會調用CommonDispatchException->KiDispatchException 並通過寄存器將如下信息傳送到函數 1. 異常代碼->EAX 2. 異常指令地址->EBX 3. 其他信息作為附帶參數(最多3個),EDX(參數1),ESI(參數2),

軟件調試(7) - 調試體系之內核調試原理

內核調試器通過內核調試引擎 控制或調試內核 內核其他部份->內核調試引擎->內核調試器 調試器通過內核調試協議 訪問和控制目標系統 內核調試API: KdAPI - 類似遠程調用方式訪問內核 與系統內核的接口函數 與調試器通信函數 斷點管理 - 使用KdpBreakpointTable記錄斷點 內核調試api - 提供調試信息給內核調試引擎 系統內核控制函數 - KdEnterDebugger 與 KdExitDebugger 管理函數 - KdEnableDebugger 與KdDisableDebugger ETW支持函數 - event log... 驅動程序更新服務 - 本地內核調試支持(XP後) kdcom.dll 負責通信部份 收/發數據包 - KdSendPacket - KdReceivePacket 接收電源狀態變化 - KdD0Transition ,喚醒系統用 - KdD3Transition ,休眠時用 內核調試引擎初始化: BIOS->Harddisk引導程式->執行NTLDR.exe->CPU初始化->切換保護模式->啟用分頁機制->通過配置boot.ini得到windows系統的系統目錄並加載系統內核文(ntoskrnl.exe)先檢查他的導入表並加載依賴文(包括內核調試通信模塊KDCOM.dll)->讀取注册表的hive->加載其中定義的啟動類型的驅動程序->完成所有工作->找到內核文件的PE文件頭找到入口函數->kISystemStartup->進入初始化三部曲-> 1. 調用HalInitializeProcessor() 初始化CPU 2. 調用KdInitSystem 初始化內核調試引擎 3. 調用KiInitializeKenrel開始內核初始化 KiInitializeKenrel->KeInitializeThread -> ExpInitializeExecutive() ExpInitializeExecutive進行大量工作包括進程管理器初始化: 進程管理器初始化: - 定義進程/線程內核對象類型 - 建立記錄系統中所有進程的鏈