3.KPCR,等待链表,调度链表

30 篇文章 5 订阅
17 篇文章 2 订阅

一、内容回顾

内容回顾

进程在内核中对应结构体:EPROCESS

线程在内核中对应结构体:ETHREAD

CPU在内核中也有一个对应的结构体:KPCR

二、KPCR结构

kd> dt _KPCR
nt!_KPCR
   +0x000 NtTib            : _NT_TIB
   +0x01c SelfPcr          : Ptr32 _KPCR
   +0x020 Prcb             : Ptr32 _KPRCB
   +0x024 Irql             : UChar
   +0x028 IRR              : Uint4B
   +0x02c IrrActive        : Uint4B
   +0x030 IDR              : Uint4B
   +0x034 KdVersionBlock   : Ptr32 Void
   +0x038 IDT              : Ptr32 _KIDTENTRY
   +0x03c GDT              : Ptr32 _KGDTENTRY
   +0x040 TSS              : Ptr32 _KTSS
   +0x044 MajorVersion     : Uint2B
   +0x046 MinorVersion     : Uint2B
   +0x048 SetMember        : Uint4B
   +0x04c StallScaleFactor : Uint4B
   +0x050 DebugActive      : UChar
   +0x051 Number           : UChar
   +0x052 Spare0           : UChar
   +0x053 SecondLevelCacheAssociativity : UChar
   +0x054 VdmAlert         : Uint4B
   +0x058 KernelReserved   : [14] Uint4B
   +0x090 SecondLevelCacheSize : Uint4B
   +0x094 HalReserved      : [16] Uint4B
   +0x0d4 InterruptMode    : Uint4B
   +0x0d8 Spare1           : UChar
   +0x0dc KernelReserved2  : [17] Uint4B
   +0x120 PrcbData         : _KPRCB
kd> dt _KPRCB
ntdll!_KPRCB
   +0x000 MinorVersion     : Uint2B
   +0x002 MajorVersion     : Uint2B
   +0x004 CurrentThread    : Ptr32 _KTHREAD
   +0x008 NextThread       : Ptr32 _KTHREAD
   +0x00c IdleThread       : Ptr32 _KTHREAD
   +0x010 Number           : Char
   +0x011 Reserved         : Char
   +0x012 BuildType        : Uint2B
   +0x014 SetMember        : Uint4B
   +0x018 CpuType          : Char
   +0x019 CpuID            : Char
   +0x01a CpuStep          : Uint2B
   +0x01c ProcessorState   : _KPROCESSOR_STATE
   +0x33c KernelReserved   : [16] Uint4B
   +0x37c HalReserved      : [16] Uint4B
   +0x3bc PrcbPad0         : [92] UChar
   +0x418 LockQueue        : [16] _KSPIN_LOCK_QUEUE
   +0x498 PrcbPad1         : [8] UChar
   +0x4a0 NpxThread        : Ptr32 _KTHREAD
   +0x4a4 InterruptCount   : Uint4B
   +0x4a8 KernelTime       : Uint4B
   +0x4ac UserTime         : Uint4B
   +0x4b0 DpcTime          : Uint4B
   +0x4b4 DebugDpcTime     : Uint4B
   +0x4b8 InterruptTime    : Uint4B
   +0x4bc AdjustDpcThreshold : Uint4B
   +0x4c0 PageColor        : Uint4B
   +0x4c4 SkipTick         : Uint4B
   +0x4c8 MultiThreadSetBusy : UChar
   +0x4c9 Spare2           : [3] UChar
   +0x4cc ParentNode       : Ptr32 _KNODE
   +0x4d0 MultiThreadProcessorSet : Uint4B
   +0x4d4 MultiThreadSetMaster : Ptr32 _KPRCB
   +0x4d8 ThreadStartCount : [2] Uint4B
   +0x4e0 CcFastReadNoWait : Uint4B
   +0x4e4 CcFastReadWait   : Uint4B
   +0x4e8 CcFastReadNotPossible : Uint4B
   +0x4ec CcCopyReadNoWait : Uint4B
   +0x4f0 CcCopyReadWait   : Uint4B
   +0x4f4 CcCopyReadNoWaitMiss : Uint4B
   +0x4f8 KeAlignmentFixupCount : Uint4B
   +0x4fc KeContextSwitches : Uint4B
   +0x500 KeDcacheFlushCount : Uint4B
   +0x504 KeExceptionDispatchCount : Uint4B
   +0x508 KeFirstLevelTbFills : Uint4B
   +0x50c KeFloatingEmulationCount : Uint4B
   +0x510 KeIcacheFlushCount : Uint4B
   +0x514 KeSecondLevelTbFills : Uint4B
   +0x518 KeSystemCalls    : Uint4B
   +0x51c SpareCounter0    : [1] Uint4B
   +0x520 PPLookasideList  : [16] _PP_LOOKASIDE_LIST
   +0x5a0 PPNPagedLookasideList : [32] _PP_LOOKASIDE_LIST
   +0x6a0 PPPagedLookasideList : [32] _PP_LOOKASIDE_LIST
   +0x7a0 PacketBarrier    : Uint4B
   +0x7a4 ReverseStall     : Uint4B
   +0x7a8 IpiFrame         : Ptr32 Void
   +0x7ac PrcbPad2         : [52] UChar
   +0x7e0 CurrentPacket    : [3] Ptr32 Void
   +0x7ec TargetSet        : Uint4B
   +0x7f0 WorkerRoutine    : Ptr32     void 
   +0x7f4 IpiFrozen        : Uint4B
   +0x7f8 PrcbPad3         : [40] UChar
   +0x820 RequestSummary   : Uint4B
   +0x824 SignalDone       : Ptr32 _KPRCB
   +0x828 PrcbPad4         : [56] UChar
   +0x860 DpcListHead      : _LIST_ENTRY
   +0x868 DpcStack         : Ptr32 Void
   +0x86c DpcCount         : Uint4B
   +0x870 DpcQueueDepth    : Uint4B
   +0x874 DpcRoutineActive : Uint4B
   +0x878 DpcInterruptRequested : Uint4B
   +0x87c DpcLastCount     : Uint4B
   +0x880 DpcRequestRate   : Uint4B
   +0x884 MaximumDpcQueueDepth : Uint4B
   +0x888 MinimumDpcRate   : Uint4B
   +0x88c QuantumEnd       : Uint4B
   +0x890 PrcbPad5         : [16] UChar
   +0x8a0 DpcLock          : Uint4B
   +0x8a4 PrcbPad6         : [28] UChar
   +0x8c0 CallDpc          : _KDPC
   +0x8e0 ChainedInterruptList : Ptr32 Void
   +0x8e4 LookasideIrpFloat : Int4B
   +0x8e8 SpareFields0     : [6] Uint4B
   +0x900 VendorString     : [13] UChar
   +0x90d InitialApicId    : UChar
   +0x90e LogicalProcessorsPerPhysicalProcessor : UChar
   +0x910 MHz              : Uint4B
   +0x914 FeatureBits      : Uint4B
   +0x918 UpdateSignature  : _LARGE_INTEGER
   +0x920 NpxSaveArea      : _FX_SAVE_AREA
   +0xb30 PowerState       : _PROCESSOR_POWER_STATE

三、重要成员介绍

1、KPCR介绍

  1. 当线程进入0环时,FS:[0]指向KPCR(3环时FS:[0] -> TEB)

  2. 每个CPU都有一个KPCR结构体(一个核一个)

  3. KPCR中存储了CPU本身要用的一些重要数据:GDT、IDT以及线程相关的一些信息。

struct	_NT_TIB
{
	+0x000 ExceptionList    : Ptr32_EXCEPTION_REGISTRATION_RECORD	//当前线程内核异常链表(SEH),但你使用try/except语句会往这里加一个
	
	+0x004 StackBase        : Ptr32 Void
   	+0x008 StackLimit       : Ptr32 Void
	//当前线程内核栈的基址和大小

	+0x018 Self             : Ptr32 _NT_TIB	//指向自己(也就是指向KPCR结构) 这样设计的目的是为了查找方便,
}
struct	KPCR
{
	+0x01c SelfPcr          : Ptr32 _KPCR
	//指向自己,方便寻址,通过IDA分析可以知道不少系统dll都通过fs[0x1c]来指向自己	
	
	+0x020 Prcb             : Ptr32 _KPRCB
	//指向拓展结构体PRCB  
	
	+0x038 IDT              : Ptr32 _KIDTENTRY
	//IDT表基址
	+0x03c GDT              : Ptr32 _KGDTENTRY
	//GDT表基址

	+0x040 TSS              : Ptr32 _KTSS
	//指针,指向TSS,每个CPU都有一个TSS.

	+0x051 Number           : UChar
	//CPU编号:0 1 2 3 4 5。。。

	+0x120 PrcbData         : _KPRCB
	//拓展结构体

}
struct	KPRCB 
{	
	+0x004 CurrentThread    : Ptr32 _KTHREAD	// 当前线程
   	+0x008 NextThread       : Ptr32 _KTHREAD	// 即将切换的下一个线程
   	+0x00c IdleThread       : Ptr32 _KTHREAD 	// 空闲线程 这个类型应该是一个函数,指向IdleThread函数
}

四、等待/调度链表

上一节课我们讲了进程结构体EPROCESS(0x50和0x190)是2个链表,里面圈着当前进程所有的线程。

对进程断链,程序可以正常运行,原因是CPU执行与调度是基于线程的,进程断链只是影响一些遍历系统进程的API,并不会影响程序执行。

对线程断链也是一样的,断链后在Windbg或者OD中无法看到被断掉的线程,但并不影响其执行(仍然再跑)。

为什么线程断链之后程序还在运行?理由很简单,因为操作系统没有使用这个链表来调度线程,这个链表只是给我们看的,不是给系统看的!
在这里插入图片描述

1、33个链表

线程有3种状态:就绪、等待、运行

正在运行中的线程存储在KPCR中,就绪和等待的线程全在另外的33个链表中。
一个等待链表,32个就绪链表:

这些链表都使用了_KTHREAD(0x060)这个位置,也就是说,线程在某一时刻,只能属于其中一个圈。

2、等待链表

kd> dd KiWaitListHead

比如:线程调用了Sleep() 或者 WaitForSingleObject()等函数时,就挂到这个链表

3、调度链表

调度链表有32个圈,就是优先级:0 - 31 0最低 31最高 默认优先级一般是8

改变优先级就是从一个圈里面卸下来挂到另外一个圈上

这32个圈是正在调度中的线程:包括正在运行的和准备运行的

比如:只有一个CPU但有10个线程在运行,那么某一时刻,正在运行的线程在KPCR中,其他9个在这32个圈中。

4、查看调度链表

既然有32个链表,就要有32个链表头。

kd> dd KiDispatcherReadyListHead L70

5、版本差异

XP只有一个33个圈,也就是说上面这个数组只有一个,多核也只有一个.

Win7也是一样的只有一个圈,如果是64位的,那就有64个圈.

服务器版本:KiWaitListHead整个系统只有一个,但KiDispatcherReadyListHead这个数组有几个CPU就有几组

6、总结:

1、正在运行的线程在KPCR中

2、准备运行的线程在32个调度链表中(0 - 31级),KiDispatcherReadyListHead 是个数组存储了这32个链表头.

3、等待状态的线程存储在等待链表中,KiWaitListHead存储链表头.

4、这些圈都挂一个相同的位置:_KTHREAD(0x060)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值