1 内核层的进程和线程对象
typedef struct _KPROCESS {
DISPATCHER_HEADER Header;
LIST_ENTRY ProfileListHead;
ULONG_PTR DirectoryTableBase[2];
KGDTENTRY LdtDescriptor;
KIDTENTRY Int21Descriptor;
USHORT IopmOffset;
UCHAR Iopl;
BOOLEAN Unused;
volatile KAFFINITY ActiveProcessors;
ULONG KernelTime;
ULONG UserTime;
LIST_ENTRY ReadyListHead;
SINGLE_LIST_ENTRY SwapListEntry;
PVOID VdmTrapcHandler;
LIST_ENTRY ThreadListHead;
KSPIN_LOCK ProcessLock;
KAFFINITY Affinity;
#define KPROCESS_AUTO_ALIGNMENT_BIT 0
#define KPROCESS_DISABLE_BOOST_BIT 1
#define KPROCESS_DISABLE_QUANTUM_BIT 2
union {
struct {
LONG AutoAlignment : 1;
LONG DisableBoost : 1;
LONG DisableQuantum : 1;
LONG ReservedFlags : 29;
};
LONG ProcessFlags;
};
SCHAR BasePriority;
SCHAR QuantumReset;
UCHAR State;
UCHAR ThreadSeed;
UCHAR PowerState;
UCHAR IdealNode;
BOOLEAN Visited;
union {
KEXECUTE_OPTIONS Flags;
UCHAR ExecuteOptions;
};
ULONG_PTR StackCount;
LIST_ENTRY ProcessListEntry;
} KPROCESS, *PKPROCESS, *PRKPROCESS;
每个KPROCESS对象都代表一个进程,即每个进程都拥有一个KPROCESS对象。
Header :一个分发器对象(dispatcher object),表明进程对象本身是可以被等待的。
ProfileListHead : 用于该进程参与性能分析(profiling)时,作为一个节点加入到全局的性能分析进程列表(KiProfileListHead)中。
DirectoryTableBase : 只有两项的数组,第一项指向该进程的页目录表地址,第二项指向该进程的超空间(hyper space)的页目录表地址。
LdtDescriptor、Int2lDescriptor、IopmOffset、Iopl是专门针对Intel x86处理器的。
LdtDescriptor :该进程的LDT(局部描述符表)的描述符
Int2lDescriptor :为了兼容DOS程序,允许它们通过int 21h指令来调用DOS系统功能
IopmOffset :指定了IOPM(I/O权限表,I/O Privilege Map)的位置,内核通过IOPM可控制进程的用户模式I/O访问权限
Iopl : 定义了进程的I/O优先级(I/O Privilege Level)
ActiveProcessors : 记录了当前进程正在哪些处理器上运行
KernerTime ,UserTime :记录内核模式和用户模式所花的时间
ReadyListHead : 记录该进程中处于就绪状态但尚未被加入全局就绪链表的线程
SwapListEntry : 一个单链表项,当一个进程要被换出内存时,它通过此域加入到以KiProcessOutSwapListHead为链头的单链表中;当一个进程要被换入内存时,它通过此域加入到以KiProcessInSwapListHead为链头的单链表中;
VdmTrapcHandler : 指向处理Ctrl+C 中断的函数,仅用于在VDM(虚拟DOS机,Virtual DOS Machine) 环境下运行16位程序
ThreadListHead : 一个链表头,包含了该进程的所有当前线程
ProcessLock : 一个自旋锁(spin lock)对象,用于保护此进程中的数据成员
Affinity : 指定了该进程的线程可以在哪些处理器上运行,其类型时KAFFINITY
ProcessFlags : 包括了进程中的几个标志:AutoAlignment、DisableBoost、DisableQuantum。AutoAlignment 位用于该进程中的内存访问对齐设置。DisableBoost和DisableQuantum位与线程调度过程中的优先级提升和时限(quantum) 分配有关
BasePriority : 用于指定一个进程中的线程基本优先权,所有的线程在启动时都会继承进程的BasePriority值。
QuantumReset : 用于指定一个进程中线程的基本时限重置值,现代Windows版本中被设置为6
State : 说明了一个进程是否存在内存中,共有六种可能的状态:ProcessInMemory、ProcessOutOfMemory、ProcessInTransition、ProcessOutTransition、ProcessInSwap、ProcessOutSwap。
ThreadSeed :用于为该进程的线程选择适当的理想处理器(Ideal processor)
PowerState : 用于记录电源状态
IdealNode : 用于为一个进程选择优先的处理器节点,是进程初始化时设定的
Visited : wrk 未使用
ExecuteOptions : 用于设置一个进程的内存执行选项
StackCount : 记录了当前进程中有多少个线程的栈位于内存中
ProcessListEntry : 用于将当前系统中所有具有活动线程的进程串成一个链表,链表头为KiProcessListHead
总结:KPROCESS对象中记录的信息主要包括两类:一类跟进程内存环境相关,比如与目录表,交换状态等;
另一类是与其线程相关的一些属性,比如线程列表以及线程所需要的优先级、时限设置等、
线程的数据结构分三部分列出,第一部分
typedef struct _KTHREAD {
DISPATCHER_HEADER Header;
LIST_ENTRY MutantListHead;
PVOID InitialStack;
PVOID StackLimit;
PVOID KernelStack;
KSPIN_LOCK ThreadLock;
union {
KAPC_STATE ApcState;
struct { ... };
};
KSPIN_LOCK ApcQueueLock;
ULONG ContextSwitches;
volatile UCHAR State;
BOOLEAN Alertable;
BOOLEAN WaitNext;
UCHAR WaitReason;
UCHAR NpxState;
KIRQL WaitIrql;
KPROCESSOR_MODE WaitMode;
LONG_PTR WaitStatus;
union {
PKWAIT_BLOCK WaitBlockList;
PKGATE GateObject;
};
} KTHREAD, *PKTHREAD, *PRKTHREAD;
Header : 一个分发器对象,线程也可以被等待。
MutantListHead : 指向一个链表头,包含了所有属于该线程的突变体对象(mutant,对应于API中的互斥体[mutex]对象)。
InitialStack : 记录了原始的栈位置(高地址)。
StackLimit : 记录了栈的低地址。
KernelStack : 记录了真正内核调用栈的开始位置。
StackBase : 记录了当前栈的基位置(高地址),在线程初始化时,InitialStack 和StackBase 是相等的,都指向原始的内核栈高地址。
ThreadLock : 一个自旋锁,用于保护线程数据成员。
ApcState : 指定了一个线程的APC(Asynchronous Procedure Call)信息。
ContextSwitches : 记录了该线程进行了多少次环境切换。
State : 反应了该线程当前的状态。关于线程的状态,请参考base\ntos\inc\ke.h 中的KTHREAD_STATE枚举类型。
NpxState : 反应了浮点处理器的状态。
Alertable : 说明了一个线程是否可以被唤醒,当一个线程正在等待时,如果Alertbale值为TRUE,则它可以被唤醒。
WaitNext : 在发出一个信号后,接下来该线程会马上调用等待函数。
WaitIrql : 与WaitNext 一起使用,当WaitNext 为TRUE时,WaitIrql 记录了原先的IRQL值。
WaitReason : 记录了一个线程的等待理由。
WaitMode : 记录了当线程等待时的处理器模式,即内核模式或用户模式的等待。
WaitStatus : 记录了等待的结果状态。
WaitBlockList : 指向一个以KWAIT_BLOCK 为元素的链表,其中的KWAIT_BLOCK对象指明了哪个线程在等待哪个分发器对象。
GateObject : 记录了正在等待的门对象。等待门对象和等待其他分发器对象不会同时发生的
KTHREAD结构定义的第二部分:
typedef struct _KTHREAD {
/*前面已列出并解释了第一部分*/
SCHAR Priority;
SCHAR BasePriority;
SCHAR PriorityDecrement;
CHAR Saturation;
UCHAR EnableStackSwap;
volatile UCHAR SwapBusy;
BOOLEAN Alerted[MaximumMode];
union {
LIST_ENTRY WaitListEntry;
SINGLE_LIST_ENTRY SwapListEntry;
};
PRKQUEUE Queue;
ULONG WaitTime;
union {
struct {
SHORT KernelApcDisable;
SHORT SpecialApcDisable;
};
ULONG CombinedApcDisable;
};
PVOID Teb;
KTIMER Timer;
union {
struct {
LONG AutoAlignment : 1;
LONG DisableBoost : 1;
LONG ReservedFlags : 30;
};
LONG ThreadFlags;
};
union {
KWAIT_BLOCK WaitBlock[THREAD_WAIT_OBJECTS + 1];
....................
};
LIST_ENTRY QueueListEntry;
}
Priority : 包含了该线程的(动态)优先级值。
BasePriority : 线程的静态优先级,其初始值时所属进程的BasePriority值,可通过KeSetBasePriorityThread函数设定。
PriorityDecrement : 记录了一个线程在优先级动态调整过程中的递减值。Windows中的优先级被分为两个区域:0-15 是普通线程的优先级,16-31是实时线程的优先级。
Saturation : 说明了线程的基本优先级相对于进程的优先级的调整量是否超过了整个区间的一半,其值为0、1或-1。
EnableStackSwap : 说明本线程的内核栈是否允许被换出到外存中。
SwapBusy : 指定了本线程当前是否正在进行上下文环境切换(context swap)。
Alerted : 一个数组,指定了该线程在每一种警告模式下是否可以被唤醒。
WaitListEntry 和SwapListEntry : 分别是一个双链表节点和一个单链表节点,它们是一个union,用于不同的情形。当一个线程正在等待被执行时,WaitListEntry作为一个线程节点加入到某个链表中。SwaitListEntry 则被用于当线程的内核栈需要被换入时,插入到全局变量KiStackInSwapListHead为链表头的单链表中。
Queue : 一个队列分发器对象,如果不为NULL,则表示当前线程正在处理此对了对象中的项。
WaitTime : 记录了一个线程进入等待时刻的时间点。
KernelApcDisable 和SpecialApcDisable 或者CombinedApcDisable : KernelApcDIsable和SpecialApcDisable ,0 表示不禁止APC,负数表示禁止APC。
Teb : 指向进程地址空间中的一个TEB(线程环境块)结构,包含了在用户地址空间中需要访问的各种信息,例如与线程相关的GDI信息、系统支持的异常,Winsock 信息等。
Timer : 附在一个线程上的定时器。
AutoAlignment 和DisableBoost : 直接继承自所属进程的同名标记,参考KPROCESS成员。
WaitBlock : 一个包含4 个KWAIT_BLOCK成员的数组,其中第4 项专门用于等待的定时器对象。
QueueListEntry : 记录了线程在处理一个队列项时加入到队列对象的线程链表中的节点地址。
KTHREAD 结构定义的第三部分:
typedef struct _KTHREAD {
/*前面已列出并解释了第一和第二部分*/
PKTRAP_FRAME TrapFrame;
PVOID CallbackStack;
PVOID ServiceTable;
UCHAR IdealProcessor;
BOOLEAN Preempted;
BOOLEAN ProcessReadyQueue;
BOOLEAN KernelStackResident;
KAFFINITY UserAffinity;
PKPROCESS Process;
KAFFINITY Affinity;
UCHAR ApcStateIndex;
PKAPC_STATE ApcStatePointer[2];
union {
KAPC_STATE SavedApcState;
struct {
...
};
};
PVOID Win32Thread;
PVOID StackBase;
union {
KAPC SuspendApc;
...
};
union {
KSEMAPHORE SuspendSemaphore;
struct {
UCHAR SuspendSemaphorefill[KSEMAPHORE_ACTUAL_LENGTH];
ULONG SListFaultCount;
};
};
LIST_ENTRY ThreadListEntry;
PVOID SListFaultAddress;
} KTHREAD, *PKTHREAD, *PRKTHREAD;
TrapFrame : 一个线程中最为关键的部分。记录控制流状态的数据结构,它是一个指向KTRAP_FRAME 类型的指针。
CallbackStack : 包含了线程的回调(callback)栈地址,此栈在该线程从内核模式调用到用户模式时使用。
ServiceTable : 指向该线程使用的系统服务表(全局变量KeServiceDescriptorTable),如果这是一个图形用户界面(GUI)线程,此域将指向影子系统服务表(全局变量KeServiceDescriptorTableShadow)。
IdealProcessor : 指明了在多处理器的机器上该线程的理想处理器。
Preempted : 说明这个线程是否被高优先级的线程抢占了,只有当一个线程正在运行或者正在等待运行而被高优先级线程抢占的时候,此值才会置为TRUE。
ProcessReadyQueue : 说明一个线程是否在所属进程KPROCESS对象的ReadyListHead 链表中,TRUE表示在此链表中。
KernelStackResident : 说明该线程的内核栈是否驻留在内存中,当线程栈被换出内存时,置为FALSE;当换入内存时,置为TRUE。
Affinity : 指定了线程的处理器亲和性,初始时继承自进程对象的Affinity 值。
Process : 指向线程的进程对象,在线程初始化时指定。
ApcStateIndex : 一个索引值,指明了当前的APC状态在ApcStatePointer 中的索引。
Win32Thread : 指向由Windows子系统管理的区域。
SuspendApc 和 SuspendSemaphore 两个union 相互之间有联系,SuspendApc被初始化成一个专门的APC。当该APC被插入并交付时,KiSuspendThread函数被执行,其执行结果时在线程的SuspendSemaphore 信号量上等待,直到该信号量对象有信号,然后线程被唤醒并继续执行。
ThreadListEntry : 一个双链表上的节点,当一个线程被创建时,它会被加入到进程对象的ThreadListHead 链表中,参考KPROCESS的ThreadListHead。
SListFaultAddress : 与用户模式互锁单链表POP操作(KeUserPopEntrySListFault函数)的错误处理有关,记录了上一次用户模式互锁单链表POP操作发生页面错误的地址
SuspendSemaphore : 记录了在地址SListFaultAddress 上发生页面错误的次数。