行程狀態

advertisement
現代系統核心報告
第三組
范綱烜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.
Download