Windows 的行程和緒程資料結構ETHREAD

advertisement
1
Chapter3 Windows 行程和緒程
3.1 行程基本觀念
3.1.1 多行程模型
3.1.2 行程與程式
3.2 緒程基本觀念
3.2.1 緒程模型
3.2.2 緒程排程演算法
3.2.3 緒程與行程的關係
3.3 Windows 的行程和緒程資料結構
3.3.1 核心層的行程和緒程物件
3.3.2 執行體層的行程和緒層物件
3.4 Windows 行程和緒程的管理
3.4.1 Windows 行程的控制代碼表
3.4.2 獲得目前的行程和緒程
2
章節地圖
3.1 行程基本觀念
3.1.1 多行程模型
3.1.2 行程與程式
3.2 緒程基本觀念
3.2.1 緒程模型
3.2.2 緒程排程演算法
3.2.3 緒程與行程的關係
3.3 Windows 的行程和緒程資料結構
3.3.1 核心層的行程和緒程物件
3.3.2 執行體層的行程和緒程物件
3.4 Windows 行程和緒程的管理
3.4.1 Windows 行程的控制代碼表
3
3.4.2 獲得目前的行程和緒程
• 行程 (Process)
– 定義了以位址空間為基本的執行環境
– 電腦中已執行程式的實體
– 本身不會執行,是緒程 (Thread) 的容器
4
• 現代作業系統提供多個工作能夠並行執行
的環境
• 偽平行
– 單核心處理器
– 將時間細分並輪流執行不同的工作
• 真平行
– 多核心處理器
– 多個工作分別在不同的處理器上執行
5
• 維護一個全域的行程表
– 記錄下目前有哪些行程正在被執行
• 把時間分成適當的片段
– 設置時鐘中斷來完成
• 在行程之間實施切換
– 保留 一個行程的環境資訊,恢復下一個行程的
執行環境
6
• 程式
– 指令的集合
– 為了完成特定的功能或工作而存在
– 需要有程式碼、暫存器、記憶體…等來配合
• 程式本身只是指令的集合,行程才是程式
的真正執行
7
8
• 靜態資料區
– 全域變數、靜態變數
– 編寫程式碼時就確定的資料區域
• 動態資料區
– 程式執行時依需要而分配或回收的記憶體區域
• 堆疊
– 紀錄執行過程中的函式狀態資訊
• 呼叫位置、區域變數…等
– 傳遞函式參數
9
• 行程的建立
– 作業系統啟動時
– 程式所需要時
• 行程的結束
– 行程完成工作之後
– 行程出錯或是狀態不正確時
10
• 狀態:行程目前的動作
– 行程執行時,狀態 (state) 會改變
狀態
描述
新生 (new)
行程新產生中。
執行 (running)
正在執行。
等待 (waiting)
等待某事發生,例如等待使用者輸入完成。
就緒 (ready)
排班中,等待CPU執行權。
結束 (terminated)
完成執行。
11
12
項目
描述
行程狀態
(Process State)
可以是 new、ready、running、waiting 或
halted 等
行程識別號
(Process Identifier)
Process 唯一的識別號,也就是 PID
• 行程控制表(Process Control Block, PCB)
程式計數器
接下來要執行的指令位址
–
是作業系統核心中一種資料結構,主要表示行
(Program Counter)
程狀態
CPU暫存器
(CPU Registers)
紀錄CPU暫存器的值,主要用途在於中斷時暫時
儲存資料,以便稍後繼續利用;其數量及類別因
電腦架構有所差異。
CPU排程資訊
包括行程的優先順序 (Priorlty)、排班佇列
(CPU Scheduling Information) (Scheduling queue) 的指標以及其它的排程參數
記憶體管理
(Memory-management
Information)
基底暫存器(base register) 和限制暫存器(limit
register),分頁表(Page table)值的資訊所使用
的記憶系統區段表(segment table)。
會計資訊
(Accounting Information)
如CPU與實際時間之使用數量、時限、帳號、工
作或行程號碼。
輸出輸入狀態
(I/O Status Information)
配置給行程的輸入/輸出裝置,包括開啟檔案的串
列 等等
13
14
• 緒程 (Thread)
– 一個指令序列,可直接存取所屬行程中的資源
– 是作業系統能夠進行運算調度的最小單位
– 每個行程至少有一個緒程
– 每個緒程每一個時刻必屬於某一個行程
– 有時候也被稱為輕量行程 (Lightweight
Process)
15
• 緒程 (Thread) 組成包含以下元素:
– 程式計數器
– CPU暫存器
• 目前 CPU 的狀態
– 堆疊空間 (Stack)
• 紀錄函式呼叫路徑以及函式所用到的變數等
– 排程優先權、已用掉的 CPU time
• 以便系統對不同的緒程做排程
16
• 一個行程 (Process) 中,可有多個緒程 (Thread)
• 同個行程中的緒程之間彼此共享
– 行程的狀態及資源
– 相同的記憶體空間 (Memory Space),存取相同
的資料
• User-level thread
• Kernel-level thread
17
• 應用程式自行管理 Thread
– 核心不會察覺 Thread 的存在
– 任何應用程式可使用 Thread
函式庫 (library),達到
Multi-Thread
– 由 Thread Library 來建立與
管理 (User mode)
• Thread 函式庫包括:
– 建立及刪除 Thread
– 在 Thread 間送訊息及資料
– Thread 排程
– … etc
18
• 優點
–
–
–
–
切換效率高
可根據應用程式的特性進行排程
可攜性高
Overhead 較低
• 缺點
– 當 Thread 執行有懸置性質 (blocking) 的系統呼叫
時,除了此 Thread 被懸置外,其餘 Thread 也會
遭懸置
– 在多處理器的環境下,User-Level Thread 只能在
一個 CPU 上執行
19
• 核心管理 Thread
– 提供 Thread 相關應用
程式介面(API)
– 由核心來建立及管理
20
• 優點
– Kernel-Level Thread 可在不同的 CPU 上平行
執行
– 當 Process 中的一個 Thread 被懸置,其他未
被懸置的 Thread 仍可執行
• 缺點
– Kernel-Level Threads 較沒效率
– Overhead 較高
– 可攜性低
21
• 如果作業系統支援 Kernel-Level Thread,
則排程通常在 Thread 的粒度上執行
• 衡量準則
– 公平性
– CPU 的有效利用
22
• FIFO (先進先出)
– 所有 Thread 構成一個 FIFO 的佇列
– 先到的先獲得執行權,直到執行結束後釋出
– 概念簡單,易於實作
– 演算法的實際效果可能非常不公平
• 若每個 Thread 所需的工作時間長短不一
23
• Round-Robin (時段輪轉)
– CPU 處理時間被切割成時間片段,稱為時段
– 以輪轉方式分配時段給每一個 Thread
– Thread 執行直到時段用完或是主動放棄執行權
– 概念簡單、易於實作
– 使用廣泛,也確實能公平分配處理器資源
24
• Priority-Based (優先層級)
– 每個 Thread 都有一個優先權值 (Priority)
– 高優先權的 Thread 優先被執行
– 相同優先權的 Thread 則使用 FIFO 或 RR
– 高優先權的 Thread 可能會霸佔 CPU 導致低優
先權的 Thread 沒有機會執行
– 導入了動態優先權的概念
• 連續執行多個時段的 Thread 要降低優先權
• 長時間沒有得到執行權的 Thread 提升優先權…等
25
26
章節地圖
3.1 行程基本觀念
3.1.1 多行程模型
3.1.2 行程與程式
3.2 緒程基本觀念
3.2.1 緒程模型
3.2.2 緒程排程演算法
3.2.3 緒程與行程的關係
3.3 Windows 的行程和緒程資料結構
3.3.1 核心層的行程和緒程物件
3.3.2 執行體層的行程和緒程物件
3.4 Windows 行程和緒程的管理
3.4.1 Windows 行程的控制代碼表
27
3.4.2 獲得目前的行程和緒程
28
PEB
TEB
EPROCESS
KPROCESS
_HANDLE_TABLE
ETHREAD
KTHREAD
29
Any Handle
Table
Object
Manager
Process
Object
Thread
Thread
Files
Events
Devices
Drivers
Process’
Handle Table
Virtual
Address
Descriptors
Thread
Thread
Thread
Thread
30
CreateProcess()
Locate imagefile (path search)
Convert DOS name to NT name
Call NtOpenFile()
Call NtCreateSection(SEC_IMAGE)
Check for special handling: VDM, WoW64, restrictions, CMD files
Call NtQuerySection() to get ImageInformation
Use LdrQueryImageFileExecutionOptions() to see if debugging
Special handling for POSIX executable
Create the new process in the kernel via NtCreateProcessEx()
If requested, call NtSetInformationProcess(ProcessPriorityClass)
If (dwCreationFlags & CREATE_DEFAULT_ERROR_MODE)
call NtSetInformationProcess(ProcessDefaultHardErrorMode)
31
Call BasePushProcessParameters() to push params into new process
Stuff in the standard handles if needed
Call BaseCreateStack() to create a user-mode stack in process
Call BaseInitializeContext() to create an initial thread context
Call NtCreateThread() to create the first thread
// thread may run, so no more modification to new process virtual
space
Use CsrClientCallServer(BasepCreateProcess) to register new
process and thread with CSRSS
If app is restricted
Set a restricted token on the process
assign it to a job object so that it can't escape the token.
Unless the initial thread was created suspended, start it with
NtResumeThread()
32
Header
PowerState
SwapListEntry
VdmTrapcHandler
ProfileListHead
IdealNode
DirectoryTableBase
Visited
ThreadListHead
LdtDescriptor
StackCount
ProcessLock
Int21Descriptor
ProcessListEntry
Affinity
IopmOffset
ProcessFlags
Iopl
BasePriority
ActiveProcessors
QuantumReset
KernelTime
State
UserTime
ReadyListHead
ThreadSeed
#include
<stdlib.h>
union { KernelTime
ULONG
Busy-waiting
SINGLE_LIST_ENTRY
SwapListEntry
DISPATCHER_HEADER
Header
UCHAR
State
ULONG_PTR
DirectoryTableBase[2]
ReadyListHead
LIST_ENTRY
ProcessListEntry
StackCount
BOOLEAN
Visited
KIDTENTRY
Int21Descriptor
#include
<stdio.h>
PVOID
VdmTrapcHandler
Iopl
struct
{
ProfileListHead
KAFFINITY
SCHAR
UCHAR
BasePriority
PowerState
Affinity
USHORT
volatile
KSPIN_LOCK
KAFFINITY
IopmOffset
ProcessLock
ActiveProcessors
ThreadListHead
IdealNode
KGDTENTRY
LdtDescriptor
Spin
Lock
QuantumReset
UCHAR
ThreadSeed
ULONG UserTime
struct Employee{
LONG AutoAlignment : 1;
記錄一個行程物件在Kernel
mode和User
mode
•1.
Singly
linked
list
structure。
兩個元素的陣列。
1.
KPROCESS物件是一個dispatcher
object。
說明Process是否在記憶體中
int
ID;
LONG
DisableBoost
:
1;
Doubly
linked
list
structure。
允許它們透過int
21h指令來呼叫DOS系統功能
定義了Process
指向處理Ctrl+C中斷的函式,僅用於VDM
I/O
Privelege
Level。
指定了該Process的thread可以在哪些處理器上
Thread的schedule參數。
記錄電源狀態,關於電源狀態管理(chap
該行程參與效能分析時,加入到全域的效能分
6.4)。
•1.
紀錄了目前Process中有多少thread的堆
將目前系統中所有具有活動Thread之
指定IOPM(I/O
主要是紀錄了目前行程正在哪些Processor上執
Thread的schedule參數。
Spinlock。
Privilege
Map,I/O權限表)。
WRK中未使用。
包含了該Process所有current
thread。
一個Process優先選擇的處理器節點(NUMA結構
Process的LDT(local
descriptor
table)描述項。
利用busy-waiting的技巧
••2.
為該行程的Thread選擇適當的Ideal
Process運用loop敍述執行來達到強迫暫停/等
下所花的時間。
Memory
第一個指向該行程的分頁目錄表位址。
2.
Dispatcher
object的定義及用法,參考Chap
• char
ProcessInMemory
name[7];
LONG
DisableQuantum
: 1;
紀錄了這個Process中處於就緒但尚未加入全域
(為了相容DOS)。
(Virtral
Dos
Machine)的環境下執行16位元
析行程清單(核心全域變數)中作為一個節點。
•2.
執行。
Process中的thread的基本優先層級。
行。
用來保護這個Process中的資料成員。
指定Process中thread基本配量重置值。
當Thread被建立時,便會加到此;終止的時候
概念)
主要是與segment的記憶體管理有關。
疊放至於記憶體中。
process串成一個串列
Processor(在Multiprocessor)。
待之效果。

Swap
out
•3.
Process的KernelTime和UserTime時間值等於其
Wait(s):
第二個指向該行程的hyper
5.4。
•1.int
ProcessOutOfMemory
salary;
LONG
ReservedFlags
: space的分頁目錄
29; I/O存取權限。
每個KPROCESS物件代表了一個行
程式。
所有Thread在啟動時都會繼承這個值。
•3.
Kernel透過IOPM控制User
確保Process資料結構的修改和存取是一致的。
在windows為6(chap
3.5會說明為什麼是6)。
mode的
從list中移除。
內容主要是與segment的起始位置,有效範圍

透過此欄位加入到KiProcessOutSwapListHead。
串列開頭為KIProcessListHead
•3. 就緒list的Thread。
每個Thread初始化時,都會拿這個的值作為它
所屬的Thread
KernelTime和UserTime的值之和。
whileswap
s <=
0 do no-op;
表位址。
當行程物件變成有信號狀態時(這發生在行程
•};While
ProcessInTransition
};程,反之亦然
當Process
out記憶體後,所屬的Thread
等相關屬性。

Swap
in
(condition)
do
no-op;
的Ideal
Processor。
•4.
s
=
s-1;
系统一般只使用DirectoryTableBase[0]。
結束時)此等待就會成功,讓thread
or
•4. 當Thread結束才會更新其Process的這兩個時間
ProcessOutTransition
LONG
 ProcessFlags;
透過此欄位加入到
如果就緒,它就會被掛在這裡,並要求swap
in
我們可在第4章中看到他分成GDT和LDT。
Threadseed會設置一個新值,以便給該
•Signal(s):
若條件式持續為True則Process會在此while
值。
2.};Process。
KPROCESS在EPROCESS建立起來
5.
我們只需要拿到目標行程裡的
KiProcessInSwapListHead(link file)。
process可以達到等待的動作。
•int
ProcessInSwap
main(){
Process的下一個Thread使用。
loop打轉,無法離開,形成waiting效果,直
•• typedef
只要Process尚未有任一Thread結束,則這兩個
sEmployee
=struct
s+1; _KPROCESS
{
DirectoryTableBase[0]值並直接設定到CR3中
ProcessOutSwap
struct
emp;
時建立
當Process進入到記憶體後,它會在將這串列上
到條件式為False,Process才離開while往下執
值是會為0。
就可以讀取了。
printf("size
of *PKPROCESS,*PRKPROCESS;
Employee
is %d\n", list。
•ProcessFlags:
缺點:waiting
process仍需同其它process爭
} 的東西全部加入到全域就緒Thread
KPROCESS,
3.
KPROCESS的位址和EPROCESS的
行。
6.
行程的分頁目錄表和hyper space參考chap 4。
sizeof(emp));
•1.
下面的code則是一個利用到ReadyListHead的例
奪cpu,將搶來的cpu
time用在無實質進展的
AutoAlignment
位址是相同的
system("pause");
子,它主要的工作就是,將所有的Thread加入
loop測試上,只是為了達到強迫等待之效果,
• 用於Process存取記憶體對齊的設置。
return
-1;
全域就緒Thread
list中。
此舉是浪費cpu
time。
• 也會被傳送到Thread的資料結構中,當
Process->State=ProcessInMemory;
•} 優點:節省不必要的context
switching,若
Thread得對齊檢查打開後,如果沒有對齊
NextEntry=Process->ReadyListHead.Flink;
process可以在極短的時間內,離開loop往下執
就會產生對齊錯誤。
While(NextEntry
!= &Process->ReadyListHead){
Thread=CONTAIN_RECORD(NextEntry, KTHREAD, WaitListEntry);
行,不被卡住,則spinlock是有利的。
• Intel
x86中並沒有作對齊檢查
RemoveEntryList(NextEntry);
Thread->ProcessReadyQueue=FALSE;
2. DisableBoost、DisableQuantum
KGDTENTRY
Intel x86 “區段+偏移”
KiReadyThread(Thread);//加入global ready thread list function
• 資料結構
這兩個旗標則是與Thread中的優先層級提
形式的邏輯位址解析過程
NextEntry=Process->ReadyListHead.Flink;
}
升與配量分配有關,(會在Chap 3.5中有
解說)
33
34
Header
WaitNext
MutantListHead
WaitReason
KernelNpxState
stack maintain
ThreadLock
WaitIrql
ApcState
WaitMode
ApcState所在union
WaitStatus
之後的欄位
ApcQueueLock
WaitBlockList
ContextSwitche
GateObject
State
Alertable
PVOID
InitialStack
DISPATCHER_HEADER
Header
typedef
struct
_KAPC_STATE
{
union
{
volatile
UCHAR
State
union
{
BOOLEAN
Alertable
ThreadLock
KSPIN_LOCK
ULONG
UCHAR
WaitReason
ContextSwitches
ApcQueueLock
KPROCESSOR_MODE
LONG_PTR
WaitStatus
WaitMode
KIRQL
WaitIrql
NpxState
BOOLEAN
WaitNext
LIST_ENTRY
MutantListHead
PVOID
StackLimit
LIST_ENTRY
ApcListHead[MaximumMode];
PKWAIT_BLOCK
WaitBlockList;
KAPC_STATE
ApcState;
KernelStack
struct
_KPROCESS
*Process;
PKGATE
GateObject;
••PVOID
Kernel層的Thread
object也是Dispatcher
struct
{
反應該Thread目前的狀態
Thread是否可以被喚醒。
Spin
lock。
記錄了該Thread進行多少次context
switch。
Spin
記錄Thread為什麼要等待的理由。
Lock。
記錄Thread等待時的Processor
記錄等待的結果狀態。
mode
記錄了原先的IRQL的值。
反映了浮點處理器的狀態。
•PVOID
True:表示這個Thread馬上要呼叫一個Kernel
指向list
head。
StackBase
BOOLEAN
KernelApcInProgress;
};object。
True:喚醒。
用於保護Thread資料成員。
保護APC
Queue的操作。
•• 不參與Thread排程或決策中。
 UCHAR
Kernel
Mode
等待函式。
包含所有屬於該Thread的mutant
BOOLEAN
KernelApcPending;
•1.1. Thread可以被等待。
ApcStateFill[KAPC_STATE_ACTUAL_LENGTH];
InitialStack
Windows

User
Mode 中的 thread 是系統處理
•• BOOLEAN
發出一個Signal後,Thread馬上會叫呼叫等待

一旦某個Thread等到了一個mutant則所
記錄了正在被等待的Gate
Object。
UserApcPending;
• 指向KWAIT_BLOCK為元素的串列。
當Thread結束時,該物件上的等待可被滿足。
BOOLEAN
ApcQueueable;
•
記錄原始Stack位置(高位址)。
函式,所以不用解除Thread排程器鎖。
器排程的基本單元,而且是在
有權歸讓Thread所有,它會被連接到
}•2.KAPC_STATE,
*PKAPC_STATE,
*PRKAPC_STATE;
等待Gate
Object和等待其它Dispatcher
每個KWAIT_BLOCK物件指明哪個Thread在
volatile
UCHAR
NextProcessor;
StackLimit
MutantListHead。
level 完成的,所以
object是不會同時發生。
volatile
UCHAR
DeferredProcessor;
等待哪個Dispatcher
object。
•Kernel
記錄Stack的低位址。
struct
_KTHREAD {
Include
APC
list。
UCHAR
AdjustReason;
•1.
GateObject和WaitBlockList構成一個
3. typedef
KernelStack
KTHREAD很多欄位與Windows的
每個KWAIT_BLOCK物件中的WaitListEntry
SCHAR
AdjustIncrement;
2.} union,共用一個指標記憶體。
是否正在處理
APC。
•thread排班機制有關。
記錄了真正Kernel呼叫stack的開始位置。
指明該Thread正在等待哪些Dispatcher
KTHREAD,
*PKTHREAD,*PRKTHREAD;
};• 記錄浮點處理器保存區和一個
3. 是否有Kernel
APC或是否有User
APC正
object;而每個Dispatcher
object,它
2.
有些欄位的涵義需結合Windows的
Typedf
struct
_KGATE{
};在等待
EXCEPTION
TRAP FRAME。
又有另一個KWAIT_BLOCK
LIST指明了哪些
DISPATCHER_HEADER
Header;
•
KernelStack的位置比InitialStack要低一
thread排班機制來了解。
4.
Process
欄位指向目前Thread所屬
••}KGATE,*PKGATE;
ApcQueueable
Thread正在等待它(Chap
5.4)。
ApcState是一個Struct
,指定了一個
些
Process的KPROCESS
 是否可插入APC。 結構。
 KTRAP_FRAME_LENGTH
+
thread的APC(Asynchronous
Procedure
5.
詳細內容於5.2.6節 非同步程序呼叫
• NextProcessor、DeferredProcessor
sizeof(FX_SAVE_AREA)
Calls)
information。
 關於處理器排程的選擇。
4. StackBase
KWAIT_BLCOCK、
KWAIT_BLCOCK
• AdjustReason、AdjustIncrement
KTHREAD、DISPATHER
• 記錄目前Stack的基底位置(高位址)。
 資料結構
優先層級調整原因和調整量。
關係圖
5. InitialStack和StackBase是相等的,都指向
Kernel stack高位址。
35
章節地圖
3.1 行程基本觀念
3.1.1 多行程模型
3.1.2 行程與程式
3.2 緒程基本觀念
3.2.1 緒程模型
3.2.2 緒程排程演算法
3.2.3 緒程與行程的關係
3.3 Windows 的行程和緒程資料結構
3.3.1 核心層的行程和緒程物件
3.3.2 執行體層的行程和緒程物件
3.4 Windows 行程和緒程的管理
3.4.1 Windows 行程的控制代碼表
37
3.4.2 獲得目前的行程和緒程
typedef struct _KTHREAD {
SCHAR Priority;
– 定義此Thread的優先層級,在執行過程中會變動
SCHAR BasePriority;
– 靜態的優先層級,初始值是所屬Process的BasePriority值,可透過
KeSetBasePriority函式重新設定
SCHAR PriorityDecrement;
– 紀錄其優先層級的變動值
– 優先層級在Windows分成兩層:
• 0~15:普通thread的優先層級
• 16~31:即時thread的優先層級
• 以上兩個區域彼此事不會互相跨越
CHAR Saturation;
– 說明此Thread相對於process的基本優先層級,調整量是否超過了整個區間的一
半,值為 0,1,-1
} KTHREAD, *PKTHREAD, *PRKTHREAD;
38
typedef struct _KTHREAD {
UCHAR EnableStackSwap;
– 為布林值,指出是否允許換出到外部記憶體。
volatile UCHAR SwapBusy;
– 為布林值,指出thread是否正在進行context swap。
BOOLEAN Alerted[MaximumMode];
– 為指定該thread在哪種警告模式下可以喚醒
• 在WRK中,警告模式只有使用者模式與核心模式,所以這個陣列含意是指
thread分別在這兩個模式下是否可以喚醒。
} KTHREAD, *PKTHREAD, *PRKTHREAD;
41
typedef struct _KTHREAD {
union {
LIST_ENTRY WaitListEntry;
– Thread在等待執行時,其會當作一個節點加入到某個序列中,也
就是KPROCESS中的WaitListEntry為起始的串列。
SINGLE_LIST_ENTRY SwapListEntry;
– 當thread的核心堆疊要換入時,插入到KiStackImSwapListHead。
– 當Thread處於DefferedReady的狀態時,其會將SwapListEntry插
入至DefferedReadyList Head串列中。
};
} KTHREAD, *PKTHREAD, *PRKTHREAD;
42
typedef struct _KTHREAD {
PRKQUEUE Queue;
– 為一個佇列發送器(分派器),如果不為NULL表示目前正處理此佇列
– 佇列機制,參考第5章
ULONG WaitTime;
– 紀錄了一個Thread進入等待時刻的時間點(低32位元),好讓平衡集
管理員可以根據這選項做出相對應的決策
} KTHREAD, *PKTHREAD, *PRKTHREAD;
43
typedef struct _KTHREAD {
union {
struct {
SHORT KernelApcDisable;
SHORT SpecialApcDisable;
1. 分別為16位元整數值,0:表示不禁止APC,負數表示禁止APC。
2. 因為多種因素造成要禁止他時,就會不停加上負值,直到消除時,才將這
個因素造成的負值補回,直到變成0為止。
3. 且只有當兩個欄位都為0時,才允許插入APC。
4. 2種核心模式APC,參考第5章(5.2.6節)
};
ULONG CombinedApcDisable;
兩欄位或者合
併成一個欄位
};
} KTHREAD, *PKTHREAD, *PRKTHREAD;
44
typedef struct _KTHREAD {
PVOID Teb;
– 指向Process位址空間的一個TEB結構。
} KTHREAD, *PKTHREAD, *PRKTHREAD;
45
typedef struct _KTHREAD {
KTIMER Timer;
– 是一個附在thread上的計時器,在實做可逾時的等待函式時
(KeWaitForSingleObject or KeWaitForMultiple)可以用到
union {
struct {
LONG AutoAlignment : 1;
LONG DisableBoost : 1;
LONG ReservedFlags : 30;
};
LONG ThreadFlags;
這兩個欄位是繼承Kprocess中的
同名欄位,所以用途相同。
};
} KTHREAD, *PKTHREAD, *PRKTHREAD;
48
typedef struct _KTHREAD {
union {
KWAIT_BLOCK WaitBlock[THREAD_WAIT_OBJECTS + 1];
有4個KWAIT_BLOCK成員的陣列
struct {
UCHAR WaitBlockFill0[KWAIT_BLOCK_OFFSET_TO_BYTE0];
BOOLEAN SystemAffinityActive;
};
struct {
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;
};
 WaitBlock是一個內建陣
列,如果Thread等待的物
件數量小於4不用另外分
配KWAIT_BLOCK物件記
憶體
 如果Thread等待的物件數
量大於4要另外分配
} KTHREAD, *PKTHREAD, *PRKTHREAD;
49
typedef struct _KTHREAD {
LIST_ENTRY QueueListEntry;
– 紀錄thread處理一個佇列項目時,他加入到佇列物件的thread串列中
的節點位址。
} KTHREAD, *PKTHREAD, *PRKTHREAD;
50
typedef struct _KTHREAD {
PKTRAP_FRAME TrapFrame;
– 紀錄控制流程狀態data structure
– TrapFrame欄位是一個thread中最關鍵的部分。
– 因為在windows中,thread式系統排程的基礎,代表一個行程中的一
個控制流程。當一個thread離開執行狀態時,他目前的執行狀態都
必續被記錄下來,以便下次來輪到這個thread執行時,可以恢復原
來的執行狀態。
– 例如:指令指標(IP)在指到哪裡、各個register的值是多少…等等。
PVOID CallbackStack;
– 包含thread的callback stack address,當thread從kernel mode呼叫
到user mode時使用
} KTHREAD, *PKTHREAD, *PRKTHREAD;
51
typedef struct _KTHREAD {
PVOID ServiceTable;
– 指向該thread使用的系統服務表(KeServiceDescriptorTable)
UCHAR IdealProcessor;
– 指明在多處理器的機器上,該thread的理想處理器
BOOLEAN Preempted;
– 表該thread是否被高優先層級的thread搶佔了
– 只有當一個thread正在執行或者正在等待執行而被高優先層級的thread
給搶暫時,這個值才會被設定為TRUE
} KTHREAD, *PKTHREAD, *PRKTHREAD;
52
typedef struct _KTHREAD {
BOOLEAN ProcessReadyQueue;
– 表一個thread是否在所屬的行程KPROCESS 物件的ReadyListHead串列中
BOOLEAN KernelStackResident;
– 說明該thread的核心堆疊是否駐留在記憶體中
– 當換入記憶體時在設定成TRUE
} KTHREAD, *PKTHREAD, *PRKTHREAD;
53
typedef struct _KTHREAD {
KAFFINITY Affinity;
1. 指定了thread的處理器親和性
2. Affinity 此值初始時繼承自行程物件的Affinity
值
3. 為thread指定的處理器集合必須是其行程的
親和性處理器集合的子集合。
4. 在thread執行過程中,Affinity的值有兩種可
能:
• 系統親和性,當該thread執行系統工作時透過
KeSetSystemAffinityThread函式來設置。
• Thread本身的親和性,稱為使用者親和性,透過
KeRevertToUserAffinityThread函式來設置。
} KTHREAD, *PKTHREAD, *PRKTHREAD;
54
typedef struct _KTHREAD {
KAFFINITY UserAffinity;
– 是thread的使用者親和性
– 此值初始時繼承自行程物件的Affinity值,之後可以透過核心函
式KeSetAffinityThread改變thread的使用親和性。
PKPROCESS Process;
– 指向thread的行程物件
– Process 在thread初始化時指定
UCHAR ApcStateIndex;
– 指目前APC狀態在ApcStatePointer欄位中的索引
PKAPC_STATE ApcStatePointer[2];
– 陣列元素的型別是指向KAPC_STATE的指標,兩個元素分別指向
thread物件的ApcState和SavedApcState
} KTHREAD, *PKTHREAD, *PRKTHREAD;
55
typedef struct _KTHREAD {
PVOID Win32Thread;
–
指向由Windows子系統管理的區域
union {
KAPC SuspendApc;
};
union {
KSEMAPHORE SuspendSemaphore;
struct {
 兩個Union欄位相互間有聯繫:
 SuspendApc 被初始化成一個專門的
APC,當該APC被插入並交付時,
KiSuspendThread函式被執行,其執行
結果是在thread的SuspendSemaphore
旗號上等待,直到該信號物件有信號,
然後thread被喚醒並且繼續執行。
 thread的suspend操作正是透過此一機制來
實作的。
 thread的resume操作則是透過控制
SuspendSemaphore 旗號的計數來實作的。
UCHAR SuspendSemaphorefill[KSEMAPHORE_ACTUAL_LENGTH];
ULONG SListFaultCount;};
};
} KTHREAD, *PKTHREAD, *PRKTHREAD;
56
typedef struct _KTHREAD {
LIST_ENTRY ThreadListEntry;
– 表一個雙串列上的節點
– 當一個thread 被建立時,他被加入到行程物件的ThreadListHead 串列
中
PVOID SListFaultAddress;
– 與user mode互鎖單串列POP操作的錯誤處理有關
– 紀錄了上一次user mode互鎖單串列操作發生分頁錯誤的address
} KTHREAD, *PKTHREAD, *PRKTHREAD;
57
1.
由於windows的thread排程演算法較複雜,以及他需要支援某些
硬體結構特性,所以KPROCESS and KTHREAD結構中,有些成
員的引入直接跟這些特性有關。
2.
核心層的process和thread object只包含了系統資源管理和多控
制流程並行執行所涉及的基本資訊。
3.
不含與應用程式相關聯的資訊(ex: process映像檔案和thread啟動
函式位址)。
4.
Process Object 提供了thread的基本執行環境。
5.
包含process address space和一組process範圍內公用的參數。
6.
Thread Object 提供了為參與thread 排程而必須的各種資訊及其
維護控制流程的狀態。
58
章節地圖
3.1 行程基本觀念
3.1.1 多行程模型
3.1.2 行程與程式
3.2 緒程基本觀念
3.2.1 緒程模型
3.2.2 緒程排程演算法
3.2.3 緒程與行程的關係
3.3 Windows 的行程和緒程資料結構
3.3.1 核心層的行程和緒程物件
3.3.2 執行體層的行程和緒程物件
3.4 Windows 行程和緒程的管理
3.4.1 Windows 行程的控制代碼表
59
3.4.2 獲得目前的行程和緒程
• 執行體層(Executive)提供各種管理策略,
並為上層應用程式提供基本功能介面
• 每一個process都由一個executive process
(EPROCESS) block表示
• 每一個thread又由一個executive thread
(ETHREAD) block表示
60
typedef struct _EPROCESS
{
KPROCESS Pcb;
EX_PUSH_LOCK ProcessLock;
LARGE_INTEGER CreateTime;
LARGE_INTEGER ExitTime;
EX_RUNDOWN_REF RundownProtect;
HANDLE UniqueProcessId;
LIST_ENTRY ActiveProcessLinks;
61
Field Name
Description
KPROCESS Pcb
KPROCESS的內嵌結構體。
系統內部一個行程的KPROCESS物件和
EPROCESS物件位址相同
EX_PUSH_LOCK ProcessLock
Push lock物件!
用於保護EPROCESS中的資料成員
LARGE_INTEGER CreateTime
行程的建立時間
LARGE_INTEGER ExitTime
行程的結束時間
EX_RUNDOWN_REF
RundownProtect
行程的停止保護鎖。
當一個行程最後被銷毀時,要等到其他所有
行程和緒程都釋放此鎖,才可繼續進行
HANDLE UniqueProcessId
行程的唯一編號,在行程建立時設定
LIST_ENTRY
ActiveProcessLinks
雙串列節點!
在Windows中,所有活動行程都連接在一起,
構成一個雙串列
62
SIZE_T
SIZE_T
SIZE_T
SIZE_T
SIZE_T
QuotaUsage [PsQuotaTypes];
QuotaPeak [PsQuotaTypes];
CommitCharge;
CommitChargeLimits;
CommitChargePeak;
SIZE_T PeakVirtualSize;
SIZE_T VirtualSize;
高峰值
65
Field Name
Description
SIZE_T
QuotaUsage [PsQuotaTypes]
行程的記憶體使用量
SIZE_T
QuotaPeak [PsQuotaTypes]
行程的記憶體尖峰使用量
SIZE_T CommitCharge
行程的virtual memory中page已使用的
數量
SIZE_T CommitChargeLimits
可使用page數量的最大值
SIZE_T CommitChargePeak
尖峰時刻已使用的page數量
SIZE_T VirtualSize
行程的virtual memory大小
SIZE_T PeakVirtualSize
virtual memory大小的尖峰值
66
LIST_ENTRY SessionProcessLinks;
PVOID DebugPort;
PVOID ExceptionPort;
PHANDLE_TABLE ObjectTable;
EX_FAST_REF Token;
...
} EPROCESS, *PEPROCESS;
67
Field Name
Description
LIST_ENTRY
SessionProcessLinks
雙串列節點。
當行程加入到一個系統工作階段中時,它會
作為一個節點加入該工作階段的行程串列中
PVOID DebugPort
控制代碼(handle)
指向偵錯埠
PVOID ExceptionPort
控制代碼(handle)
指向例外埠
PHANDLE_TABLE ObjectTable
行程的控制代碼表
EX_FAST_REF Token
快速引用。
指向行程的存取權杖,用於該行程的安全存
取檢查
68
typedef struct _EPROCESS
{
...
PFN_NUMBER WorkingSetPage;
KGUARDED_MUTEX AddressCreationLock;
KSPIN_LOCK HyperSpaceLock;
struct _ETHREAD *ForkInProgress;
ULONG_PTR HardwareTrigger;
69
Field Name
Description
PFN_NUMBER WorkingSetPage
指包含行程工作集的page
KGUARDED_MUTEX
AddressCreationLock
guarded mutex,
保護對位址空間的操作
KSPIN_LOCK HyperSpaceLock
Spin lock。
保護行程的超空間(hyper space)
struct _ETHREAD *
ForkInProgress
指向正在複製位址空間的thread
ULONG_PTR HardwareTrigger
WRK中沒有使用。
紀錄硬體錯誤效能分析次數
70
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;
71
Field Name
Description
PMM_AVL_TABLE
PhysicalVadRoot
指向行程實體VAD樹的根!
PVOID CloneRoot
指向一個平衡樹的根
PFN_NUMBER
NumberOfPrivatePages
行程私有page的數量
PFN_NUMBER
NumberOfLockedPages
行程被鎖住的page數量
PVOID Win32Process
指向由Windows子系統管理的行程區域的指標
struct _EJOB *Job
本書不討論Job物件
PVOID SectionObject
代表行程記憶體區段物件的指標
PVOID
SectionBaseAddress
該記憶體區段物件的基底位址
PEPROCESS_QUOTA_BLOCK
QuotaBlock
指向行程的配額區塊
72
PPAGEFAULT_HISTORY WorkingSetWatch;
HANDLE Win32WindowStation;
HANDLE InheritedFromUniqueProcessId;
PVOID
PVOID
PVOID
PVOID
LdtInformation;
VadFreeHint;
VdmObjects;
DeviceMap;
...
} EPROCESS, *PEPROCESS;
74
Field Name
Description
PPAGEFAULT_HISTORY
WorkingSetWatch
用於監視一個行程的page fault,
由全域變數PsWatchEnabled控制
HANDLE Win32WindowStation
一個行程所屬的視窗工作站的控制代碼
HANDLE
父行程的PID
InheritedFromUniqueProcessId
PVOID LdtInformation
用來維護一個行程的LDT資訊
(Local Descriptor Table)
PVOID VadFreeHint
指向一個提示VAD節點,
用於加速在VAD樹中執行搜尋的操作
PVOID VdmObjects
指向目前行程的VDM資料區。
VDM型別為VDM_PROCESS_OBJECTS,
行程可透過NtVdmControl系統服務來初
始化VDM
PVOID DeviceMap
指向行程使用的裝置表
75
typedef struct _EPROCESS
{
...
PVOID Spare0[3];
Union{
HARDWARE_PTE PageDirectoryPte;
ULONGLONG Filler;
};
PVOID Session;
UCHAR ImageFileName[ 16 ];
LIST_ENTRY JobLinks;
PVOID LockedPagesList;
76
Field Name
Description
PVOID Spare0[3]
待命欄位,WRK沒有使用
HARDWARE_PTE
PageDirectoryPte
上層分頁目錄頁面的分頁表項目!
PVOID Session
指向行程所在的系統工作階段。
是一個指向MM_SESSION_SPACE的指標
UCHAR ImageFileName[ 16 ]
行程的映像檔名,
僅包含最後一個路徑分隔符號之後的字串
LIST_ENTRY JobLinks
雙串列節點。
一個Job中的所有行程構成一個雙串列!
PVOID LockedPagesList
指向LOCK_HEADER結構的指標。
該結構包含一個串列開頭,Windows透過
此串列紀錄哪些page已被鎖住
77
LIST_ENTRY ThreadListHead;
PVOID SecurityPort;
PVOID PaeTop;
ULONG ActiveThreads;
ACCESS_MASK GrantedAccess;
ULONG DefaultHardErrorProcessing;
NTSTATUS LastThreadExitStatus;
PPEB Peb;
...
} EPROCESS, *PEPROCESS;
80
Field Name
Description
LIST_ENTRY ThreadListHead
雙串列的頭節點!
此串列包含一個行程中的所有緒程
PVOID SecurityPort
安全埠。
指向該行程與lsass行程之間跨行程通訊埠
PVOID PaeTop
支援PAE記憶體存取機制
ULONG ActiveThreads
記錄目前行程有多少個活動threads
ACCESS_MASK GrantedAccess
行程的存取權限
ULONG
指定硬體錯誤處理的預設值
DefaultHardErrorProcessing
NTSTATUS
LastThreadExitStatus
記錄最後一個thread的結束狀態
PPEB Peb
一個行程的行程環境區塊!
81
typedef struct _EPROCESS
{
...
EX_FAST_REF PrefetchTrace;
LARGE_INTEGER
LARGE_INTEGER
LARGE_INTEGER
LARGE_INTEGER
LARGE_INTEGER
LARGE_INTEGER
ReadOperationCount;
WriteOperationCount;
OtherOperationCount;
ReadTransferCount;
WriteTransferCount;
OtherTransferCount;
84
Field Name
Description
EX_FAST_REF PrefetchTrace
快速引用。
指向與該行程關聯的一個預取痕跡結構
LARGE_INTEGER
ReadOperationCount
目前行程NtReadFile系統服務被呼叫次數
LARGE_INTEGER
WriteOperationCount
目前行程NtWriteFile系統服務被呼叫次
數
LARGE_INTEGER
OtherOperationCount
記錄除讀寫操作以外的其他I/O服務次數
LARGE_INTEGER
ReadTransferCount
記錄I/O讀取操作完成次數
LARGE_INTEGER
WriteTransferCount
記錄I/O寫入操作完成次數
LARGE_INTEGER
OtherTransferCount
記錄非讀寫操作完成次數
85
PVOID AweInfo;
SE_AUDIT_PROCESS_CREATION_INFO SeAuditProcessCreationInfo;
MMSUPPORT Vm;
LIST_ENTRY MmProcessLinks;
ULONG ModifiedPageCount;
ULONG JobStatus;
86
Field Name
Description
PVOID AweInfo
指向AWEINFO結構的指標。
以支援AWE!
SE_AUDIT_PROCESS_CREATION_INFO
SeAuditProcessCreationInfo
包含建立行程時指定的行程映像檔全
路徑名稱
MMSUPPORT Vm
Windows為每個行程管理虛擬記憶體
的資料結構成員
LIST_ENTRY MmProcessLinks
雙串列節點!
所有擁有自己位址空間的行程都加入
到這個雙串列中
ULONG ModifiedPageCount
記錄行程已修改的page數量
ULONG JobStatus
記錄行程所屬Job狀態
87
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, *PEPROCESS
90
Field Name
Description
ULONG Flags
包含了行程的旗標位元
NTSTATUS ExitStatus
行程的結束狀態
USHORT NextPageColor
用於實體頁面分配演算法
UCHAR
SubSystemMinorVersion
行程的子系統主版本序號
UCHAR
SubSystemMajorVersion
行程的子系統次版本序號
UCHAR PriorityClass
行程的priority
MM_AVL_TABLE VadRoot
指向一個平衡二元樹的根
ULONG Cookie
一個代表行程的隨機值。
透過NtQueryInformationProcess函式獲取
91
章節地圖
3.1 行程基本觀念
3.1.1 多行程模型
3.1.2 行程與程式
3.2 緒程基本觀念
3.2.1 緒程模型
3.2.2 緒程排程演算法
3.2.3 緒程與行程的關係
3.3 Windows 的行程和緒程資料結構
3.3.1 核心層的行程和緒程物件
3.3.2 執行體層的行程和緒程物件
3.4 Windows 行程和緒程的管理
3.4.1 Windows 行程的控制代碼表
92
3.4.2 獲得目前的行程和緒程
在Windows下,會給每個Process
建立一個EPROCESS結構,相對應
的緒程也會建立一個ETHREAD結構
而ETHREAD結構的第一個成員會是
KTHREAD結構。
每個行程的緒程的ETHREAD結構都
會按右圖所示連結起來
圖源
http://kost0911.pixnet.net/blog/post/61607285
http://flylib.com/books/en/1.242.1.65/1/
93
typedef struct _ETHREAD
定址一個64
{
位元的有號
KTHREAD Tcb;
數整數
LARGE_INTEGER CreateTime;
記錄執行緒
的建立時間
union {
LARGE_INTEGER ExitTime;
LIST_ENTRY LpcReplyChain;
LIST_ENTRY KeyedWaitChain;
};
所有的緒程會透過
……..
此結構串在一個雙
向循環串列上
記錄執行緒的
結束時間
用於跨行程通訊
用於帶鍵事件的
等待串列
94
32位元整數,針對驅
動程式的部分去傳回
程式狀態
union {
NTSTATUS ExitStatus;
PVOID OfsChain;
沒用到!
};
一個指標指向空
的型態(void *)
LIST_ENTRY PostBlockList;
結束狀態
向"組態管理員
(Reporting Services)"
登記"登錄機碼"的變化
通知所有已
通知 登記要接收
其終止事件
的那些port
union {
PTERMINATION_PORT TerminationPort;
struct _ETHREAD *ReaperLink;
僅在thread結束時
PVOID KeyedWaitValue;
使用 ,使kernel
帶鍵事件的按鍵值
};
stack可回收 97
LIST_ENTRY ActiveTimerListHead;
ULONG ActiveTimerListLock;
參數
UniqueProcess Cid;
CLIENT_ID
UniqueThread
包含目前緒
程中的所有
timer
控制此list的
spin lock
意義
包含thread的
所屬process的UniqueProcessID
唯一識別字
process控制代碼表中的控制代碼
用於LPC應
union {
答通知
KSEMAPHORE LpcReplySemaphore;
KSEMAPHORE KeyedWaitSemaphore;
用於處理
帶鍵的事
};
98
件
帶有要回覆應
union {
答的訊息
PVOID LpcReplyMessage;
PVOID LpcWaitingOnPort;
說明在哪個
};
指向thread
base\ntos\lpc\lpcp.h
port上等待
的模仿資訊
PPS_IMPERSONATION_INFORMATION ImpersonationInfo;
LIST_ENTRY IrpList;
ULONG TopLevelIrp;
包含目前thread
所有正在處理但
未完成的I/O請求
指向thread的上層IRP,或指向
NULL或一個IRP
99
struct _DEVICE_OBJECT *DeviceToVerify
指向目前所
屬的
process
PERPROCESS ThreadsProcess;
PVOID StartAddress;
指向一個待
檢驗的裝置
包含thread
的真正啟動
位址
union {
PVOID Win32StartAddress;
ULONG LpcReceivedMessageId;
windows子系
統接受到的
thread啟動位
址
};
接收到的LPC訊息ID
101
LIST_ENTRY ThreadListEntry;
thread加到所屬
Eprocess結構的
ThreadListHead中
EX_RUNDOWN_REF RundownProtect;
EX_PUSH_LOCK ThreadLock;
thread的停止
protected
lock
用來保護thread的
資料屬性
ULONG LpcReceivedMessageId;
等待要回覆的
MessageId
102
ULONG ReadClusterSize;
一次I/O操作要讀
取幾個頁面
ACCESS_MASK GrantedAccess;
public\sdk\inc\ntpsapi.h
union {
ULONG CrossThreadFlags;
struct {...};
};
存取權限
針對跨thread存取
的flag位元
103
union {
ULONG SameThreadPassiveFlags;
只能在最低中斷層
struct {...};
級才可存取,且只
能被自身存取
};
union {
ULONG SameThreadApcFlags;
struct {...};
};
在APC中斷層
級上被自身存
取的flag
105
BOOLEAN ForwardClusterOnly;
是否僅向前聚集?
BOOLEAN DisablePageFaultClustering;
控制頁面交
換的聚集與
否
UCHAR ActiveFaultCount;
} ETHREAD, *PETHREAD;
正在進行的分
頁錯誤數量
106
章節地圖
3.1 行程基本觀念
3.1.1 多行程模型
3.1.2 行程與程式
3.2 緒程基本觀念
3.2.1 緒程模型
3.2.2 緒程排程演算法
3.2.3 緒程與行程的關係
3.3 Windows 的行程和緒程資料結構
3.3.1 核心層的行程和緒程物件
3.3.2 執行體層的行程和緒程物件
3.4 Windows 行程和緒程的管理
3.4.1 Windows 行程的控制代碼表
107
3.4.2 獲得目前的行程和緒程
• “In computer programming, a handle is a particular kind
of smart pointer.”
• The Windows API heavily uses handles to:
– represent objects in the system
– provide a communication pathway between the operating
system and user space.
• For example, a window on the desktop is represented by a
handle of type HWND (handle, window).
http://en.wikipedia.org/wiki/Handle_%28computing%29
108
• 在 Windows 中
– handle是process範圍內的物件參考
– handle僅在一個process範圍內才有效
– handle是一個索引,指向所在process的handle
table中的一個項目
– 一個handle table包含所有已被該process開啟的
物件之指標
109
• 在 Windows Server 2003 中
– handle table為一多層結構,資料型態為HANDLE_TABLE
– 每一個handle table entry結構為HANDLE_TABLE_ENTRY,
其大小為8 bytes
– Windows執行體在分配handle table記憶體時按照分頁
(4KB)來申請記憶體
– 每申請一個分頁來存放handle table entry,handle table
容量增加512
– 這些結構都被定義在base\ntos\inc\ex.h
110
111
typedef struct _HANDLE_TABLE {
ULONG_PTR TableCode; // 指向handle table最頂層的指標
struct _EPROCESS *QuotaProcess; // 紀錄handle table記憶體資源的process
HANDLE UniqueProcessId; // process ID,用於callback function
EX_PUSH_LOCK HandleTableLock[HANDLE_TABLE_LOCKS];
// 僅在擴充handle table時使用。 HANDLE_TABLE_LOCKS = 4
LIST_ENTRY HandleTableList; // 所有handle table所形成的串列
EX_PUSH_LOCK HandleContentionEvent; // 當race condition發生時使用
PHANDLE_TRACE_DEBUG_INFO DebugInfo; // 偵錯資訊,偵錯時方有意義
112
LONG ExtraInfoPages; // 稽核資訊所佔用的分頁數量
ULONG FirstFree; // 紀錄空閒handle的索引值
ULONG LastFree; // 紀錄最近被釋放之handle的索引值
ULONG NextHandleNeedingPool;// 下一次擴充handle table的起始索引值
LONG HandleCount; // 使用中handle的數量
union {
ULONG Flags;
BOOLEAN StrictFIFO : 1;
};
} HANDLE_TABLE, *PHANDLE_TABLE;
113
• TableCode是一個指向handle table最頂層頁面的指標,其最低2位
元代表目前table的層數:
– 00: 僅一層,該process最多只能容納512 handles (LOWLEVEL_THRESHOLD)
– 01: 兩層,process可容納512*1024 handles (MIDLEVEL_THRESHOLD)
– 10: 三層,process可容納512*1024*1024 handles (HIGHLEVEL_THRESHOLD)
• Windows 執行體限制每個process的handle數目不得超過224 =
16,777,216個 (MAX_HANDLES)
• 實際上,每個最低層handle table頁面的第一個handle table entry
有特殊用途,真正可供process使用的handles只有512 - 1個
114
115
• 執行體在建立process時,會先為其分配一單層的
handle table
• handle table是透過ExCreateHandleTable函式來
完成的
• 隨著process中的handle數量增加,
ExpAllocateHandleTableEntry函式會呼叫
ExpAllocateHandleTableEntrySlow函式將handle
table擴充到兩層至三層
• 上述函式的實作程式碼位於
base\ntos\ex\handle.c
116
NTKERNELAPI 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);
ExAcquirePushLockExclusive( &HandleTableListLock );
InsertTailList( &HandleTableListHead, &HandleTable->HandleTableList ); // 將handle table 插入list
ExReleasePushLockExclusive( &HandleTableListLock );
KeLeaveCriticalRegionThread (CurrentThread);
return HandleTable;
}
117
typedef struct _HANDLE_TABLE_ENTRY {
union {
// 指向此handle所代表的物件
PVOID Object;
ULONG ObAttributes; // 最低三位元具有特別意義
PHANDLE_TABLE_ENTRY_INFO InfoTable; //紀錄每個handle table分頁第一個entry
ULONG_PTR Value;
};
union {
union {
ACCESS_MASK GrantedAccess; // 存取遮罩
struct {
USHORT GrantedAccessIndex;
USHORT CreatorBackTraceIndex;
};
};
LONG NextFreeTableEntry; // 空閒時表示下一個空閒handle之索引
};
} HANDLE_TABLE_ENTRY, *PHANDLE_TABLE_ENTRY;
118
• Object指標指向了handle所代表的kernel object
• 其最低3位元具有特別的含義:
– 第0位: OBJ_PROTECT_CLOSE,表示呼叫者是否允許關閉該handle
// 在WRK中,關閉保護位元被移到GrantedAccess成員,
// 而此位元變成handle table entry的lock flag
– 第1位: OBJ_INHERIT,指示該process之sub process可否繼承該handle
– 第2位: OBJ_AUDIT_OBJECT_CLOSE,指示關閉該object時是否產生一稽
核事件
119
• 一個有效的handle有四種可能的值:
– -1 : 代表目前的process
– -2 : 代表目前的thread
– <0 : 其絕對值為kernel handle table的索引,僅限kernel mode的函式
使用
– < 226 : 目前process的handle table索引
• kernel handle table
– 是指系統空間中的global handle table
– 即WRK中的ObpKernelHandleTable變數
– 只能在kernel mode下被使用
– 可以位於任何一個process environment中,故為跨行程環境
120
121
• 解析handle的基本函式是ObReferenceObjectByHandle
• 其程式碼位於base\ntos\ob\obref.c
• 首先判斷傳入之handle值屬於前述4種情形的哪一種
– -1 或 -2 : 無需搜尋handle table,檢查process/thread存取權限
後即可回傳物件
– <0 或 <226 :
1.
2.
3.
4.
先呼叫ExMapHandleToPointerEx函式找到該handle索引值所指到的
handle entry
並檢查其存取權限是否滿足要求
再呼叫ObpAuditObjectAccess進行稽核
最後回傳物件主體
(ExMapHandleToPointerEx函式呼叫ExpLookupHandleTableEntry函式來
122
搜尋handle table到最底層的項目)
• 將物件插入到handle table的是ObInsertObject函式
• 其程式碼位於base\ntos\ob\obinsert.c
• 函式簡略流程:
– 首先對參數作各種檢查
– 呼叫ObpCreateHandle函式
1.
為要插入的物件建立handle
2.
呼叫ExCreateHandle建立handle entry
123
• 物件的引用方式有兩種:
1. 在kernel中透過物件的位址來引用
•
這是透過ObReferenceObjectByPointer函式來記
錄引用次數
2. 透過handle來引用物件
•
由ObpIncrementHandleCount函式來檢查並記
錄handle的引用
124
•
•
•
在WRK中, handle的生命週期的起點為:
–
被插入到handle table
–
ObpCreateHandle
→ ObpIncrementHandleCount
handle生命週期的終點:
–
handle被關閉
–
ObpCloseHandle
→ ObpCloseHandleTableEntry
→ ObpDecrementHandleCount
此外,當handle呼叫ObReferenceObjectByHandle後,若該物件
指標不再使用,必須呼叫ObDeferenceObject
125
1. 作為物件引用的容器
2. 分配process、thread的unique ID
– Process : UniqueProcessId
– Thread : Cid
– ExCreateHandle在全域的handle table叫做PspCidTable
(Client ID handle table)中建立的handle索引值
– PspCidTable中的handle entry包含process或thread的物
件位址
126
• process和thread的unique ID都是4的倍數
– 0 是專門保留給空閒的process
• 並非透過ExCreateHandle函式獲得
– 4 是第一個handle索引值,被分配給System process的unique ID
• CID handle table按照Strict FIFO來重用handle entry
• 在kernel中,根據process/thread的唯一ID可方便找到相關物件位址
– PsLookupProcessThreadByCid
– PsLookupProcessByProcessId
– PsLookupThreadByThreadId
(上述三函式位於base\ntos\pscid.c)
127
• KeGetCurrentThread函式傳回目前處理器
上正在執行的緒程的KTHREAD結構指標
• 透過此結構資訊,進一步可得到
KPROCESS、ETHREAD和EPROCESS結構。
128
FORCEINLINE
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
}
• 以上程式碼實際上是用來存取FS暫存器上特定偏移的指令
• 藉此以取得目前Thread之KTHREAD結構指標
129
• FS暫存器指向一塊被稱為處理器控制區的
記記憶體(PCR),其資料型別為KPCR。
• KPCR有一個型別為KPRCB的資料成員
PrcbData,這是目前處理器的控制區塊
(Processor Control Block),其中包含了指
向目前緒程的KTHREAD結構的指標。
130
• KPRCB 是一個 structure,在_KPRCB
structure 包含了:
struct _KTHREAD *CurrentThread; < = target
struct _KTHREAD *NextThread;
struct _KTHREAD *IdleThread;
• 我們能從其中一項結構找到 CurrentThread 的所在
131
• 獲得了目前緒程的KTHREAD結構的指標後,
便可方便地獲得ETHREAD結構的指標,以
及KPROCESS或EPROCESS結構的指標。
• 在執行體層上獲得目前緒程或行程的函式
分別是PsGetCurrentThread和
PsGetCurrentProcess。
132
#define _PsGetCurrentProcess() (CONTAINING_RECORD \
(((KeGetCurrentThread()) -> ApcState.Process), EPROCESS, Pcb))
#define _PsGetCurrentThread() ((PETHREAD) KeGetCurrentThread())
PEPROCESS
PsGetCurrentProcess(VOID) {
return _PsGetCurrentProcss() ;
}
PETHREAD
PsGetCurrentThread(VOID) {
return _PsGetCurrentThread() ;
}
133
• _PsGetCurrentProcess從目前緒程KTHREAD
結構的ApcState成員中獲得目前緒程所屬行程
的KPROCESS結構。
• 即使目前緒程附加到其他行程中,或又回到原
先行程中,ApcState總能獲得正確的目前行程
結構的指標,故不是從KTHREAD的Process欄
位或ETHREAD的ThreadsProcess欄位獲得行
程結構的指標。
• 作法請參考5.2.6節 APC環境的敘述
134
135
• Process
– http://zh.wikipedia.org/wiki/%E8%A1%8C%E7%A8%8B
– http://zh.wikipedia.org/wiki/%E8%A1%8C%E7%A8%8B%E6%8E%A
7%E5%88%B6%E8%A1%A8
– http://en.wikipedia.org/wiki/Process_control_block
– http://www.personal.kent.edu/~rmuhamma/OpSystems/Myos/proc
essControl.htm
• Thread
http://ppt.cc/dnzk
http://programming.im.ncnu.edu.tw/J_Chapter9.htm
http://ccckmit.wikidot.com/thread
http://zh.wikipedia.org/wiki/%E5%9F%B7%E8%A1%8C%E7%B7%92
http://wiki.answers.com/Q/What_is_the_difference_between_user_le
vel_threads_and_kernel_level_threads
– http://nixchun.pixnet.net/blog/post/7044425-os---5.-threads
–
–
–
–
–
136
• Operating System Concepts, 8/e (IE-Paperback)
•
•
•
– Abraham Silberschatz, Peter Baer Galvin, Greg Gagne
http://www.nirsoft.net/kernel_struct/vista/KPROCESS.html
http://doxygen.reactos.org/df/d2c/structKPROCESS_adf7c1ea8dabdb9
aad4ea79dc089ac110.html#adf7c1ea8dabdb9aad4ea79dc089ac110
http://www.google.com.tw/url?sa=t&rct=j&q=&esrc=s&source=web&
cd=5&ved=0CIABEBYwBA&url=http%3A%2F%2Fi-web.i.utokyo.ac.jp%2Fedu%2Ftraining%2Fss%2Flecture%2Fnewdocuments%2FLectures%2F13-Processes%2FProcesses.ppt&ei=CrGsTH1KOHUmAXWyaWoBA&usg=AFQjCNF1eR9Y5RHYyLve8rZxC0oePurt8
A&sig2=Yx2jydJtDuDuYSCmIfKxwg
137
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
EPROCESS
PUSH LOCK
LIST_ENTRY
CommitCharge
FAST_REF(P.28)
EX_FAST_REF
Working Set
Working Set
Hyper Space
VAD
EJOB
LDT
MM_SESSION_SPACE
PAE
AWE
Vista EPROCESS
138
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
http://msdn.microsoft.com/zh-tw/library/ms123401
http://hi.baidu.com/solohac/blog/item/b536d02ef45b67321f3089cd.html
http://blog.csdn.net/imquestion/article/details/16423
http://kost0911.pixnet.net/blog/post/61607285
http://flylib.com/books/en/1.242.1.65/1/
http://news.ccidnet.com/art/32859/20100714/2114941_2.html
http://blog.csdn.net/better0332/article/details/4292433
http://doxygen.reactos.org/dd/d05/ndk_2pstypes_8h_source.html#l00877
http://book.51cto.com/art/201011/235760.htm
http://bazislib.sysprogs.org/dox/a00166.html
http://puremonkey2010.blogspot.com/2011/01/windows-ddp_31.html
http://en.wikipedia.org/wiki/I/O_request_packet
http://fsinternals.com/?p=29
http://pollos-blog.blogspot.com/2007/09/windows-driver-programming5.html
http://www.nirsoft.net/kernel_struct/vista/ETHREAD.html
http://msdn.moonsols.com/msdn
139
140
Download