WindowsAPI编程核心技术-栈和函数调用

什么是栈

每个普通用户进程都有俩栈,一个为内核态栈记录在_KTHREAD结构中,另一个为用户态栈记录在_TEB结构中。

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
207
0: kd> .thread
Implicit thread is now fffff804`09b27600
0: kd> dt nt!_KTHREAD fffff804`09b27600
+0x000 Header : _DISPATCHER_HEADER
+0x018 SListFaultAddress : (null)
+0x020 QuantumTarget : 0x791ddc0
+0x028 InitialStack : 0xfffff804`0ba7fc90 Void //原栈顶位置 内核态代码逆向调用用户态代码时使用
+0x030 StackLimit : 0xfffff804`0ba7a000 Void //内核态栈边界 即StackBase-内核态栈大小
+0x038 StackBase : 0xfffff804`0ba80000 Void //内核态栈基地址
+0x040 ThreadLock : 0
+0x048 CycleTime : 0x0000033e`caa858aa
+0x050 CurrentRunTime : 0xffffffff
+0x054 ExpectedRunTime : 0
+0x058 KernelStack : 0xfffff804`0ba7fc20 Void //内核态栈的栈顶地址
+0x060 StateSaveArea : 0xfffff804`0ba7fcc0 _XSAVE_FORMAT
+0x068 SchedulingGroup : (null)
+0x070 WaitRegister : _KWAIT_STATUS_REGISTER
+0x071 Running : 0x1 ''
+0x072 Alerted : [2] ""
+0x074 AutoBoostActive : 0y1
+0x074 ReadyTransition : 0y0
+0x074 WaitNext : 0y0
+0x074 SystemAffinityActive : 0y1
+0x074 Alertable : 0y0
+0x074 UserStackWalkActive : 0y0
+0x074 ApcInterruptRequest : 0y0
+0x074 QuantumEndMigrate : 0y0
+0x074 UmsDirectedSwitchEnable : 0y0
+0x074 TimerActive : 0y0
+0x074 SystemThread : 0y1
+0x074 ProcessDetachActive : 0y0
+0x074 CalloutActive : 0y0
+0x074 ScbReadyQueue : 0y0
+0x074 ApcQueueable : 0y0
+0x074 ReservedStackInUse : 0y0
+0x074 UmsPerformingSyscall : 0y0
+0x074 TimerSuspended : 0y0
+0x074 SuspendedWaitMode : 0y0
+0x074 SuspendSchedulerApcWait : 0y0
+0x074 CetUserShadowStack : 0y0
+0x074 BypassProcessFreeze : 0y0
+0x074 Reserved : 0y0000000000 (0)
+0x074 MiscFlags : 0n1033
+0x078 ThreadFlagsSpare : 0y00
+0x078 AutoAlignment : 0y1
+0x078 DisableBoost : 0y0
+0x078 AlertedByThreadId : 0y0
+0x078 QuantumDonation : 0y0
+0x078 EnableStackSwap : 0y1
+0x078 GuiThread : 0y0
+0x078 DisableQuantum : 0y0
+0x078 ChargeOnlySchedulingGroup : 0y0
+0x078 DeferPreemption : 0y0
+0x078 QueueDeferPreemption : 0y0
+0x078 ForceDeferSchedule : 0y0
+0x078 SharedReadyQueueAffinity : 0y0
+0x078 FreezeCount : 0y0
+0x078 TerminationApcRequest : 0y0
+0x078 AutoBoostEntriesExhausted : 0y0
+0x078 KernelStackResident : 0y1 //内核态栈是否位于物理内存中
+0x078 TerminateRequestReason : 0y00
+0x078 ProcessStackCountDecremented : 0y0
+0x078 RestrictedGuiThread : 0y0
+0x078 VpBackingThread : 0y0
+0x078 ThreadFlagsSpare2 : 0y0
+0x078 EtwStackTraceApcInserted : 0y00000000 (0)
+0x078 ThreadFlags : 0n131140
+0x07c Tag : 0 ''
+0x07d SystemHeteroCpuPolicy : 0 ''
+0x07e UserHeteroCpuPolicy : 0y0001000 (0x8)
+0x07e ExplicitSystemHeteroCpuPolicy : 0y0
+0x07f RunningNonRetpolineCode : 0y0
+0x07f SpecCtrlSpare : 0y0000000 (0)
+0x07f SpecCtrl : 0 ''
+0x080 SystemCallNumber : 0
+0x084 ReadyTime : 0
+0x088 FirstArgument : (null)
+0x090 TrapFrame : (null)
+0x098 ApcState : _KAPC_STATE
+0x098 ApcStateFill : [43] "???"
+0x0c3 Priority : 0 ''
+0x0c4 UserIdealProcessor : 0
+0x0c8 WaitStatus : 0n0
+0x0d0 WaitBlockList : (null)
+0x0d8 WaitListEntry : _LIST_ENTRY [ 0x00000000`00000000 - 0x00000000`00000000 ]
+0x0d8 SwapListEntry : _SINGLE_LIST_ENTRY
+0x0e8 Queue : (null)
+0x0f0 Teb : (null)
+0x0f8 RelativeTimerBias : 0
+0x100 Timer : _KTIMER
+0x140 WaitBlock : [4] _KWAIT_BLOCK
+0x140 WaitBlockFill4 : [20] ""
+0x154 ContextSwitches : 0x140fe
+0x140 WaitBlockFill5 : [68] ""
+0x184 State : 0x2 ''
+0x185 Spare13 : 0 ''
+0x186 WaitIrql : 0x2 ''
+0x187 WaitMode : 0 ''
+0x140 WaitBlockFill6 : [116] ""
+0x1b4 WaitTime : 0x16c30
+0x140 WaitBlockFill7 : [164] ""
+0x1e4 KernelApcDisable : 0n0
+0x1e6 SpecialApcDisable : 0n0
+0x1e4 CombinedApcDisable : 0
+0x140 WaitBlockFill8 : [40] ""
+0x168 ThreadCounters : (null)
+0x140 WaitBlockFill9 : [88] ""
+0x198 XStateSave : (null)
+0x140 WaitBlockFill10 : [136] ""
+0x1c8 Win32Thread : (null)
+0x140 WaitBlockFill11 : [176] ""
+0x1f0 Ucb : (null)
+0x1f8 Uch : (null)
+0x200 ThreadFlags2 : 0n0
+0x200 BamQosLevel : 0y00000000 (0)
+0x200 ThreadFlags2Reserved : 0y000000000000000000000000 (0)
+0x204 Spare21 : 0
+0x208 QueueListEntry : _LIST_ENTRY [ 0x00000000`00000000 - 0x00000000`00000000 ]
+0x218 NextProcessor : 0
+0x218 NextProcessorNumber : 0y0000000000000000000000000000000 (0)
+0x218 SharedReadyQueue : 0y0
+0x21c QueuePriority : 0n0
+0x220 Process : 0xfffff804`09b24a00 _KPROCESS
+0x228 UserAffinity : _GROUP_AFFINITY
+0x228 UserAffinityFill : [10] "???"
+0x232 PreviousMode : 0 ''
+0x233 BasePriority : 0 ''
+0x234 PriorityDecrement : 0 ''
+0x234 ForegroundBoost : 0y0000
+0x234 UnusualBoost : 0y0000
+0x235 Preempted : 0 ''
+0x236 AdjustReason : 0 ''
+0x237 AdjustIncrement : 0 ''
+0x238 AffinityVersion : 0x18
+0x240 Affinity : _GROUP_AFFINITY
+0x240 AffinityFill : [10] "???"
+0x24a ApcStateIndex : 0x1 ''
+0x24b WaitBlockCount : 0 ''
+0x24c IdealProcessor : 0
+0x250 NpxState : 4
+0x258 SavedApcState : _KAPC_STATE
+0x258 SavedApcStateFill : [43] "Xx???"
+0x283 WaitReason : 0x19 ''
+0x284 SuspendCount : 0 ''
+0x285 Saturation : 0 ''
+0x286 SListFaultCount : 0
+0x288 SchedulerApc : _KAPC
+0x288 SchedulerApcFill0 : [1] "??????"
+0x289 ResourceIndex : 0x2 ''
+0x288 SchedulerApcFill1 : [3] "???"
+0x28b QuantumReset : 0x7f ''
+0x288 SchedulerApcFill2 : [4] "???"
+0x28c KernelTime : 0x17b9b
+0x288 SchedulerApcFill3 : [64] "???"
+0x2c8 WaitPrcb : (null)
+0x288 SchedulerApcFill4 : [72] "???"
+0x2d0 LegoData : (null)
+0x288 SchedulerApcFill5 : [83] "???"
+0x2db CallbackNestingLevel : 0 ''
+0x2dc UserTime : 0
+0x2e0 SuspendEvent : _KEVENT
+0x2f8 ThreadListEntry : _LIST_ENTRY [ 0xffffbc81`52e72438 - 0xfffff804`09b24a30 ]
+0x308 MutantListHead : _LIST_ENTRY [ 0xfffff804`09b27908 - 0xfffff804`09b27908 ]
+0x318 AbEntrySummary : 0x3f '?'
+0x319 AbWaitEntryCount : 0 ''
+0x31a AbAllocationRegionCount : 0 ''
+0x31b SystemPriority : 0 ''
+0x31c SecureThreadCookie : 0
+0x320 LockEntries : 0xfffff804`09b27c50 _KLOCK_ENTRY
+0x328 PropagateBoostsEntry : _SINGLE_LIST_ENTRY
+0x330 IoSelfBoostsEntry : _SINGLE_LIST_ENTRY
+0x338 PriorityFloorCounts : [16] ""
+0x348 PriorityFloorCountsReserved : [16] ""
+0x358 PriorityFloorSummary : 0
+0x35c AbCompletedIoBoostCount : 0n0
+0x360 AbCompletedIoQoSBoostCount : 0n0
+0x364 KeReferenceCount : 0n0
+0x366 AbOrphanedEntrySummary : 0 ''
+0x367 AbOwnedEntryCount : 0 ''
+0x368 ForegroundLossTime : 0
+0x370 GlobalForegroundListEntry : _LIST_ENTRY [ 0x00000000`00000001 - 0x00000000`00000000 ]
+0x370 ForegroundDpcStackListEntry : _SINGLE_LIST_ENTRY
+0x378 InGlobalForegroundList : 0
+0x380 ReadOperationCount : 0n0
+0x388 WriteOperationCount : 0n0
+0x390 OtherOperationCount : 0n0
+0x398 ReadTransferCount : 0n0
+0x3a0 WriteTransferCount : 0n0
+0x3a8 OtherTransferCount : 0n0
+0x3b0 QueuedScb : (null)
+0x3b8 ThreadTimerDelay : 0
+0x3bc ThreadFlags3 : 0n0
+0x3bc ThreadFlags3Reserved : 0y00000000 (0)
+0x3bc PpmPolicy : 0y00
+0x3bc ThreadFlags3Reserved2 : 0y0000000000000000000000 (0)
+0x3c0 TracingPrivate : [1] 0
+0x3c8 SchedulerAssist : (null)
+0x3d0 AbWaitObject : (null)
+0x3d8 ReservedPreviousReadyTimeValue : 0
+0x3e0 KernelWaitTime : 0
+0x3e8 UserWaitTime : 0
+0x3f0 GlobalUpdateVpThreadPriorityListEntry : _LIST_ENTRY [ 0x00000000`00000001 - 0x00000000`00000000 ]
+0x3f0 UpdateVpThreadPriorityDpcStackListEntry : _SINGLE_LIST_ENTRY
+0x3f8 InGlobalUpdateVpThreadPriorityList : 0
+0x400 SchedulerAssistPriorityFloor : 0n0
+0x404 Spare28 : 0
+0x408 EndPadding : [5] 0

用户态栈基本信息记录在线程信息块_NT_TIB结构中,它是TEB的第一部分。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
0:000> ~
. 0 Id: d24.db0 Suspend: 1 Teb: 00000029`d4850000 Unfrozen
1 Id: d24.1224 Suspend: 1 Teb: 00000029`d4852000 Unfrozen
2 Id: d24.1248 Suspend: 1 Teb: 00000029`d4854000 Unfrozen
3 Id: d24.1230 Suspend: 1 Teb: 00000029`d4856000 Unfrozen
0:000> dt _NT_TIB 00000029`d4850000
MSVCP140!_NT_TIB
+0x000 ExceptionList : (null)
+0x008 StackBase : 0x00000029`d4b00000 Void //用户态栈基地址
+0x010 StackLimit : 0x00000029`d4afb000 Void //栈边界
+0x018 SubSystemTib : (null)
+0x020 FiberData : 0x00000000`00001e00 Void
+0x020 Version : 0x1e00
+0x028 ArbitraryUserPointer : (null)
+0x030 Self : 0x00000029`d4850000 _NT_TIB

栈的创建

创建系统线程用PsCreateSystemThread和用户线程用NtCreateThread都用内核线程创建函数PspCreateThread,后者创建内核态栈。

这节先鸽着。

栈增长与栈溢出

栈空间有自动增长机制:栈创建时系统多提交一个页面的栈空间,该页面称为栈保护页面,具有PAGE_GUARD属性。具有该属性的内存页被访问时CPU产生页错误异常并执行系统内存管理函数。内存管理函数此时先清除PAGE_GUARD属性,用MiCheckForUserStackOverflow,后者从当前线程TEB中读取用户态栈基本信息并检查导致异常的地址。若导致异常的被访问地址不属于栈空间范围,则返回STATUS_GUARD_PAGE_VIOLATION,否则用ZwAllocateVirtualMemory从保留空间中再提交一个具有PAGE_GUARD属性的内存页。

保留空间的最后一个页面永远不会被提交,且不设置PAGE_GUARD属性。