Windows线程研究——基础知识

moshui Lv3

基础结构

与进程相似的在内核层具有_KTHREAD_ETHREAD两个结构体

KTHREAD

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
0: kd> dt _KTHREAD
nt!_KTHREAD
+0x000 Header : _DISPATCHER_HEADER
+0x018 SListFaultAddress : Ptr64 Void
+0x020 QuantumTarget : Uint8B
+0x028 InitialStack : Ptr64 Void
+0x030 StackLimit : Ptr64 Void
+0x038 StackBase : Ptr64 Void
+0x040 ThreadLock : Uint8B
+0x048 CycleTime : Uint8B
+0x050 CurrentRunTime : Uint4B
+0x054 ExpectedRunTime : Uint4B
+0x058 KernelStack : Ptr64 Void
+0x060 StateSaveArea : Ptr64 _XSAVE_FORMAT
+0x068 SchedulingGroup : Ptr64 _KSCHEDULING_GROUP
+0x070 WaitRegister : _KWAIT_STATUS_REGISTER
+0x071 Running : UChar
+0x072 Alerted : [2] UChar
+0x074 AutoBoostActive : Pos 0, 1 Bit
+0x074 ReadyTransition : Pos 1, 1 Bit
+0x074 WaitNext : Pos 2, 1 Bit
+0x074 SystemAffinityActive : Pos 3, 1 Bit
+0x074 Alertable : Pos 4, 1 Bit
+0x074 UserStackWalkActive : Pos 5, 1 Bit
+0x074 ApcInterruptRequest : Pos 6, 1 Bit
+0x074 QuantumEndMigrate : Pos 7, 1 Bit
+0x074 UmsDirectedSwitchEnable : Pos 8, 1 Bit
+0x074 TimerActive : Pos 9, 1 Bit
+0x074 SystemThread : Pos 10, 1 Bit
+0x074 ProcessDetachActive : Pos 11, 1 Bit
+0x074 CalloutActive : Pos 12, 1 Bit
+0x074 ScbReadyQueue : Pos 13, 1 Bit
+0x074 ApcQueueable : Pos 14, 1 Bit
+0x074 ReservedStackInUse : Pos 15, 1 Bit
+0x074 UmsPerformingSyscall : Pos 16, 1 Bit
+0x074 TimerSuspended : Pos 17, 1 Bit
+0x074 SuspendedWaitMode : Pos 18, 1 Bit
+0x074 SuspendSchedulerApcWait : Pos 19, 1 Bit
+0x074 CetUserShadowStack : Pos 20, 1 Bit
+0x074 BypassProcessFreeze : Pos 21, 1 Bit
+0x074 Reserved : Pos 22, 10 Bits
+0x074 MiscFlags : Int4B
+0x078 ThreadFlagsSpare : Pos 0, 2 Bits
+0x078 AutoAlignment : Pos 2, 1 Bit
+0x078 DisableBoost : Pos 3, 1 Bit
+0x078 AlertedByThreadId : Pos 4, 1 Bit
+0x078 QuantumDonation : Pos 5, 1 Bit
+0x078 EnableStackSwap : Pos 6, 1 Bit
+0x078 GuiThread : Pos 7, 1 Bit
+0x078 DisableQuantum : Pos 8, 1 Bit
+0x078 ChargeOnlySchedulingGroup : Pos 9, 1 Bit
+0x078 DeferPreemption : Pos 10, 1 Bit
+0x078 QueueDeferPreemption : Pos 11, 1 Bit
+0x078 ForceDeferSchedule : Pos 12, 1 Bit
+0x078 SharedReadyQueueAffinity : Pos 13, 1 Bit
+0x078 FreezeCount : Pos 14, 1 Bit
+0x078 TerminationApcRequest : Pos 15, 1 Bit
+0x078 AutoBoostEntriesExhausted : Pos 16, 1 Bit
+0x078 KernelStackResident : Pos 17, 1 Bit
+0x078 TerminateRequestReason : Pos 18, 2 Bits
+0x078 ProcessStackCountDecremented : Pos 20, 1 Bit
+0x078 RestrictedGuiThread : Pos 21, 1 Bit
+0x078 VpBackingThread : Pos 22, 1 Bit
+0x078 ThreadFlagsSpare2 : Pos 23, 1 Bit
+0x078 EtwStackTraceApcInserted : Pos 24, 8 Bits
+0x078 ThreadFlags : Int4B
+0x07c Tag : UChar
+0x07d SystemHeteroCpuPolicy : UChar
+0x07e UserHeteroCpuPolicy : Pos 0, 7 Bits
+0x07e ExplicitSystemHeteroCpuPolicy : Pos 7, 1 Bit
+0x07f RunningNonRetpolineCode : Pos 0, 1 Bit
+0x07f SpecCtrlSpare : Pos 1, 7 Bits
+0x07f SpecCtrl : UChar
+0x080 SystemCallNumber : Uint4B
+0x084 ReadyTime : Uint4B
+0x088 FirstArgument : Ptr64 Void
+0x090 TrapFrame : Ptr64 _KTRAP_FRAME
+0x098 ApcState : _KAPC_STATE
+0x098 ApcStateFill : [43] UChar
+0x0c3 Priority : Char
+0x0c4 UserIdealProcessor : Uint4B
+0x0c8 WaitStatus : Int8B
+0x0d0 WaitBlockList : Ptr64 _KWAIT_BLOCK
+0x0d8 WaitListEntry : _LIST_ENTRY
+0x0d8 SwapListEntry : _SINGLE_LIST_ENTRY
+0x0e8 Queue : Ptr64 _DISPATCHER_HEADER
+0x0f0 Teb : Ptr64 Void
+0x0f8 RelativeTimerBias : Uint8B
+0x100 Timer : _KTIMER
+0x140 WaitBlock : [4] _KWAIT_BLOCK
+0x140 WaitBlockFill4 : [20] UChar
+0x154 ContextSwitches : Uint4B
+0x140 WaitBlockFill5 : [68] UChar
+0x184 State : UChar
+0x185 Spare13 : Char
+0x186 WaitIrql : UChar
+0x187 WaitMode : Char
+0x140 WaitBlockFill6 : [116] UChar
+0x1b4 WaitTime : Uint4B
+0x140 WaitBlockFill7 : [164] UChar
+0x1e4 KernelApcDisable : Int2B
+0x1e6 SpecialApcDisable : Int2B
+0x1e4 CombinedApcDisable : Uint4B
+0x140 WaitBlockFill8 : [40] UChar
+0x168 ThreadCounters : Ptr64 _KTHREAD_COUNTERS
+0x140 WaitBlockFill9 : [88] UChar
+0x198 XStateSave : Ptr64 _XSTATE_SAVE
+0x140 WaitBlockFill10 : [136] UChar
+0x1c8 Win32Thread : Ptr64 Void
+0x140 WaitBlockFill11 : [176] UChar
+0x1f0 Ucb : Ptr64 _UMS_CONTROL_BLOCK
+0x1f8 Uch : Ptr64 _KUMS_CONTEXT_HEADER
+0x200 ThreadFlags2 : Int4B
+0x200 BamQosLevel : Pos 0, 8 Bits
+0x200 ThreadFlags2Reserved : Pos 8, 24 Bits
+0x204 Spare21 : Uint4B
+0x208 QueueListEntry : _LIST_ENTRY
+0x218 NextProcessor : Uint4B
+0x218 NextProcessorNumber : Pos 0, 31 Bits
+0x218 SharedReadyQueue : Pos 31, 1 Bit
+0x21c QueuePriority : Int4B
+0x220 Process : Ptr64 _KPROCESS
+0x228 UserAffinity : _GROUP_AFFINITY
+0x228 UserAffinityFill : [10] UChar
+0x232 PreviousMode : Char
+0x233 BasePriority : Char
+0x234 PriorityDecrement : Char
+0x234 ForegroundBoost : Pos 0, 4 Bits
+0x234 UnusualBoost : Pos 4, 4 Bits
+0x235 Preempted : UChar
+0x236 AdjustReason : UChar
+0x237 AdjustIncrement : Char
+0x238 AffinityVersion : Uint8B
+0x240 Affinity : _GROUP_AFFINITY
+0x240 AffinityFill : [10] UChar
+0x24a ApcStateIndex : UChar
+0x24b WaitBlockCount : UChar
+0x24c IdealProcessor : Uint4B
+0x250 NpxState : Uint8B
+0x258 SavedApcState : _KAPC_STATE
+0x258 SavedApcStateFill : [43] UChar
+0x283 WaitReason : UChar
+0x284 SuspendCount : Char
+0x285 Saturation : Char
+0x286 SListFaultCount : Uint2B
+0x288 SchedulerApc : _KAPC
+0x288 SchedulerApcFill0 : [1] UChar
+0x289 ResourceIndex : UChar
+0x288 SchedulerApcFill1 : [3] UChar
+0x28b QuantumReset : UChar
+0x288 SchedulerApcFill2 : [4] UChar
+0x28c KernelTime : Uint4B
+0x288 SchedulerApcFill3 : [64] UChar
+0x2c8 WaitPrcb : Ptr64 _KPRCB
+0x288 SchedulerApcFill4 : [72] UChar
+0x2d0 LegoData : Ptr64 Void
+0x288 SchedulerApcFill5 : [83] UChar
+0x2db CallbackNestingLevel : UChar
+0x2dc UserTime : Uint4B
+0x2e0 SuspendEvent : _KEVENT
+0x2f8 ThreadListEntry : _LIST_ENTRY
+0x308 MutantListHead : _LIST_ENTRY
+0x318 AbEntrySummary : UChar
+0x319 AbWaitEntryCount : UChar
+0x31a AbAllocationRegionCount : UChar
+0x31b SystemPriority : Char
+0x31c SecureThreadCookie : Uint4B
+0x320 LockEntries : Ptr64 _KLOCK_ENTRY
+0x328 PropagateBoostsEntry : _SINGLE_LIST_ENTRY
+0x330 IoSelfBoostsEntry : _SINGLE_LIST_ENTRY
+0x338 PriorityFloorCounts : [16] UChar
+0x348 PriorityFloorCountsReserved : [16] UChar
+0x358 PriorityFloorSummary : Uint4B
+0x35c AbCompletedIoBoostCount : Int4B
+0x360 AbCompletedIoQoSBoostCount : Int4B
+0x364 KeReferenceCount : Int2B
+0x366 AbOrphanedEntrySummary : UChar
+0x367 AbOwnedEntryCount : UChar
+0x368 ForegroundLossTime : Uint4B
+0x370 GlobalForegroundListEntry : _LIST_ENTRY
+0x370 ForegroundDpcStackListEntry : _SINGLE_LIST_ENTRY
+0x378 InGlobalForegroundList : Uint8B
+0x380 ReadOperationCount : Int8B
+0x388 WriteOperationCount : Int8B
+0x390 OtherOperationCount : Int8B
+0x398 ReadTransferCount : Int8B
+0x3a0 WriteTransferCount : Int8B
+0x3a8 OtherTransferCount : Int8B
+0x3b0 QueuedScb : Ptr64 _KSCB
+0x3b8 ThreadTimerDelay : Uint4B
+0x3bc ThreadFlags3 : Int4B
+0x3bc ThreadFlags3Reserved : Pos 0, 8 Bits
+0x3bc PpmPolicy : Pos 8, 2 Bits
+0x3bc ThreadFlags3Reserved2 : Pos 10, 22 Bits
+0x3c0 TracingPrivate : [1] Uint8B
+0x3c8 SchedulerAssist : Ptr64 Void
+0x3d0 AbWaitObject : Ptr64 Void
+0x3d8 ReservedPreviousReadyTimeValue : Uint4B
+0x3e0 KernelWaitTime : Uint8B
+0x3e8 UserWaitTime : Uint8B
+0x3f0 GlobalUpdateVpThreadPriorityListEntry : _LIST_ENTRY
+0x3f0 UpdateVpThreadPriorityDpcStackListEntry : _SINGLE_LIST_ENTRY
+0x3f8 InGlobalUpdateVpThreadPriorityList : Uint8B
+0x400 SchedulerAssistPriorityFloor : Int4B
+0x404 Spare28 : Uint4B
+0x408 EndPadding : [5] Uint8B

以下是一些关键结构

1
2
3
+0x028 InitialStack
+0x030 StackLimit
+0x038 StackBase

分别表示了栈底(高地址)、栈顶(低地址)、保存栈地址的变量。

  • 有关线程等待的:
    • +0x074 Alertable : Pos 4, 1 Bit: 说明线程是否可以被唤醒。

    • +0x072 Alerted : [2] UChar :指示r0、r1下的唤醒状态,[0]是r0下的,[1]是r3下的。 值为1就是一种就绪等待状态,可随时唤醒,0则是一种死等待。

    • +0x0c8 WaitStatus : Int8B: 记录了等待的结果状态。

    • +0x074 WaitNext : Pos 2, 1 Bit:1表示这个线程马上要调用一个内核等待函数。

    • +0x186 WaitIrql : UChar:当WaitNext为1时,该位置记录了原先的IRQL值。

    • +0x187 WaitMode : Char:记录了处理器的模式,内核模式或用户模式。

    • +0x1b4 WaitTime : Uint4B: 记录了一个线程进入等待时刻的时间点(时钟滴答值的低32位)。

    • +0x0d0 WaitBlockList : Ptr64 _KWAIT_BLOCK: 该成员指向了一个以KWAIT_BLOCK为元素的链表,其中KWAIT_BLOCK对象指明了哪个线程在等待哪个分发器对象。

    • +0x0d8 WaitListEntrySwapListEntry 分别是一个双向链表和单向链表节点,它们是一个联合体。当线程等待执行的时候WaitListEntry作为线程节点加到链表中。当线程的内核栈需要被换入时SwapListEntry将被插入到KiStackInSwapListHead单链表中。另外的如果是处于延迟等待状态下将会插入某个处理器(KPRCB)的DeferredReadyListHead单链表中。

    • +0x140 WaitBlock : [4] _KWAIT_BLOCK: 该成员包含了4个KWAIT_BLOCK类型的数组,前3个是用于分发器对象的等待,第4个是用于定时器对象的等待。如果等待的数量大于4则需要额外的分配了。这个成员是一种优化的手段

1
2
3
4
5
6
7
8
9
10
nt!_KWAIT_BLOCK
+0x000 WaitListEntry : _LIST_ENTRY
+0x010 WaitType : UChar
+0x011 BlockState : UChar
+0x012 WaitKey : Uint2B
+0x014 SpareLong : Int4B
+0x018 Thread : Ptr64 _KTHREAD
+0x018 NotificationQueue : Ptr64 _KQUEUE
+0x020 Object : Ptr64 Void
+0x028 SparePtr : Ptr64 Void

KWAIT_BLOCK结构代表了一个线程正在等待一个分发器对象,或者说一个分发器对象正在被一个线程等待,它会被同时加入到两个双链表结构中。

  • +0x283 WaitReason : UChar:记录了进程等待的原因(具体解释参考《软件调试(第二版)》P42页)。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
      typedef enum _KWAIT_REASON {
    Executive,
    FreePage,
    PageIn,
    PoolAllocation,
    DelayExecution,
    Suspended,
    UserRequest,
    WrExecutive,
    WrFreePage,
    WrPageIn,
    WrPoolAllocation,
    WrDelayExecution,
    WrSuspended,
    WrUserRequest,
    WrEventPair,
    WrQueue,
    WrLpcReceive,
    WrLpcReply,
    WrVirtualMemory,
    WrPageOut,
    WrRendezvous,
    Spare2,
    Spare3,
    Spare4,
    Spare5,
    Spare6,
    WrKernel,
    WrResource,
    WrPushLock,
    WrMutex,
    WrQuantumEnd,
    WrDispatchInt,
    WrPreempted,
    WrYieldExecution,
    WrFastMutex,
    WrGuardedMutex,
    WrRundown,
    MaximumWaitReason
    } KWAIT_REASON;
  • 有关优先级的:

    • +0x0c3 Priority : Char 线程动态优先级:KPCR中线程就绪队列中的位置(大小为32)初始优先级为8,越大优先级越高(0-15为普通线程的优先级,16-31是实时线程的优先级,这两个区域在优先级调整时不会跨越)。

    • +0x233 BasePriority : Char 线程的静态优先级:从所属进程的BasePriority继承而来。

    • +0x285 Saturation : Char:表明了线程的基本优先级相当于与基本优先级的调整量是否超过了整个区间的一半,值为0、1、-1。

    • +0x234 PriorityDecrement : Char:记录了一个线程在优先级动态调整过程中的递减值(例如KiComputeNewPriority函数中会使用)。

    • +0x235 Preempted : UChar:说明这个线程是否被高优先级的线程抢占,只有当一个线程正在运行或者正在等待运行而被高优先级线程抢占的时候,会被设为1

  • 有关APC的:

    • +0x074 ApcQueueable : Pos 14, 1 Bit:表示了是否可以插入APC。

    • +0x1e4 KernelApcDisable+0x1e6 SpecialApcDisable合成了一个CombinedApcDisable域,KernelApcDisableSpecialApcDisable都是16位的整数值,分别控制 内核APC特殊的内核APC。其值为0可以插入APC负数无法插入APC。一个线程在执行的时候用多种原因要禁止APC,所以这些因素可以累加起来,消除的时候按累加的值消去。

    • +0x24a ApcStateIndex : UChar:指示使用ApcState还是SavedApcState的成员

    • +0x258 SavedApcState : _KAPC_STATE: 在该线程被attach到了另一个进程中后,未交付的APC将会挂在这个底下,detach之后又会被转移到ApcState底下

    • +0x098 ApcState : _KAPC_STATE :其中_KAPC_STATE结构值得关注

1
2
3
4
5
6
7
8
9
10
nt!_KAPC_STATE
+0x000 ApcListHead : [2] _LIST_ENTRY
+0x020 Process : Ptr64 _KPROCESS
+0x028 InProgressFlags : UChar
+0x028 KernelApcInProgress : Pos 0, 1 Bit
+0x028 SpecialApcInProgress : Pos 1, 1 Bit
+0x029 KernelApcPending : UChar
+0x02a UserApcPendingAll : UChar
+0x02a SpecialUserApcPending : Pos 0, 1 Bit
+0x02a UserApcPending : Pos 1, 1 Bit

其中+0x020 Process : Ptr64 _KPROCESS表示了当前线程所属的进程的_KPROCESS

一些其他的结构

  • +0x074 SystemThread : Pos 10, 1 Bit :值为1则表示是系统线程,可以使用API PsIsSystemThread来判断。
  • +0x078 EnableStackSwap : Pos 6, 1 Bit :说明本线程的内核栈是否允许被换出。
  • +0x078 KernelStackResident : Pos 17, 1 Bit :值为1则可以拓展内核栈,反之则不行。(内核栈大小默认为12K)
  • +0x090 TrapFrame : Ptr64 _KTRAP_FRAME:当该线程离开运行状态时,状态会被保存至此。
  • +0x0e8 Queue : Ptr64 _DISPATCHER_HEADER:该成员是一个队列分发器对象,如果不为NULL,则表示当前线程正在处理此队列对象中的项。
  • +0x208 QueueListEntry : _LIST_ENTRY:记录了线程在处理一个队列项时加入到队列对象的线程链表中的节点地址。
  • +0x100 Timer : _KTIMER:附在一个线程上的定时器,当线程执行的时候需要定时器的时候会用此对象。
  • **+0x1c8 Win32Thread :**:指向Windows子系统的管理区域。
  • +0x250 NpxState : Uint8B :反应了浮点处理器的状态。
  • +0x154 ContextSwitches : Uint4B : 当前线程切换次数。
  • +0x218 NextProcessor : Uint4B : 下一次运行时跑在哪个核心上。
  • +0x184 State : UChar : 当前线程运行状态。
  • +0x220 Process : Ptr64 _KPROCESS创建该线程的进程_KPROCESS
  • +0x2f8 ThreadListEntry : _LIST_ENTRY :创建该线程的进程的线程列表,其_KPROCESS结构中的ThreadListHead指向此结构。

进程对象提供了线程的基本执行环境,线程对象提供了为参与线程调度而必须的各种信息。

ETHREAD

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
0: kd> dt _ETHREAD
nt!_ETHREAD
+0x000 Tcb : _KTHREAD
+0x430 CreateTime : _LARGE_INTEGER
+0x438 ExitTime : _LARGE_INTEGER
+0x438 KeyedWaitChain : _LIST_ENTRY
+0x448 PostBlockList : _LIST_ENTRY
+0x448 ForwardLinkShadow : Ptr64 Void
+0x450 StartAddress : Ptr64 Void
+0x458 TerminationPort : Ptr64 _TERMINATION_PORT
+0x458 ReaperLink : Ptr64 _ETHREAD
+0x458 KeyedWaitValue : Ptr64 Void
+0x460 ActiveTimerListLock : Uint8B
+0x468 ActiveTimerListHead : _LIST_ENTRY
+0x478 Cid : _CLIENT_ID
+0x488 KeyedWaitSemaphore : _KSEMAPHORE
+0x488 AlpcWaitSemaphore : _KSEMAPHORE
+0x4a8 ClientSecurity : _PS_CLIENT_SECURITY_CONTEXT
+0x4b0 IrpList : _LIST_ENTRY
+0x4c0 TopLevelIrp : Uint8B
+0x4c8 DeviceToVerify : Ptr64 _DEVICE_OBJECT
+0x4d0 Win32StartAddress : Ptr64 Void
+0x4d8 ChargeOnlySession : Ptr64 Void
+0x4e0 LegacyPowerObject : Ptr64 Void
+0x4e8 ThreadListEntry : _LIST_ENTRY
+0x4f8 RundownProtect : _EX_RUNDOWN_REF
+0x500 ThreadLock : _EX_PUSH_LOCK
+0x508 ReadClusterSize : Uint4B
+0x50c MmLockOrdering : Int4B
+0x510 CrossThreadFlags : Uint4B
+0x510 Terminated : Pos 0, 1 Bit
+0x510 ThreadInserted : Pos 1, 1 Bit
+0x510 HideFromDebugger : Pos 2, 1 Bit
+0x510 ActiveImpersonationInfo : Pos 3, 1 Bit
+0x510 HardErrorsAreDisabled : Pos 4, 1 Bit
+0x510 BreakOnTermination : Pos 5, 1 Bit
+0x510 SkipCreationMsg : Pos 6, 1 Bit
+0x510 SkipTerminationMsg : Pos 7, 1 Bit
+0x510 CopyTokenOnOpen : Pos 8, 1 Bit
+0x510 ThreadIoPriority : Pos 9, 3 Bits
+0x510 ThreadPagePriority : Pos 12, 3 Bits
+0x510 RundownFail : Pos 15, 1 Bit
+0x510 UmsForceQueueTermination : Pos 16, 1 Bit
+0x510 IndirectCpuSets : Pos 17, 1 Bit
+0x510 DisableDynamicCodeOptOut : Pos 18, 1 Bit
+0x510 ExplicitCaseSensitivity : Pos 19, 1 Bit
+0x510 PicoNotifyExit : Pos 20, 1 Bit
+0x510 DbgWerUserReportActive : Pos 21, 1 Bit
+0x510 ForcedSelfTrimActive : Pos 22, 1 Bit
+0x510 SamplingCoverage : Pos 23, 1 Bit
+0x510 ReservedCrossThreadFlags : Pos 24, 8 Bits
+0x514 SameThreadPassiveFlags : Uint4B
+0x514 ActiveExWorker : Pos 0, 1 Bit
+0x514 MemoryMaker : Pos 1, 1 Bit
+0x514 StoreLockThread : Pos 2, 2 Bits
+0x514 ClonedThread : Pos 4, 1 Bit
+0x514 KeyedEventInUse : Pos 5, 1 Bit
+0x514 SelfTerminate : Pos 6, 1 Bit
+0x514 RespectIoPriority : Pos 7, 1 Bit
+0x514 ActivePageLists : Pos 8, 1 Bit
+0x514 SecureContext : Pos 9, 1 Bit
+0x514 ZeroPageThread : Pos 10, 1 Bit
+0x514 WorkloadClass : Pos 11, 1 Bit
+0x514 ReservedSameThreadPassiveFlags : Pos 12, 20 Bits
+0x518 SameThreadApcFlags : Uint4B
+0x518 OwnsProcessAddressSpaceExclusive : Pos 0, 1 Bit
+0x518 OwnsProcessAddressSpaceShared : Pos 1, 1 Bit
+0x518 HardFaultBehavior : Pos 2, 1 Bit
+0x518 StartAddressInvalid : Pos 3, 1 Bit
+0x518 EtwCalloutActive : Pos 4, 1 Bit
+0x518 SuppressSymbolLoad : Pos 5, 1 Bit
+0x518 Prefetching : Pos 6, 1 Bit
+0x518 OwnsVadExclusive : Pos 7, 1 Bit
+0x519 SystemPagePriorityActive : Pos 0, 1 Bit
+0x519 SystemPagePriority : Pos 1, 3 Bits
+0x519 AllowUserWritesToExecutableMemory : Pos 4, 1 Bit
+0x519 AllowKernelWritesToExecutableMemory : Pos 5, 1 Bit
+0x519 OwnsVadShared : Pos 6, 1 Bit
+0x51c CacheManagerActive : UChar
+0x51d DisablePageFaultClustering : UChar
+0x51e ActiveFaultCount : UChar
+0x51f LockOrderState : UChar
+0x520 PerformanceCountLowReserved : Uint4B
+0x524 PerformanceCountHighReserved : Int4B
+0x528 AlpcMessageId : Uint8B
+0x530 AlpcMessage : Ptr64 Void
+0x530 AlpcReceiveAttributeSet : Uint4B
+0x538 AlpcWaitListEntry : _LIST_ENTRY
+0x548 ExitStatus : Int4B
+0x54c CacheManagerCount : Uint4B
+0x550 IoBoostCount : Uint4B
+0x554 IoQoSBoostCount : Uint4B
+0x558 IoQoSThrottleCount : Uint4B
+0x55c KernelStackReference : Uint4B
+0x560 BoostList : _LIST_ENTRY
+0x570 DeboostList : _LIST_ENTRY
+0x580 BoostListLock : Uint8B
+0x588 IrpListLock : Uint8B
+0x590 ReservedForSynchTracking : Ptr64 Void
+0x598 CmCallbackListHead : _SINGLE_LIST_ENTRY
+0x5a0 ActivityId : Ptr64 _GUID
+0x5a8 SeLearningModeListHead : _SINGLE_LIST_ENTRY
+0x5b0 VerifierContext : Ptr64 Void
+0x5b8 AdjustedClientToken : Ptr64 Void
+0x5c0 WorkOnBehalfThread : Ptr64 Void
+0x5c8 PropertySet : _PS_PROPERTY_SET
+0x5e0 PicoContext : Ptr64 Void
+0x5e8 UserFsBase : Uint8B
+0x5f0 UserGsBase : Uint8B
+0x5f8 EnergyValues : Ptr64 _THREAD_ENERGY_VALUES
+0x600 SelectedCpuSets : Uint8B
+0x600 SelectedCpuSetsIndirect : Ptr64 Uint8B
+0x608 Silo : Ptr64 _EJOB
+0x610 ThreadName : Ptr64 _UNICODE_STRING
+0x618 SetContextState : Ptr64 _CONTEXT
+0x620 LastExpectedRunTime : Uint4B
+0x624 HeapData : Uint4B
+0x628 OwnerEntryListHead : _LIST_ENTRY
+0x638 DisownedOwnerEntryListLock : Uint8B
+0x640 DisownedOwnerEntryListHead : _LIST_ENTRY
+0x650 LockEntries : [6] _KLOCK_ENTRY
+0x890 CmDbgInfo : Ptr64 Void

关键结构

  • +0x450 StartAddress : Ptr64 Void真正的线程起始地址,但是通常是kernel32!BaseProcessStartkernel32!BaseThreadStart
  • +0x4d0 Win32StartAddress : Ptr64 Void:Windows子系统接收到的线程启动地址,即CreateThread接收到的线程启动地址。
  • +0x478 Cid: _CLIENT_ID : 其中保存的是创建该线程的进程id与线程id结构如下:
    1
    2
    3
    nt!_CLIENT_ID
    +0x000 UniqueProcess : Ptr64 Void
    +0x008 UniqueThread : Ptr64 Void
  • +0x4b0 IrpList : _LIST_ENTRY:是一个双链表头,其中包含了当前线程所有正在处理但是尚未完成的IO请求(IRP对象)。
  • +0x4e8 ThreadListEntry : _LIST_ENTRY :与上文相仿,也是线程列表其_EPROCESS结构中的ThreadListHead指向此结构。
  • +0x510 CrossThreadFlags:其中是一些针对跨线程访问的标志位。
    • Terminated——Pos 0:线程已终止操作。
    • HideFromDebugger——Pos 2:该线程对于调试器不可见
    • HardErrorsAreDisabled——Pos 4:该线程对于硬件错误无效。
    • BreakOnTermination——Pos 5:调试器在线程终止时停下来。
  • +0x514 SameThreadPassiveFlags:在PASSIVE_LEVEL才能访问的标志位,且只能被线程自身访问
  • +0x518 SameThreadApcFlags:在APC_LEVEL及以上被该线程访问自身的标志位。

KiFindReadyThread逆向

该函数用于寻找一个就绪态的线程。
在x64下其结构较为复杂,但是大致与x86下一样。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
_LIST_ENTRY **__fastcall KiFindReadyThread(_KPRCB *a1, _KPRCB *a2, __int64 a3, unsigned int readyBitmap)
{
unsigned __int64 v4; // r12
_LIST_ENTRY *v5; // r13
_KPRCB *v7; // r11
int v8; // esi
unsigned int HighstBitPos; // eax
LIST_ENTRY **v10; // r14
LIST_ENTRY *readyThreadListEntry; // rbx
unsigned int v12; // eax
_KTHREAD *readyThread; // rdi
unsigned __int64 v14; // rbp
_LIST_ENTRY **pReadyThread; // rax
_KSCHEDULING_GROUP *volatile v16; // rcx
_KPRCB *v17; // r11
__int64 v18; // rcx
unsigned __int64 v19; // rax
_KPRCB *v20; // [rsp+70h] [rbp+8h]
_KPRCB *v21; // [rsp+78h] [rbp+10h]
char v23; // [rsp+88h] [rbp+20h]

v21 = a2;
v20 = a1;
v4 = a1->GroupSetMember;
v5 = a2->DispatcherReadyListHead;
if ( !a2 )
v5 = (a3 + 16);
v7 = a1;
v8 = 64;
LABEL_4:
_BitScanReverse(&HighstBitPos, readyBitmap);//bsr 指令直接获得就绪位图的最高位,也就是找到了优先级最高的就绪线程
readyBitmap ^= 1 << HighstBitPos;
v10 = &v5[HighstBitPos].Flink;
v23 = HighstBitPos;
readyThreadListEntry = *v10;
while ( 1 )
{
v12 = BYTE5(readyThreadListEntry[-6].Flink);// SystemHeteroCpuPolicy
readyThread = &readyThreadListEntry[-14].Blink;// 获得了 _KTHREAD
v14 = readyThreadListEntry[22].Blink;
if ( v12 >= 5 )
{
v12 = KiConvertDynamicHeteroPolicy(&readyThreadListEntry[-14].Blink, a2, v7);
v7 = v20;
}
if ( v12 )
{
a2 = v7->ParentNode;
v19 = v14 & *(&a2->GroupSetMember + 3 * v12);
if ( v19 )//判断是否是一个组的
v14 = v19;
}
if ( (v4 & v14) != 0 )
{
v16 = readyThread->SchedulingGroup;
if ( !v16 )
break;
v18 = v16 + v7->ScbOffset;
if ( !v18 || !KiCheckForMaxOverQuotaScb(v18) )
break;
}
readyThreadListEntry = readyThreadListEntry->Flink;
--v8;
if ( readyThreadListEntry == v10 || !v8 )
{
if ( !readyBitmap || !v8 )
return 0i64;
goto LABEL_4;
}
}
if ( v21 )
KiRemoveThreadFromReadyQueue(v21, readyThreadListEntry, v23);
else
KiRemoveThreadFromSharedReadyQueue(a3, &readyThreadListEntry[-14].Blink, v23);
pReadyThread = &readyThreadListEntry[-14].Blink;
readyThread->NextProcessor = v17->Number; // v17 就是 a1
return pReadyThread;
}

使用文本描述流程则是:

  1. 在就绪位图中找到优先级最大的就绪线程
  2. 判断其是否可以运行在当前CPU上
  3. 从就绪队列中抹除该线程
  4. 把该线程的下一次运行CPU设置好
  5. 返回就绪线程
  • 标题: Windows线程研究——基础知识
  • 作者: moshui
  • 创建于 : 2025-01-28 13:40:32
  • 更新于 : 2025-02-17 15:04:00
  • 链接: https://www.moshui.eu.org/2025/01/28/windows-thread-1/
  • 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。
评论