現代系統核心報告 第三組 范綱烜995202029張柔止995202059 陳浩宇995202032呂兆威995202037 鄭清懷995202065張靖裕995202055 李怡臻995202078楊郁莉995202084 Chapter 3 windows行程與緒程 Windows 行程(process) 緒程(thread) 行程(process) 行程(process) 行程定義了一個執行環境 位置空間(address space) 程式碼(text) … 行程記憶體結構 行程的建立 建立一個執行體行程物件 建立一個初始緒程 為初始緒程建立一個堆疊 設置初始環境 緒程參予系統的排程 行程狀態 行程控制表 每一個行程在作業系統之中都對應著一個 行程控制表(Process Control Block) 行程控制表(續) 行程狀態(Process state ) 程式計數器(Program counter) 指明該行程接著要執行的指令位址 CPU暫存器(CPU registers) 可以是new、ready、running、waiting或halted等 其數量和類別,完全因電腦架構而異 CPU排班法則(CPU scheduling information) 包括行程的優先順序 (Priorlty)、排班佇列(scheduling queue)的指標以及其它 的排班參數 行程控制表(續) 記憶體管理資訊(Memory-management information) Accounting information 基底暫存器(base register)和限制暫存器(limit register),分頁表(Page table)值的資訊統所使用的記憶系統區段表(segment table)。 CPU和實際時間的使用數量、時限、帳號工作或行程號碼 輸入/輸出狀態資訊(I/O status information) 配置給行程的輸入/輸出裝置,包括開啟檔案的串列 等等 多行程模型 Process switch 行程間通訊 (Inter-Process Communication ) 行程間通訊(IPC,Inter-Process Communication),指至少兩個行程 或執行緒間傳送資料或訊號的一些技術或方法。 shared memory Pipe Socket Thread Thread組成包含以下元素: 程式計數器 CPU暫存器 堆疊空間 執行緒ID狀態 Thread 在同一個Process中,不同Thread之間可以 彼此共享資源: 程式碼區域 資料區域 作業系統資源(EX:openfile,signal) 行程與緒程 一個Process可以有多個Thread。 同一個Process內的Thread使用相同的 Memory Space,這些Thread各自擁有其 Stack。 User-level thread User-level threads implement in user-level libraries, rather than via systems calls, so thread switching does not need to call operating system and to cause interrupt to the kernel. In fact, the kernel knows nothing about user-level threads and manages them as if they were single-threaded processes. Present by 995202059 張柔止 User-level thread Advantages: 1. User-level threads does not require modification to operating systems. 2. Simple Representation & Management 3. Fast & Efficient 4. 應用程式可採用適合自己特點的緒程選擇演算法, 並根據應用程式的邏輯來定義緒程的優先層級缺點 。 Disadvantages: 增加應用程式碼的複雜性。 Present by 995202059 張柔止 kernel-level thread Instead of thread table in each process, the kernel has a thread table that keeps track of all threads in the system. Operating Systems kernel provides system call to create and manage threads. Present by 995202059 張柔止 kernel-level thread Advantages: 核心會妥善處理好緒程之間共用處理器的資源 分配問題,而無需考慮緒程之間的控制權轉換 。 Disadvantages: The kernel-level threads are slow and inefficient. Significant overhead & increased in kernel complexity. Present by 995202059 張柔止 Multithreaded programming 在支援kernel-level thread的環境中,行程 可以容納多個緒程,這導致了多緒程程式 設計(Multithreaded programming)模型。 在此模型中,緒程間的通訊十分方便及高 效率。但是也容易造成緒程間因同步不正 確,而導致資料被破壞。 Present by 995202059 張柔止 Thread scheduling algo 衡量準則: 1. 公平性 2. CPU被有效利用 FIFO: 若緒程的執行時間長短不一,則實際 效果可能非常不公平 Random: 打斷緒程執行時,會存在固有的緒 程切換負擔 Priority: 高優先權的緒程可能霸佔處理器資源 Present by 995202059 張柔止 Thread & process Present by 995202059 張柔止 3.3 Windows 中行程和緒程資料結 構 3.3.1核心層的行程和緒程物件 3.3.1核心層的行程和緒程物件 在Kernerl中,Process 和 Thread 都有相對 應的資料結構 一個KPROCESS代表一個行程,每個行程都 會一個KPROCESS EPROCESS會建立KPROCESS 3.3.1核心層的行程和緒程物件KPROCESS Define typedef struct _KPROCESS { 接下來欄位與proecss的 context swithch 有關 DISPATCHER_HEADER Header; //表示整個Pocess是一個Dispatcher, ULONG_PTR DirectoryTableBase[2]; //1.指向Process的分頁目錄表位置 所以proecss是可以等待的 2.指向這個Process的Hyper Space LIST_ENTRY ProfileListHead; //是用來參與效能分析時,用來加入到全域效能分析清單中 ,行成當中的一個節點 分頁目錄表位置 Dispatcher object(chap5.4) //以下參數皆是為了Intel X86設計 共有六種-在這裡會提到KPROCESS 與KTHREAD KGDTENTRY LdtDescriptor; //是這個Process的LDT(區域描述表) KPROCESS KIDTENTRY Int21Descriptor;//為了相容DOS允許存取DOS系統功能 在行程建立時,他會被設定為無信號,當行程(Process)結束時, USHORT IopmOffset; //指定IOPM,(I/O權限表), 他會變成有信號。 kernel透過IOPM控制user mode的 I/O存取 每個行程都會有一個KPORCESS物件,其內容欄位表示目 UCHAR Iopl;所以另外一個thread在等待某個process時就可以被通知喚醒該thread //定義了I/O的優先層級 前的Process狀況。 Unused; KTHREAD BOOLEAN 狀況是與KPROCESS相同但是角色變成THREAD等待THREAD的信號。 volatile KAFFINITY ActiveProcessors; // 記錄Process正在那些處理器上執行 } KPROCESS, *PKPROCESS, *PRKPROCESS; 3.3.1核心層的行程和緒程物件-KPROCESS typedef struct _KPROCESS { LIST_ENTRY 接下來欄位與proecss的 ReadyListHead; //是一個雙向串列的表頭,記錄在這個process 發生clock interrupt 有關 SINGLE_LIST_ENTRY SwapListEntry; 中已經就緒但未加入全域就緒串列的thread 換入=>透過這個欄位加入到KiProcessInSwapListHead(皆為單串列) 間 PVOID //指向處理Ctrl+C中斷的函式,僅用於VDM ULONGVdmTrapcHandler; UserTime;//記錄在使用者模式下所花時 (Virtral Dos Machine)的環境下執行16位元程式。 間 //換出=>透過這個欄位加入到KiProcessOutSwapListHead ULONG KernelTime;// 記錄在核心模式下所花時 當process被換出記憶體後,這個process所屬的thread如果就緒後, 他就會被掛到這個串列中,接著要求換入這process LIST_ENTRY ThreadListHead;//是串列的開頭,主要包含了這個Process 目前所有的thread 我們也可以從這邊看 會等於thread中的值和,但是只會當一個 例如用途:將串列中的每個thread加入到全域就緒thread中 Process->State=ProcessInMemory; 出Process與thread之間的從屬關係。 thread結束時才會更新到Process這兩個的值 NextEntry=Process->PeadyListHead.Flink; While(NextEntry != &Process->ReadyListHead){ KSPIN_LOCK ProcessLock; //這是一個spin lock的物件。用來保護Process中的成員。 Thread=CONTAIN_RECORD(NextEntry, KTHREAD, WaitListEntry); RemoveEntryList(NextEntry); 指出這個Process可以在哪些處理器上執行。 Thread->ProcessReadyQueue=FALSE; KiReadyThread(Thread);//加入全域就緒thread的finction NextEntry=Process->ReadyListHead.Flink; KAFFINITY Affinity;// } } KPROCESS, *PKPROCESS, *PRKPROCESS 3.3.1核心層的行程和緒程物件-KPROCESS typedef struct _KPROCESS { SCHAR union { BasePriority; //process中的thread他的基本優先層級 SCHAR //指定process中的thread基本配量重置值(在windows為6) structQuantumReset; { UCHAR State;//說明是否在記憶體中,有六種可能狀態 LONG AutoAlignment : 1;//用於記憶體對齊設置(intel x86並無此設置) 1.ProcessInMemory2. ProcessOutOfMemory3. ProcessInTransition LONG DisableBoostProcessInSwap6. : 1; 4. ProcessOutTransition5. ProcessOutSwap Summry UCHAR ThreadSeed; //在一個多處理器的環境下,每個thread都有一個優先選擇的處理 LONG DisableQuantum : 1;//與thread過程中的優先層級提昇和配量分配有關 器 Process主要會紀錄的資訊分成下面兩類 LONG ReservedFlags : 29; UCHAR PowerState; //用於電源狀態管理 1.與行程的記憶體環境相關 }; UCHAR IdealNode; //一個process優先選擇的處理器節點 2.與其Thread 相關 LONG ProcessFlags; BOOLEAN Visited; }; ULONG_PTR StackCount; //紀錄了目前porcess中有多少thread的堆疊放至於記憶體 中 LIST_ENTRY ProcessListEntry;//將目前系統中有活動中的thread的process串成一個 串列 } KPROCESS, *PKPROCESS, *PRKPROCESS 3.3 Windows 中行程和緒程資料結 構 3.3.1核心層的行程和緒程物件 3.3.1核心層的行程和緒程物件KTHREAD(Part1) typedef struct _KTHREAD { DISPATCHER_HEADER Header; //跟Process一樣是發送器物件,所以是可以被等待的 LIST_ENTRY MutantListHead;//指向一個串列開頭, PVOID PVOID PVOID PVOID 這個串列包含了所有該thread的突變體物件 InitialStack;//原始堆疊的位置(高位置) StackLimit;//堆疊的最低位置 KernelStack;//紀錄了真正核心呼叫堆疊的開始位置,他會比InitalStack還低一點, 因為中間還要紀錄浮點處理器保存區和一個例外陷阱框架。 StackBase; //紀錄目前的堆疊基底位置,初始化石他會與InitialStack相同。 KSPIN_LOCK ThreadLock; //跟Process一樣的功能類似,是用來保護Thread中的資料成 } KTHREAD, *PKTHREAD, *PRKTHREAD; 3.3.1核心層的行程和緒程物件KTHREAD(Part1) typedef struct _KTHREAD { union ULONG union {{ ContextSwitches;//紀錄了這個thread進行了幾次切換 KAPC_STATE ApcState; //指向目前Thread所屬的Preocess的KPROCESS結構 volatile UCHAR State; //紀錄了目前thread的狀態 PKWAIT_BLOCK WaitBlockList; //用來指向PKWAIT_BLOCK為元素的串列, struct {Alertable; //說明Thread是否可以被喚醒,用於等待時, 這個物件主要是要指出哪個thread在等待分派器物件, BOOLEAN 同時每個分派器物件也會紀錄哪些thread正在等待他。 UCHAR ApcStateFill[KAPC_STATE_ACTUAL_LENGTH]; 如果他為TRUE就可以被喚醒 PKGATE GateObject; //紀錄正在被等待的閘道物件,這兩個不會同發生, BOOLEAN ApcQueueable; //是否可以插入APC BOOLEAN WaitNext; //TRUE:表示他要呼叫等待函式,所以發出訊號就可以馬上呼叫, 所以構成一個union共用指標記憶體。 不需要解除排程器鎖。 volatile UCHAR NextProcessor; }; UCHAR NpxState; volatile UCHAR DeferredProcessor; //處理器的排程選擇 KIRQL WaitIrql; UCHAR//要與WaitNext合用,當為TRUE時紀錄下先前的IRQL AdjustReason; UCHARSCHAR WaitReason; //紀錄下為什麼會需要等待的理由。 AdjustIncrement; //這兩個是給優先層級調整原因及調整量 LONG_PTR WaitStatus;//紀錄等待的結果。 }; KPROCESSOR_MODE WaitMode;//紀錄下當他進入等待時是在kernel mode or user m }; KSPIN_LOCK ApcQueueLock; //是一個spinLock 用於保護APC佇列的操作 } KTHREAD, *PKTHREAD, *PRKTHREAD; 3.3.1核心層的行程和緒程物件KTHREAD(Part2) typedef struct _KTHREAD { union SCHAR UCHAR { Priority; EnableStackSwap; //定義了這Thread的優先層級,在這裡 //布林值,指出是否允許換出到外部記憶體 這是可以變動的。 SCHAR volatile LIST_ENTRY UCHAR BasePriority; SwapBusy; WaitListEntry; //靜態的優先層級,初始值是所屬Process的BasePriority值, //布林值,指出thread是否正在進行context //當Thread在等待執行時,他會作為一個節點 swap 加入 可以 透過KeSetBasePriority函式設定。 到某個序列中,也就是KPROCESS中的 BOOLEAN Alerted[MaximumMode]; //指定該thread在哪種警告模式下可以喚醒。 WaitListEntry為起始的串列 SCHAR PriorityDecrement;//紀錄他的優先層級的變動值。 在WRK中,警告模式只有使用者模式與核心模式,所以也就是指出thread在這兩個模式 SINGLE_LIST_ENTRY SwapListEntry; //當thread的核心堆疊要換入時, 優先層級在Windows分成兩層: 下是否可以喚醒 插入到 0~15:普通thread的優先層級 KiStackImSwapListHead 16~31:即時thread的優先層級 ,這兩個區域彼此事不會互相跨越的。 當Thread處於DefferedReady的狀態時, 他會將SwapListEntry插入到 CHAR Saturation;//說明這個Thread相對於process的基本優先層級,是否超越者個 區 間的一半,值為 0,1,-1 DefferedReadyList Head串列中 }; PRKQUEUE Queue; //是一個佇列發送器(分派器),如果不為NULL表示目前正處理此佇列 ULONG WaitTime; //紀錄了一個Thread進入等待時刻的時間點, 好讓平衡集管理員可以根據這選項做出相對應的決策 } KTHREAD, *PKTHREAD, *PRKTHREAD; 3.3.1核心層的行程和緒程物件KTHREAD(Part2) typedef struct _KTHREAD { KTIMER Timer;//是一個附在thread上的計時器 union { 在實做可逾時的等待函式時( KeWaitForSingleObject or struct { KeWaitForMultiple )可以用到 SHORT union { KernelApcDisable; SHORT SpecialApcDisable; //分別為16位元,0:表示不禁止APC,負數表 struct { 示禁止 LONG AutoAlignment : 1; APC,只要因為多種因素造成要禁止他就會不停 LONG DisableBoost : 1;//這兩個欄位是繼承Kprocess中的同名欄位, 加上負值,直到消除時才將這個因素造成的負值 所以用途相同。 補回,直到變成0為止。且只有當兩個欄位都為0 LONG ReservedFlags : 30; 時,才允許插入APC。 }; }; LONG ThreadFlags; ULONG CombinedApcDisable; }; }; } KTHREAD, *PKTHREAD, *PRKTHREAD; 3.3.1核心層的行程和緒程物件KTHREAD(Part2) typedef struct _KTHREAD { union { LIST_ENTRY QueueListEntry; //紀錄了當thead處理一個佇列項目時, KWAIT_BLOCK WaitBlock[THREAD_WAIT_OBJECTS + 1];//有4個KWAIT_BLOCK成員的陣列 他加入到佇列物件的thread串列中的節點位址 struct { WaitBlock其實是一個內建陣列 UCHAR WaitBlockFill0[KWAIT_BLOCK_OFFSET_TO_BYTE0]; BOOLEAN SystemAffinityActive; 如果Thread等待的物件數量小於4 }; =>無須另外分配KWAIT_BLOCK物件記憶體 struct { 如果Thread等待的物件數量大於4 UCHAR WaitBlockFill1[KWAIT_BLOCK_OFFSET_TO_BYTE1]; CCHAR PreviousMode; =>需要另外分配 }; struct { UCHAR WaitBlockFill2[KWAIT_BLOCK_OFFSET_TO_BYTE2]; UCHAR ResourceIndex; }; struct { UCHAR WaitBlockFill3[KWAIT_BLOCK_OFFSET_TO_BYTE3];//專門用於可等待的計時器物件 UCHAR LargeStack; }; } KTHREAD, *PKTHREAD, *PRKTHREAD; 3.3.1核心層的行程和緒程物件KTHREAD(Part3) typedef struct _KTHREAD { PKTRAP_FRAME TrapFrame; //紀錄控制流程狀態data structure PVOID CallbackStack; //包含thread的callback stack address 當thread從kernel mode呼叫到user mode時使用 PVOID ServiceTable; //指向該thread使用的系統服務表 UCHAR IdealProcessor; //指明在多處理器的機器上,該thread的理想處理器 BOOLEAN Preempted; //表該thread是否被高優先層級的thread搶佔了 BOOLEAN ProcessReadyQueue; //表一個thread是否在所屬的行程 KPROCESS 物件的ReadyListHead串列中 BOOLEAN KernelStackResident; //說明該thread的核心堆疊是否駐留在記憶 體中 } KTHREAD, *PKTHREAD, *PRKTHREAD; 3.3.1核心層的行程和緒程物件KTHREAD(Part3) typedef struct _KTHREAD { KAFFINITY Affinity; //指定了thread的處理器親和性 KAFFINITY UserAffinity; //是thread的使用者親和性 PKPROCESS Process; //指向thread的行程物件 UCHAR ApcStateIndex; //指名目前APC狀態在ApcStatePointer欄位中的索引 PKAPC_STATE ApcStatePointer[2]; //陣列元素的型別是指向KAPC_STATE的 指標 兩個元素分別指向thread物件的ApcState和SavedApcState union { KAPC_STATE SavedApcState; struct { ...... };*PKTHREAD, }; } KTHREAD, *PRKTHREAD; 3.3.1核心層的行程和緒程物件KTHREAD(Part3) typedef struct _KTHREAD { PVOID Win32Thread; //指向由Windows子系統管理的區域 union { KAPC SuspendApc; }; union { KSEMAPHORE SuspendSemaphore; struct { UCHAR SuspendSemaphorefill[KSEMAPHORE_ACTUAL_LENGTH]; ULONG SListFaultCount;}; }; } KTHREAD, *PKTHREAD, *PRKTHREAD; 3.3.1核心層的行程和緒程物件KTHREAD(Part3) typedef struct _KTHREAD { LIST_ENTRY ThreadListEntry; //表一個雙串列上的節點 PVOID SListFaultAddress; //與user mode互鎖單串列POP操作的錯誤處理有 關 } KTHREAD, *PKTHREAD, *PRKTHREAD; 3.3.1核心層的行程和緒程物件KTHREAD(Part3) 從以上介紹的KPROCESS和KTHREAD的資料結構可看出 核心層的process和thread object只包含了系統資源管理和多控制 流程並行執行所涉及的基本資訊 不含與應用程式相關聯的資訊(ex: process映像檔案和thread啟動 函式位址) 3.3.1核心層的行程和緒程物件KTHREAD(Part3) Process Object 提供了thread的基本執行環境 包含process address space和一組process範圍內公用的參數 Thread Object 提供了為參與thread 排程而必須的各種資 訊及其維護控制流程的狀態 EPROCESS Define 995202078 李怡臻 Outline Introduction EPROCESS Structure Introduction 每一個Windows process都是由一個 Executive process (EPROCESS) block來表示。而一個 process可能有多個thread,這些thread則由一 個executive thread (ETHREAD) block來表示。 EPROCESS不僅包括了進程(Process)的許多 屬性,還包擴了許多指向其他數據結構的 指針,其中包含了大量有用的信息。 EPROCESS Structure(1/4) typedef struct _EPROCESS { KPROCESS Pcb; EX_PUSH_LOCK ProcessLock; LARGE_INTEGER CreateTime; LARGE_INTEGER ExitTime; EX_RUNDOWN_REF RundownProtect; HANDLE UniqueProcessId; LIST_ENTRY ActiveProcessLinks; SIZE_T QuotaUsage[PsQuotaTypes]; SIZE_T QuotaPeak[PsQuotaTypes]; SIZE_T CommitCharge; SIZE_T Commit ChargeLimit; SIZE_T Commit ChargePeak SIZE_T PeakVirtualSize; SIZE_T VirtualSize; LIST_ENTRY SessionProcessLinks; PVOID DebugPort; PVOID ExceptionPort; PHANDLE_TABLE ObjectTable; EX_FAST_REF Token; EPROCESS Structure Element Purpose KPROCESS Pcb PCB 包含process分頁資料的指標、屬於此process的kernel thread列表、process預設的權限以及process全部的kernel time 和user time,系統內部一個行程的KPROCESS位址與 EPROCESS位址是相同的。 EX_PUSH_LOCK ProcessLock 為push lock 物件,用於保護EPROCESS中的資料成員。 (push lock:可以在多個reader中共享,只有在Thread需要寫時 才需要排他性) LARGE_INTEGER CreateTime / ExitTime Process的建立時間和結束時間。 EX_RUNDOWN_REF RundownProtect 屬於Process的停止保護鎖,當一個Process最後被銷毀時, 他要等到其他Process和Thread已經釋放了此鎖,才可以繼 續進行。 HANDLE UniqueProcessId Process中的唯一編號,在Process建立時設定。 LIST_ENTRY ActiveProcessLinks 為雙串列結點,在Windows中所有活動的Process都連接在一 起,形成一個雙串列。 SIZE_T QuotaUsage / QuotaPeak 為陣列[3]紀錄Process的記憶體使用量和尖峰使用量,其中 的元素分別對應於非分頁集區、分頁集區、和交換檔中的 記憶體使用量。 EPROCESS Structure_ActiveProcessLinks EPROCESS KPROCESS… EPROCESS KPROCESS EPROCESS KPROCESS PsActiveProcessHead LIST_ENTRY LIST_ENTRY LIST_ENTRY LIST_ENTRY Flink Flink Flink Flink Blink Blink Blink Blink EPROCESS Structure (Con.) Element Purpose SIZE_T CommitCharge Process的虛擬記憶體已提交的頁面數量。 SIZE_T Commit ChargeLimit 已提交頁面數量的限制值,如果是0就表示沒有 限制,預設為0。 SIZE_T Commit ChargePeak 尖峰時刻的已提交頁面數量 SIZE_T VirtualSize Process的虛擬記憶體大小 SIZE_T PeakVirtualSize Process的虛擬記憶體大小的尖峰值 LIST_ENTRY SessionProcessLinks 為雙串列結點,當一個Process加入一個系統工作 階段中時,SessionProcessLinks 當作節點加入。 PVOID DebugPort/ExceptionPort 控制代碼,分別指向偵錯埠和例外埠。 PHANDLE_TABLE ObjectTable Process 的控制代碼表,控制代碼是一個抽象概念, 代表該Process已開啟的一個物件 EX_FAST_REF Token 快速引用,指向該Process的存取權杖, 用於該 Process 的安全存取檢查。 Windows記憶體管理機制 Windows使用了Intel x86的二級或 多級分頁表機制來存取虛擬記憶體。 處理器在執行記憶體存取指令時, 將虛擬位址翻譯成實體位址,翻譯 過程涉及到查詢分頁目錄和分頁表, 一旦分頁表項目指出一個頁面末在 實體記憶體中,則觸發分頁錯誤 ( page fault)例外。 Two-Level Page-Table Scheme EPROCESS Structure(2/4) typedef struct _EPROCESS { /*前面已列出第一部分*/ PFN_NUMBER WorkingSetPage; KGUARDED_MUTEX AddressCreationLock; KSPIN_LOCK HyperSpaceLock; struct _ETHREAD *ForkInProgress; ULONG_PTR HardwareTrigger; PMM_AVL_TABLE PhysicalVadRoot; PVOID CloneRoot; PFN_NUMBER NumberOfPrivatePages; PFN_NUMBER NumberOfLockedPages; PVOID Win32Process; struct _EJOB *Job; PVOID SectionObject; PVOID SectionBaseAddress; PEPROCESS_QUOTA_BLOCK QuotaBlock; PPAGEFAULT_HISTORY WorkingSetWatch; HANDLE Win32WindowStation; HANDLE InheritedFromUniqueProcessId; PVOID LdtInformation; PVOID VadFreeHint; PVOID VdmObjects; EPROCESS Structure (Con.) Element Purpose PFN_NUMBER WorkingSetPage 指包含Process工作集的頁面 (注:工作集指一個 process目前正在使用的實體頁面的集合) KGUARDED_MUTEX AddressCreationLock 是一個 guarded mutex,用於保護對地址空間的操作。 KSPIN_LOCK HyperSpaceLock; 是一個Spin Lock,用於保護process的hyper space。 struct _ETHREAD *ForkInProgress 指向正在複製地址空間的那個thread ULONG_PTR HardwareTrigger 記錄硬件錯誤性能分析次數,在WRK中沒有使用 PMM_AVL_TABLE PhysicalVadRoot 指向process的實體 VAD樹的根,它並不總是存在,只有當 確實需要對應實體記憶體時才會被建立。 PVOID CloneRoot 指向一個平衡樹的根,當process 位址空間複製時,此樹被 建立,建立出來以後,一直到process退出的時候才被銷毀 PFN_NUMBER NumberOfPrivatePages/ NumberOfLockedPages 指process私有頁面的數量和被鎖住頁面的數量。 Lock (鎖) 鎖的用途是實作互斥存取: 鎖=0:表示瑣是空閒的,任何 thread都可以獲得,獲 得後,鎖的值指定為1,其他thread 都無法獲得鎖 鎖=1:未獲得鎖的thread必須被封鎖,直到使用鎖的 thread釋放該鎖為止。 Spinlock(自旋鎖):本質上是一種忙等待(busywait)。為了取得spinlock,處理器不停的檢查 鎖的狀態而不做其他事情,直到鎖的狀態變成 可用。 Pushlock(推鎖):支援互斥和共用兩種模式的同步 機制。 Virtual Address Descriptor(VAD) 對於每一個process,Windows的記憶體管理一組虛擬位址 描述項(VAD) 每個VAD物件描述了一段連續的位址範圍,在整個位址空間 中保留的或提交的範圍有可能不連續,因此Windows使用一 顆平衡二元搜尋樹來管理VAD物件。 VadRoot 範圍:20000000到2000FFFF 保護限制:讀/寫 繼承:有 範圍:00002000到0000FFFF 保護限制:只讀 繼承:無 範圍:4E000000到4F000000 保護限制:複製可寫入 繼承:有 範圍:32000000到3300FFFF 保護限制:只讀 繼承:無 範圍:7AAA0000到7AAA00FF 保護限制:讀/寫 繼承:無 EPROCESS Structure (Con.) Element Purpose PVOID Win32Process 此欄位是一個指標,指向由Windows子系統管理的process 區域,如果此值不為 NULL,則說明這是一個Windows子 系統進程(GUI)。 struct _EJOB *Job 只有當一個process屬於Job時才會指向_EJOB物件 PVOID SectionObject 此欄位是一個指標,代表process的記憶體區段物件 PVOID SectionBaseAddress 該記憶體區段物件的基底位址 PEPROCESS_QUOTA_BLOCK Qu otaBlock 指向的process的配額區塊,windows系統中的配額區塊相互 串列形成雙串列,每個配額區塊可以被多個process共用, 配額區塊中主要定義了非分頁集區、分頁集區和交換檔中 的記憶體配額限制。 PPAGEFAULT_HISTORY WorkingSetWatch 用於監視一個process的分頁錯誤,一旦啟用後,每次發生 錯誤時都會將該分頁錯誤記錄到WorkingSetWatch欄位中 的WatchInfo中。 HANDLE Win32WindowStation Process所屬的視窗工作站的控制代碼,控制代碼值是由每 個process的控制代碼表來決定的,所以同一個視窗工作站 有可能代碼不同。 EPROCESS Structure (Con.) Element Purpose HANDLE InheritedFromUniqueProcessId 說明 process從哪裡繼承,父Process的識別字。 PVOID LdtInformation 用來維護一個process的LDT(Local Descriptor Table )資 訊 PVOID VadFreeHint 指向一個提示VAD(虛擬位址描述項)節點,用於加速在 VAD樹中執行搜尋操作 PVOID VdmObjects 指向目前process的VDM資料區,其型別為 VDM_PROCESS_OBJECTS,process可透過VdmObject系 統服務來初始化VDM。 PVOID DeviceMap 指向process使用的裝置表。 EPROCESS Structure(3/4) typedef struct _EPROCESS { /*前面已列出第二部分*/ PVOID Spare0[3]; union { HARDWARE_PTE PageDirectoryPte; ULONGLONG Filler; }; PVOID Session; UCHAR ImageFileName[ 16 ]; LIST_ENTRY JobLinks; PVOID LockedPagesList; LIST_ENTRY ThreadListHead; PVOID SecurityPort; PVOID PaeTop; ULONG ActiveThreads; ACCESS_MASK GrantedAccess; ULONG DefaultHardErrorProcessing; NTSTATUS LastThreadExitStatus; PPEB Peb; EPROCESS Structure (Con.) Element Purpose PVOID Spare0[3] Spare0 欄位是一個備用欄位,在WRK 中没有使用 HARDWARE_PTE PageDirectoryPte 上層分頁目錄頁面的分頁表項目 PVOID Session 指向Process所在的系統工作階段,每個process在建立 位址空間時會加入到目前的系統工作階段中 UCHAR ImageFileName[ 16 ] 欄位包含了映像檔名,僅包含最後一個路徑分隔符號 之後的字串,不超過16個字元 LIST_ENTRY JobLinks 所有的Job透過此節點構成一個雙串列,其串列開頭為 全域變數PspJobList,每個Job中的process又構成一個雙 串列。 PVOID LockedPagesList 指向LOCK_HEADER結構的指標,該結構包含了一個 串列開頭,Windows過此串列紀錄哪些頁面已被鎖住 LIST_ENTRY ThreadListHead 雙串列的頭節點,該串列包含了一個行程中的所有 thread EPROCESS Structure_ActiveProcessLinks EPROCESS ETHREAD ETHREAD KPROCESS LIST_ENTRY ThreadListHead LIST_ENTRY ThreadListEntry LIST_ENTRY ThreadListEntry Flink Flink Flink Blink Blink Blink EPROCESS Structure (Con.) Element Purpose PVOID SecurityPort 此欄位為安全埠,指向該行程與lsass process 之間的跨 行程通訊埠 PVOID PaeTop 支援 PAE記憶體存取機制 ULONG ActiveThreads 紀錄目前process有多少active的thread ACCESS_MASK GrantedAccess 此欄位包含了process的存取權限,存取權限是一個位 元組合 ULONG DefaultHardErrorProcessing 預設的硬體錯誤處理 NTSTATUS LastThreadExitStatus 記錄了剛才最後一個thread 的結束狀態 PPEB Peb Process Environment Block(PEB),包含了有關process位 址空間中的推疊和系統模組等資訊 Process Environment Block(PEB) EPROCESS Structure(4/4) typedef struct _EPROCESS { /*前面已列出第三部分*/ EX_FAST_REF PrefetchTrace; LARGE_INTEGER ReadOperationCount; LARGE_INTEGER WriteOperationCount; LARGE_INTEGER OtherOperationCount; LARGE_INTEGER ReadTransferCount; LARGE_INTEGER WriteTransferCount; LARGE_INTEGER OtherTransferCount; PVOID AweInfo; SE_AUDIT_PROCESS_CREATION_INFO SeAuditProcessCreationInfo; MMSUPPORT Vm; LIST_ENTRY MmProcessLinks; ULONG ModifiedPageCount; ULONG JobStatus; union { ULONG Flags; struct { …… }; }; NTSTATUS ExitStatus; USHORT NextPageColor; union { struct { UCHAR SubSystemMinorVersion; UCHAR SubSystemMajorVersion; }; USHORT SubSystemVersion; }; UCHAR PriorityClass; MM_AVL_TABLE VadRoot; ULONG Cookie; EPROCESS Structure (Con.) Element Purpose EX_FAST_REF PrefetchTrace; 此欄位是一個快速引用,指向該process關聯的一個 預取痕跡結構 LARGE_INTEGER ReadOperationCount/ WriteOperationCount; 紀錄目前process NtReadFile和ntWritwFile系統服務被 呼叫的次數 LARGE_INTEGER OtherOperationCount 紀錄除讀寫以外的其他I/O服務操作次數 LARGE_INTEGER ReadTransferCount/W riteTransferCount 紀錄I/O讀取操作或寫入操作完成的次數 LARGE_INTEGER OtherTransferCount 紀錄非讀寫操作完成次數 PVOID AweInfo 指向AWEINFO結構的指標,其目的是為了支援 AWE(Address Windowing Extension) SE_AUDIT_PROCESS_CREATION_INFO Se AuditProcessCreationInfo 建立Process時指定的映像全路徑名稱,前面提到的 ImageFileName實際上是從這裡提取出來的 MMSUPPORT Vm Windows為每個process管理虛擬記憶體的重要資料結 構成員 Address Windowing Extension(AWE) AWE 是一組針對記憶管理員功能的應用程式發展介面 (API,Application Programming Interface),可以讓程式定址比標準 32 位元定址所提供的 4 GB ,還要多的記憶體 AWE 讓程式能夠以非分頁記憶體形式保留實體記憶體,然後將非分頁記憶體 的部分,動態對應到工作中的程式記憶體 Data Structure Related to Working Set EPROCESS資料結構中 的成員VM,型別為 MMSUPPORT包含了工作 集管理員在判斷是否需要 修剪一個行程(process)時 所需要的各種資訊, 其中包含該行程所設定的 工作集最小值和最大值。 EPROCESS Structure (Con.) Element Purpose LIST_ENTRY MmProcessLinks 代表一個雙串列節點,所有擁有自己位址空間的process 都加入到一個雙串列中,雙串列開頭是全域變數 MmProcessList ULONG ModifiedPageCount 紀錄該process以修改頁面的數量 ULONG JobStatus 紀錄process所屬Job狀態 ULONG Flags Process的旗標位元,反映process目前狀態和配置 NTSTATUS ExitStatus Process結束狀態,從此狀態可獲知Process非正常結束的 大致原因 USHORT NextPageColor 此欄位用於實體頁面分配演算法 UCHAR SubSystemMinorVersion/ SubSystemMajorVersion 分別紀錄一個process的子系統主版本和次版本序號,其 值來自於Process的映像檔案對應版本資訊 UCHAR PriorityClass; 說明了一個行程的優先層級程度 MM_AVL_TABLE VadRoot; 指向一個平衡的二元樹的根,用於管理虛擬位址空間 ULONG Cookie; 存放一個代表該Process的隨機值 3.3.2 ETHREAD 995202084 楊郁莉 Introduction ETHREAD為管理執行緒區塊 (Executive Thread Block) 是屬於執行體層(Executive Layer)的一種 thread位於Kernel Space Relationship ETHREAD Thread開始位置 KTHREAD EProcess Pointer 排班和同步訊息 TEB Thread 識別器 使用者堆疊 … … 執行層 內核層 Kernel Space … User Space Architecture KTHREAD Create and Exit Time Process ID EPROCESS Thread Start Address Impersonation Information LPC Message Information Access Token Timer Information Pending I/O Requests Architecture KTHREAD Create and Exit Time Process ID EPROCESS Thread Start Address Impersonation Information LPC Message Information Access Token Timer Information Pending I/O Requests Code-KTHREAD typedef struct _ETHREAD { KTHREAD Tcb; //指向kthread指標 . . . } ETHREAD, *PETHREAD; Architecture KTHREAD Create and Exit Time Process ID EPROCESS Thread Start Address Impersonation Information LPC Message Information Access Token Timer Information Pending I/O Requests Code-Create and Exit Time typedef struct _ETHREAD { LARGE_INTEGER CreateTime;//包含thread建立時間 union { LARGE_INTEGER ExitTime;//thread結束函式指定 LIST_ENTRY KeyedWaitChain;//用於跨行程通訊 LIST_ENTRY LpcReplyChain;//用於帶鍵事件等待 串列 }; … } ETHREAD, *PETHREAD; Architecture KTHREAD Create and Exit Time Process ID EPROCESS Thread Start Address Impersonation Information LPC Message Information Access Token Timer Information Pending I/O Requests Code-Process ID typedef struct _ETHREAD { CLIENT_ID Cid; //包含thread的唯一識別字 … } ETHREAD, *PETHREAD; Unique Process:所屬行程的Unique Process ID Unique Thread:此物件在Process中的控制代碼 Architecture KTHREAD Create and Exit Time Process ID EPROCESS Thread Start Address Impersonation Information LPC Message Information Access Token Timer Information Pending I/O Requests Code-EPROCESS typedef struct _ETHREAD { PEROCESS ThreadProcess; //thread建立時被指定,可存取他所屬process LIST_ENTRY Thread ListEntry; //每個thread加入到他所屬行程Eprocess的 ThreadListHead中 … } ETHREAD, *PETHREAD; Architecture KTHREAD Create and Exit Time Process ID EPROCESS Thread Start Address Impersonation Information LPC Message Information Access Token Timer Information Pending I/O Requests Code-Thread Start Address typedef struct _ETHREAD { POVID StartAddress;//包含thread啟動的address union { POVID Win32StartAddress; //window子系統啟動位址 ULONG LpcReceiveMessgeId; //包含LPC接收到訊息 }; … } ETHREAD, *PETHREAD; Architecture KTHREAD Create and Exit Time Process ID EPROCESS Thread Start Address Impersonation Information LPC Message Information Access Token Timer Information Pending I/O Requests Code-Access Token typedef struct _ETHREAD { ACCESS_MASK GranteAccess; //包含thread 存取權限 . . } ETHREAD, *PETHREAD; Architecture KTHREAD Create and Exit Time Process ID EPROCESS Thread Start Address Impersonation Information LPC Message Information Access Token Timer Information Pending I/O Requests Code-Impersonation Information typedef struct _ETHREAD { PPS_IMPERSOPNATION_INFORMATION ImpersionationInfo; //指向thread的模仿資訊,thread允許一個thread在 執行過程中模仿其他使用者來執行一段功能 … } ETHREAD, *PETHREAD; Architecture KTHREAD Create and Exit Time Process ID EPROCESS Thread Start Address Impersonation Information LPC Message Information Access Token Timer Information Pending I/O Requests Code-LPC Message typedef struct _ETHREAD { union{ KSEMAPHORE LpcReplySemaphore;//用於LPC應答 KSEMAPHORE KeyedWaitSemaphore;//用於處理帶鍵事件 }; union{ PVOID LpcReplyMessage; //指向LPCP_MESSAGE指標,包含LPC應答訊息 PVOID LpcWaitingOnPort;//說明在哪個port上等待 }; … } ETHREAD, *PETHREAD; Architecture KTHREAD Create and Exit Time Process ID EPROCESS Thread Start Address Impersonation Information LPC Message Information Access Token Timer Information Pending I/O Requests Code-Time Information typedef struct _ETHREAD { KSPIN_LOCK ActiveTimerListLock ; //串列的自旋鎖 LIST_ENTRY ActiveTimerListHead; //串列中包含目前thread的所有計時器 … } ETHREAD, *PETHREAD; Architecture KTHREAD Create and Exit Time Process ID EPROCESS Thread Start Address Impersonation Information LPC Message Information Access Token Timer Information Pending I/O Requests Code-Pending I/O Requests typedef struct _ETHREAD { LIST_ENTRY IrpList; //包含目前thread所有在處理但未完成I/O請求 ULONG TopLevelIrp; //指向上層的IRP,僅thread的I/O呼叫最上層的元件 是檔案系統時他才指向目前的IRP PDEVICE_OBJECT DeviceToVerify; //指向一個待檢驗的裝置物件 … } ETHREAD, *PETHREAD; Table of Executive Thread Block Element Description KTHREAD Pointer points to Kthread THREAD Time Thread create and exit time Process Identification Process ID and pointer to Eprocess block of process that the thread belong to . Start Address Address thread of start routine Impersonation information Access token and Impersonation level LPC Information Message ID that the thread is waiting for and address of message I/O Information List of pending I/O request packets(IRPs) Conclusion(1/2) EProcess和EThread內嵌了KProcess和 Kthread 。 核心層的process和thread物件偏重於基本 的功能和機制。 執行體層的process和thread則偏重於管理 和策略。 Conclusion(2/2) Application Program Executive Layer EProcess EThread EThread KThread KThread KThread KProcess KThread KThread KThread KThread KThread Kernel Layer KProcess EThread Process and thread control in Windows NT 陳浩宇 Outline 3.4 Windows Process and Thread Management 3.4.1 Windows Process Handle Table 3.4.2 Handling Process and Thread Introduction We create and access object in creating thread. We have to know how we access object first. Object access In Windows executive layer We manage system resource and object by Object Manager. In process We access system object by Handle. For example, we can access same object by handle in different processes. Every process got different handle, these handles can access same file. Every handle is managed in handle table. If 𝑃𝑟𝑜𝑐𝑒𝑠𝑠𝑎 transmit handle to 𝑃𝑟𝑜𝑐𝑒𝑠𝑠𝑏 , the handle is invalid . Handle table In windows. Handle table of process contains all pointers of object opened by each process. In windows 2003 Hierarchical model Control Information Handle table ( code ) typedef struct _HANDLE_TABLE { ULONG_PTR TableCode; // 紀錄table的layer數 struct _EPROCESS *QuotaProcess; // 指向這process的pointer HANDLE UniqueProcessId; // process id #define HANDLE_TABLE_LOCKS 4 EX_PUSH_LOCK HandleTableLock[HANDLE_TABLE_LOCKS]; // LIST_ENTRY HandleTableList; // EX_PUSH_LOCK HandleContentionEvent; // For race condition PHANDLE_TRACE_DEBUG_INFO DebugInfo; // Using in debug mode LONG ExtraInfoPages; ULONG FirstFree; ULONG LastFree; ULONG NextHandleNeedingPool; LONG HandleCount; union { ULONG Flags; BOOLEAN StrictFIFO : 1; }; } HANDLE_TABLE, *PHANDLE_TABLE; Handle table (in structure) ULONG_PTR TableCode; ... 01 10 0 Levels Table level • How to get table level ULONG_PTR CapturedTable = HandleTable->TableCode; ULONG TableLevel = (ULONG)(CapturedTable & LEVEL_CODE_MASK); //此HandleTable之Level是多少 • How to get count and threshold of size in each level #define MAX_HANDLES (1<<24) #define TABLE_PAGE_SIZE PAGE_SIZE #define LOWLEVEL_COUNT (TABLE_PAGE_SIZE / sizeof(HANDLE_TABLE_ENTRY)) #define MIDLEVEL_COUNT (PAGE_SIZE / sizeof(PHANDLE_TABLE_ENTRY)) #define HIGHLEVEL_COUNT MAX_HANDLES / (LOWLEVEL_COUNT * MIDLEVEL_COUNT) #define LOWLEVEL_THRESHOLD LOWLEVEL_COUNT #define MIDLEVEL_THRESHOLD (MIDLEVEL_COUNT * LOWLEVEL_COUNT) #define HIGHLEVEL_THRESHOLD (MIDLEVEL_COUNT * MIDLEVEL_COUNT * LOWLEVEL_COUNT) // Define the page size for the Intel 386 as 4096 (0x1000). // Define the HANDLE_TABLE_ENTRY size as 8 ( bytes ) // Sizeof(PHANDLE_TABLE_ENTRY) presents length of PHANDLE_TABLE_ENTRY( 4 bytes ) Handle table We allocate a 1-layer handle table for a process at start. We initial it. ExCreateHandleTable(__in_opt struct _EPROCESS *Process) — ExpAllocateHandleTable( Process, TRUE ) We extend table when space is not enough. ExpAllocateHandleTableEntrySlow (IN PHANDLE_TABLE HandleTable, IN BOOLEAN DoInit ) ExCreateHandleTable PHANDLE_TABLE ExCreateHandleTable ( __in_opt struct _EPROCESS *Process ) { PKTHREAD CurrentThread; PHANDLE_TABLE HandleTable; PAGED_CODE(); CurrentThread = KeGetCurrentThread (); HandleTable = ExpAllocateHandleTable( Process, TRUE ); //建立初始Handle Table if (HandleTable == NULL) { return NULL; } KeEnterCriticalRegionThread (CurrentThread); 將Handle Table 加入List ExAcquirePushLockExclusive( &HandleTableListLock ); InsertTailList( &HandleTableListHead, &HandleTable->HandleTableList ); ExReleasePushLockExclusive( &HandleTableListLock ); KeLeaveCriticalRegionThread (CurrentThread); return HandleTable; } ExpAllocateHandleTableEntry … PHANDLE_TABLE_ENTRY ExpAllocateHandleTableEntry ( IN PHANDLE_TABLE HandleTable, OUT PEXHANDLE pHandle ) { … while (1) { OldValue = HandleTable->FirstFree; … Handle.Value = (OldValue & FREE_HANDLE_MASK); Entry = ExpLookupHandleTableEntry (HandleTable, Handle); Idx = ((OldValue & FREE_HANDLE_MASK)>>2) % HANDLE_TABLE_LOCKS; KeMemoryBarrier (); NewValue = *(volatile ULONG *) &Entry->NextFreeTableEntry; NewValue1 = InterlockedCompareExchange ((PLONG)&HandleTable->FirstFree, NewValue, OldValue); } … BOOLEAN ExpAllocateHandleTableEntrySlow ( IN PHANDLE_TABLE HandleTable, IN BOOLEAN DoInit ) { ULONG_PTR CapturedTable = HandleTable->TableCode; ULONG TableLevel = (ULONG)(CapturedTable & LEVEL_CODE_MASK); PAGED_CODE(); NewLowLevel = null ; //建立一新的HandleTable CapturedTable = CapturedTable & ~LEVEL_CODE_MASK; //TableCode最低2位元Mask if ( TableLevel == 0 ) { NewMidLevel = ExpAllocateMidLevelTable( HandleTable, DoInit, &NewLowLevel ); //建立 MidLevelHandleTable if (NewMidLevel == NULL) { 並且建立一LowlevelHandleTable return FALSE; } NewMidLevel[1] = NewMidLevel[0]; //將新建立的 LowlevelHandleTable 至於此處 NewMidLevel[0] = (PHANDLE_TABLE_ENTRY)CapturedTable; //將原先Handle CapturedTable = ((ULONG_PTR)NewMidLevel) | 1; Table至於此 … } Handle table ( code ) typedef struct _HANDLE_TABLE { ULONG_PTR TableCode; // 紀錄table的layer數 struct _EPROCESS *QuotaProcess; // 指向這process的pointer HANDLE UniqueProcessId; // process id #define HANDLE_TABLE_LOCKS 4 EX_PUSH_LOCK HandleTableLock[HANDLE_TABLE_LOCKS]; // LIST_ENTRY HandleTableList; // EX_PUSH_LOCK HandleContentionEvent; // For race condition PHANDLE_TRACE_DEBUG_INFO DebugInfo; // Using in debug mode LONG ExtraInfoPages; ULONG FirstFree; ULONG LastFree; ULONG NextHandleNeedingPool; LONG HandleCount; union { ULONG Flags; BOOLEAN StrictFIFO : 1; }; } HANDLE_TABLE, *PHANDLE_TABLE; ExpMoveFreeHandles ULONG ExpMoveFreeHandles ( IN PHANDLE_TABLE HandleTable ) { … FreeSize = OldIndex = 0; FirstEntry = NULL; while (1) { FreeSize++; //計算 FreeHandle 數 Handle.Value = Index; Entry = ExpLookupHandleTableEntry (HandleTable, Handle); EXASSERT (Entry->Object == NULL); NewIndex = Entry->NextFreeTableEntry; 將 FreeHandle List 反轉 Entry->NextFreeTableEntry = OldIndex; if (OldIndex == 0) { FirstEntry = Entry; } //第一次進入迴圈將第一個Entry OldIndex = Index; 設為FirstEntry if (NewIndex == 0) { break; } Index = NewIndex; } //反轉結束時,原List Tail = List Head , List Head = List Tail NewValue = ExpInterlockedExchange (&HandleTable->FirstFree, OldIndex, FirstEntry); //將新的List Head 設給 Handle->FirstFree, 至此 新的FreeHandleList就建立起來 ExpMoveFreeHandles StrictFIFO = 0 Handle table entry( code ) typedef struct _HANDLE_TABLE_ENTRY { union { PVOID Object; ULONG ObAttributes; // 指向handle所代表的object // 以最低的3個bit代表各種attribute // OBJ_HANDLE_ATTRIBUTES 巨集定義 PHANDLE_TABLE_ENTRY_INFO InfoTable; //每個handle table page的第一個項目 ULONG_PTR Value; }; union { union { ACCESS_MASK GrantedAccess; struct { // 存取遮罩 , 紀錄物件的存取狀況 //當NtGlobalFlag中包含 //FLG_KERNEL_STACK_TRACE_DB標記時使用 USHORT GrantedAccessIndex; USHORT CreatorBackTraceIndex; }; }; LONG NextFreeTableEntry; // 下一個free handle的index }; } HANDLE_TABLE_ENTRY, *PHANDLE_TABLE_ENTRY; Handle table entry PVOID Object; ... OBJ_PROTECT_CLOSE OBJ_PROTECT_CLOSE 是否允許關閉Handle OBJ_INHERIT Child是否可以繼承此Handle OBJ_INHERIT OBJ_AUDIT_OBJECT_CLOSE OBJ_AUDIT_OBJECT_CLOSE 關閉物件時是否觸發Audit事件 Handle table entry How to Know what Handle means ? A valid Handle has four possible Present this process #define NtCurrentProcess() ((HANDLE)0xFFFFFFFF) // ntapi.h 2) Present this thread #define NtCurrentThread() ((HANDLE)0xFFFFFFFE) // ntapi.h 3) Present system handle Handle = DecodeKernelHandle( Handle ); HandleTable = ObpKernelHandleTable; 4) Present excuting process handle HandleTable = PsGetCurrentProcessByThread(Thread)>ObjectTable; 1) ObReferenceObjectByHandle NTSTATUS ObReferenceObjectByHandle ( __in HANDLE Handle, …….) { … if ((LONG)(ULONG_PTR) Handle < 0) { if (Handle == NtCurrentProcess()) { // 判別Handle 是否為 Current process handle if ((ObjectType == PsProcessType) || (ObjectType == NULL)) { Process = PsGetCurrentProcessByThread(Thread); // 取得目前執行之Process GrantedAccess = Process->GrantedAccess; if ((SeComputeDeniedAccesses(GrantedAccess, DesiredAccess) == 0) || (AccessMode == KernelMode)) { //若AccessMode 為KernelMode 或 為許可之 AccessMode ObjectHeader = OBJECT_TO_OBJECT_HEADER(Process); if (ARGUMENT_PRESENT(HandleInformation)) { HandleInformation->GrantedAccess = GrantedAccess; HandleInformation->HandleAttributes = 0; } ObpIncrPointerCount(ObjectHeader); //Count用以得知Object是否被使用 , 以防Object遭 Delete *Object = Process; // 設定Object pointer為Process ASSERT( *Object != NULL ); Status = STATUS_SUCCESS; ObReferenceObjectByHandle } else if (Handle == NtCurrentThread()) { if ((ObjectType == PsThreadType) || (ObjectType == NULL)) { GrantedAccess = Thread->GrantedAccess; if ((SeComputeDeniedAccesses(GrantedAccess, DesiredAccess) == 0) || (AccessMode == KernelMode)) { ObjectHeader = OBJECT_TO_OBJECT_HEADER(Thread); if (ARGUMENT_PRESENT(HandleInformation)) { HandleInformation->GrantedAccess = GrantedAccess; HandleInformation->HandleAttributes = 0; } ObpIncrPointerCount(ObjectHeader); *Object = Thread; ASSERT( *Object != NULL ); Status = STATUS_SUCCESS; } else { Status = STATUS_ACCESS_DENIED; } } else { Status = STATUS_OBJECT_TYPE_MISMATCH; } return Status; 按照Handle Table的結構,找 ASSERT(HandleTable != NULL); 到Handle索引值所指向的 KeEnterCriticalRegionThread(&Thread->Tcb); Handle項目 ObjectTableEntry = ExMapHandleToPointerEx ( HandleTable, Handle, AccessMode ); … if (ObjectTableEntry != NULL) { ObjectHeader = (POBJECT_HEADER)(((ULONG_PTR)(ObjectTableEntry->Object)) & ~OBJ_HANDLE_ATTRIBUTES); ReadForWriteAccess(ObjectHeader); if ((ObjectHeader->Type == ObjectType) || (ObjectType == NULL)) { if ((SeComputeDeniedAccesses(GrantedAccess, DesiredAccess) == 0) || (AccessMode == KernelMode)) { 檢查Handle存取權限是否 滿足要求 PHANDLE_TABLE_ENTRY_INFO ObjectInfo; ObjectInfo = ExGetHandleInfo(HandleTable, Handle, TRUE); if ( (ObjectTableEntry->ObAttributes & OBJ_AUDIT_OBJECT_CLOSE) &&(ObjectInfo != NULL) && (ObjectInfo->AuditMask != 0) &&(DesiredAccess != 0)) { ObpAuditObjectAccess( Handle, ObjectInfo, &ObjectHeader->Type->Name, DesiredAccess ); } // 對物件 ObpIncrPointerCount(ObjectHeader); ExUnlockHandleTableEntry( HandleTable, ObjectTableEntry ); KeLeaveCriticalRegionThread(&Thread->Tcb); *Object = &ObjectHeader->Body; // 傳回 Object ASSERT( *Object != NULL ); return STATUS_SUCCESS; How to Insert Object to HandleTable NTSTATUS ObInsertObject ( __in PVOID Object, 針對物件參數進行各種檢查後 __in_opt PACCESS_STATE AccessState, __in_opt ACCESS_MASK DesiredAccess, 呼叫ObpCreateHandle為物件建立 Handle __in ULONG ObjectPointerBias, __out_opt PVOID *NewObject, if (ARGUMENT_PRESENT (Handle)) { __out_opt PHANDLE Handle Status = ObpCreateHandle( OpenReason, ) InsertObject, NULL, 建立Handle並置入於 AccessState, HandleTable對應Entry中 1 + ObjectPointerBias, NTKERNELAPI HANDLE ObjectCreateInfoExCreateHandle ( >Attributes, __inout PHANDLE_TABLE HandleTable, &LookupContext, __in PHANDLE_TABLE_ENTRY PreviousMode, HandleTableEntry NewObject, ) &NewHandle ); Reference Count 1. Reference by object address — 2. ObReferenceObjectByPointer Reference by Handle — ObpIncrementHandleCount ObpCreateHandl e ObpIncrementHandleCount ObpCloseHandle ObpDecrementHandleCount Handle - ID UniqueProcessI d Cid Handle ID idle 0 PspCidTable System 4 𝑃𝑖𝑑1 8 𝑃𝑖𝑑2 12 … … PspCidTable PspCidTable 在系統初始化時以PspInitPhase()初始化Process管理子系統並建立PspCidTable … BOOLEAN PspInitPhase0 ( IN PLOADER_PARAMETER_BLOCK LoaderBlock ) { … PspCidTable = ExCreateHandleTable (NULL); if (PspCidTable == NULL) { return FALSE; } ExSetHandleTableStrictFIFO (PspCidTable); } //建立PspCidTable //設定運作為FIFO … NTSTATUS PspCreateProcess (OUT PHANDLE ProcessHandle, ….. ) { CidEntry.Object = Process; CidEntry.GrantedAccess = 0; Process->UniqueProcessId = ExCreateHandle (PspCidTable, &CidEntry); if (Process->UniqueProcessId == NULL) { Status = STATUS_INSUFFICIENT_RESOURCES; goto exit_and_deref; … … } NTSTATUS PspCreateThread(OUT PHANDLE ThreadHandle, ……) { Thread->ThreadsProcess = Process; Thread->Cid.UniqueProcess = Process->UniqueProcessId; CidEntry.Object = Thread; CidEntry.GrantedAccess = 0; Thread->Cid.UniqueThread = ExCreateHandle (PspCidTable, &CidEntry); if (Thread->Cid.UniqueThread == NULL) { ObDereferenceObject (Thread); return (STATUS_INSUFFICIENT_RESOURCES); } … } Obtain current process or thread 陳浩宇 How do we get current thread We can use KeGetCurrentThread to get current thread. In ntos\inc\i386.h, cl.exe(compiler) ver. Is larger than 13012035, we perform program in “if”. struct _KTHREAD * NTAPI KeGetCurrentThread (VOID) { #if (_MSC_FULL_VER >= 13012035) return (struct _KTHREAD *) (ULONG_PTR) __readfsdword (FIELD_OFFSET (KPCR, PrcbData.CurrentThread)); #else __asm { mov eax, fs:[0] KPCR.PrcbData.CurrentThread } #endif } How do we get current thread In _KPCR( kernel processor control region ), we can find processor control block ( _KPRCB ). _KPRCB is structure. In _KPRCB structure, it shows that: struct _KTHREAD *CurrentThread; < = target struct _KTHREAD *NextThread; struct _KTHREAD *IdleThread; How do we get current thread __readfsdword (FIELD_OFFSET (KPCR, rcbData.CurrentThread)) #define FIELD_OFFSET(t,f) ((LONG)&(((t*)0)-> f)) for example: FIELD_OFFSET(MSG_STRUCT,Length) 得到的就是Length在MSG_STRUCT結構中的offset FIELD_OFFSET(MSG_STRUCT,Content[4]) 得到的就是Content[4]在MSG_STRUCT結構中的offset By FIELD_OFFSET , we can get OFFSET of CurrentThread in KPCR. How do we get current thread Next , we can use __readfsdword to get content of KPCR:offset( called current thread ) unsigned long __readfsdword( unsigned long Offset ); The memory contents of the byte, word, doubleword, or quadword (as indicated by the name of the function called) at the location FS:[Offset]. Now we got current thread. How do we get current process In previously page, we got (_KTHREAD) current thread. Now we use Current thread tracing current process. In previous chapter, we know pthread contains kthread. It means each pointer pointing to pthread point kthread too. by _KTHREAD->ApcState, we got KPROCESS which contains_KTHREAD. Finally, we got PPROCESS by KPROCESS Why do we find KPROCESS through _ KTHREAD>ApcState? We can easy to find process attaching _KTHREAD by checking ApcState.