首页
论坛
课程
招聘
X86内核笔记_4_进程和线程
2021-12-7 15:06 14179

X86内核笔记_4_进程和线程

2021-12-7 15:06
14179

1.KPCR结构

CPU控制块结构,每一个逻辑核都有一个KPCR结构描述当前CPU的各种信息。全局变量“KeNumberProcessors”中保存了当前机器的CPU核数。

 

在系统调用章节我们初步了解了KPCR的部分成员。

 

KPCR结构成员列表:

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
//0x3748 bytes (sizeof)
struct _KPCR
{
    union
    {
        struct _NT_TIB NtTib;                                               //0x0
        struct
        {
            struct _EXCEPTION_REGISTRATION_RECORD* Used_ExceptionList;      //0x0
            VOID* Used_StackBase;                                           //0x4
            VOID* Spare2;                                                   //0x8
            VOID* TssCopy;                                                  //0xc
            ULONG ContextSwitches;                                          //0x10
            ULONG SetMemberCopy;                                            //0x14
            VOID* Used_Self;                                                //0x18
        };
    };
    struct _KPCR* SelfPcr;                                                  //0x1c
    struct _KPRCB* Prcb;                                                    //0x20
    UCHAR Irql;                                                             //0x24
    ULONG IRR;                                                              //0x28
    ULONG IrrActive;                                                        //0x2c
    ULONG IDR;                                                              //0x30
    VOID* KdVersionBlock;                                                   //0x34
    struct _KIDTENTRY* IDT;                                                 //0x38
    struct _KGDTENTRY* GDT;                                                 //0x3c
    struct _KTSS* TSS;                                                      //0x40
    USHORT MajorVersion;                                                    //0x44
    USHORT MinorVersion;                                                    //0x46
    ULONG SetMember;                                                        //0x48
    ULONG StallScaleFactor;                                                 //0x4c
    UCHAR SpareUnused;                                                      //0x50
    UCHAR Number;                                                           //0x51
    UCHAR Spare0;                                                           //0x52
    UCHAR SecondLevelCacheAssociativity;                                    //0x53
    ULONG VdmAlert;                                                         //0x54
    ULONG KernelReserved[14];                                               //0x58
    ULONG SecondLevelCacheSize;                                             //0x90
    ULONG HalReserved[16];                                                  //0x94
    ULONG InterruptMode;                                                    //0xd4
    UCHAR Spare1;                                                           //0xd8
    ULONG KernelReserved2[17];                                              //0xdc
    struct _KPRCB PrcbData;                                                 //0x120
};
  • +0 NtTib:
    • +0 Used_ExceptionList:异常处理程序链表。
    • +4 Used_StackBase:当前线程的栈底。
    • +8 Spare2/StackLimit:当前线程的堆栈大小。
    • +18 Used_Self:指向NtTib自身,也是KPCR自身(fs:[0x18])。
  • +1C SelfPcr:指向KPCR自身。与UsedSelf不同,SelfPcr必然指向KPCR自身,UsedSelf有时候会指向TEB。
  • +20 Prcb:KPRCB结构指针。见后文。
  • +38 IDT:当前线程的IDT表地址。
  • +3C GDT:当前线程的GDT表地址。
  • +40 TSS:指向当前线程的TSS表。
  • +48 SetNumber:当前CPU编号。从1开始。
  • +51 Number:当前CPU编号。从0开始。
  • +120 PrcbData:KPRCB结构,扩展结构,见后文。

KPRCB结构

CPU控制块扩展块。全局变量“KiProcessorBlock”中保存了KPRCB的地址。

 

KPRCB结构成员列表:

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
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
//0x3628 bytes (sizeof)
struct _KPRCB
{
    USHORT MinorVersion;                                                    //0x0
    USHORT MajorVersion;                                                    //0x2
    struct _KTHREAD* CurrentThread;                                         //0x4
    struct _KTHREAD* NextThread;                                            //0x8
    struct _KTHREAD* IdleThread;                                            //0xc
    UCHAR LegacyNumber;                                                     //0x10
    UCHAR NestingLevel;                                                     //0x11
    USHORT BuildType;                                                       //0x12
    CHAR CpuType;                                                           //0x14
    CHAR CpuID;                                                             //0x15
    union
    {
        USHORT CpuStep;                                                     //0x16
        struct
        {
            UCHAR CpuStepping;                                              //0x16
            UCHAR CpuModel;                                                 //0x17
        };
    };
    struct _KPROCESSOR_STATE ProcessorState;                                //0x18
    ULONG KernelReserved[16];                                               //0x338
    ULONG HalReserved[16];                                                  //0x378
    ULONG CFlushSize;                                                       //0x3b8
    UCHAR CoresPerPhysicalProcessor;                                        //0x3bc
    UCHAR LogicalProcessorsPerCore;                                         //0x3bd
    UCHAR PrcbPad0[2];                                                      //0x3be
    ULONG MHz;                                                              //0x3c0
    UCHAR CpuVendor;                                                        //0x3c4
    UCHAR GroupIndex;                                                       //0x3c5
    USHORT Group;                                                           //0x3c6
    ULONG GroupSetMember;                                                   //0x3c8
    ULONG Number;                                                           //0x3cc
    UCHAR PrcbPad1[72];                                                     //0x3d0
    struct _KSPIN_LOCK_QUEUE LockQueue[17];                                 //0x418
    struct _KTHREAD* NpxThread;                                             //0x4a0
    ULONG InterruptCount;                                                   //0x4a4
    ULONG KernelTime;                                                       //0x4a8
    ULONG UserTime;                                                         //0x4ac
    ULONG DpcTime;                                                          //0x4b0
    ULONG DpcTimeCount;                                                     //0x4b4
    ULONG InterruptTime;                                                    //0x4b8
    ULONG AdjustDpcThreshold;                                               //0x4bc
    ULONG PageColor;                                                        //0x4c0
    UCHAR DebuggerSavedIRQL;                                                //0x4c4
    UCHAR NodeColor;                                                        //0x4c5
    UCHAR PrcbPad20[2];                                                     //0x4c6
    ULONG NodeShiftedColor;                                                 //0x4c8
    struct _KNODE* ParentNode;                                              //0x4cc
    ULONG SecondaryColorMask;                                               //0x4d0
    ULONG DpcTimeLimit;                                                     //0x4d4
    ULONG PrcbPad21[2];                                                     //0x4d8
    ULONG CcFastReadNoWait;                                                 //0x4e0
    ULONG CcFastReadWait;                                                   //0x4e4
    ULONG CcFastReadNotPossible;                                            //0x4e8
    ULONG CcCopyReadNoWait;                                                 //0x4ec
    ULONG CcCopyReadWait;                                                   //0x4f0
    ULONG CcCopyReadNoWaitMiss;                                             //0x4f4
    volatile LONG MmSpinLockOrdering;                                       //0x4f8
    volatile LONG IoReadOperationCount;                                     //0x4fc
    volatile LONG IoWriteOperationCount;                                    //0x500
    volatile LONG IoOtherOperationCount;                                    //0x504
    union _LARGE_INTEGER IoReadTransferCount;                               //0x508
    union _LARGE_INTEGER IoWriteTransferCount;                              //0x510
    union _LARGE_INTEGER IoOtherTransferCount;                              //0x518
    ULONG CcFastMdlReadNoWait;                                              //0x520
    ULONG CcFastMdlReadWait;                                                //0x524
    ULONG CcFastMdlReadNotPossible;                                         //0x528
    ULONG CcMapDataNoWait;                                                  //0x52c
    ULONG CcMapDataWait;                                                    //0x530
    ULONG CcPinMappedDataCount;                                             //0x534
    ULONG CcPinReadNoWait;                                                  //0x538
    ULONG CcPinReadWait;                                                    //0x53c
    ULONG CcMdlReadNoWait;                                                  //0x540
    ULONG CcMdlReadWait;                                                    //0x544
    ULONG CcLazyWriteHotSpots;                                              //0x548
    ULONG CcLazyWriteIos;                                                   //0x54c
    ULONG CcLazyWritePages;                                                 //0x550
    ULONG CcDataFlushes;                                                    //0x554
    ULONG CcDataPages;                                                      //0x558
    ULONG CcLostDelayedWrites;                                              //0x55c
    ULONG CcFastReadResourceMiss;                                           //0x560
    ULONG CcCopyReadWaitMiss;                                               //0x564
    ULONG CcFastMdlReadResourceMiss;                                        //0x568
    ULONG CcMapDataNoWaitMiss;                                              //0x56c
    ULONG CcMapDataWaitMiss;                                                //0x570
    ULONG CcPinReadNoWaitMiss;                                              //0x574
    ULONG CcPinReadWaitMiss;                                                //0x578
    ULONG CcMdlReadNoWaitMiss;                                              //0x57c
    ULONG CcMdlReadWaitMiss;                                                //0x580
    ULONG CcReadAheadIos;                                                   //0x584
    ULONG KeAlignmentFixupCount;                                            //0x588
    ULONG KeExceptionDispatchCount;                                         //0x58c
    ULONG KeSystemCalls;                                                    //0x590
    ULONG AvailableTime;                                                    //0x594
    ULONG PrcbPad22[2];                                                     //0x598
    struct _PP_LOOKASIDE_LIST PPLookasideList[16];                          //0x5a0
    struct _GENERAL_LOOKASIDE_POOL PPNPagedLookasideList[32];               //0x620
    struct _GENERAL_LOOKASIDE_POOL PPPagedLookasideList[32];                //0xf20
    volatile ULONG PacketBarrier;                                           //0x1820
    volatile LONG ReverseStall;                                             //0x1824
    VOID* IpiFrame;                                                         //0x1828
    UCHAR PrcbPad3[52];                                                     //0x182c
    VOID* volatile CurrentPacket[3];                                        //0x1860
    volatile ULONG TargetSet;                                               //0x186c
    VOID (* volatileWorkerRoutine)(VOID* arg1, VOID* arg2, VOID* arg3, VOID* arg4); //0x1870
    volatile ULONG IpiFrozen;                                               //0x1874
    UCHAR PrcbPad4[40];                                                     //0x1878
    volatile ULONG RequestSummary;                                          //0x18a0
    struct _KPRCB* volatile SignalDone;                                     //0x18a4
    UCHAR PrcbPad50[56];                                                    //0x18a8
    struct _KDPC_DATA DpcData[2];                                           //0x18e0
    VOID* DpcStack;                                                         //0x1908
    LONG MaximumDpcQueueDepth;                                              //0x190c
    ULONG DpcRequestRate;                                                   //0x1910
    ULONG MinimumDpcRate;                                                   //0x1914
    ULONG DpcLastCount;                                                     //0x1918
    ULONG PrcbLock;                                                         //0x191c
    struct _KGATE DpcGate;                                                  //0x1920
    UCHAR ThreadDpcEnable;                                                  //0x1930
    volatile UCHAR QuantumEnd;                                              //0x1931
    volatile UCHAR DpcRoutineActive;                                        //0x1932
    volatile UCHAR IdleSchedule;                                            //0x1933
    union
    {
        volatile LONG DpcRequestSummary;                                    //0x1934
        SHORT DpcRequestSlot[2];                                            //0x1934
        struct
        {
            SHORT NormalDpcState;                                           //0x1934
            union
            {
                volatile USHORT DpcThreadActive:1;                          //0x1936
                SHORT ThreadDpcState;                                       //0x1936
            };
        };
    };
    volatile ULONG TimerHand;                                               //0x1938
    ULONG LastTick;                                                         //0x193c
    LONG MasterOffset;                                                      //0x1940
    ULONG PrcbPad41[2];                                                     //0x1944
    ULONG PeriodicCount;                                                    //0x194c
    ULONG PeriodicBias;                                                     //0x1950
    ULONGLONG TickOffset;                                                   //0x1958
    struct _KTIMER_TABLE TimerTable;                                        //0x1960
    struct _KDPC CallDpc;                                                   //0x31a0
    LONG ClockKeepAlive;                                                    //0x31c0
    UCHAR ClockCheckSlot;                                                   //0x31c4
    UCHAR ClockPollCycle;                                                   //0x31c5
    UCHAR PrcbPad6[2];                                                      //0x31c6
    LONG DpcWatchdogPeriod;                                                 //0x31c8
    LONG DpcWatchdogCount;                                                  //0x31cc
    LONG ThreadWatchdogPeriod;                                              //0x31d0
    LONG ThreadWatchdogCount;                                               //0x31d4
    volatile LONG KeSpinLockOrdering;                                       //0x31d8
    ULONG PrcbPad70[1];                                                     //0x31dc
    struct _LIST_ENTRY WaitListHead;                                        //0x31e0
    ULONG WaitLock;                                                         //0x31e8
    ULONG ReadySummary;                                                     //0x31ec
    ULONG QueueIndex;                                                       //0x31f0
    struct _SINGLE_LIST_ENTRY DeferredReadyListHead;                        //0x31f4
    ULONGLONG StartCycles;                                                  //0x31f8
    volatile ULONGLONG CycleTime;                                           //0x3200
    volatile ULONG HighCycleTime;                                           //0x3208
    ULONG PrcbPad71;                                                        //0x320c
    ULONGLONG PrcbPad72[2];                                                 //0x3210
    struct _LIST_ENTRY DispatcherReadyListHead[32];                         //0x3220
    VOID* ChainedInterruptList;                                             //0x3320
    LONG LookasideIrpFloat;                                                 //0x3324
    volatile LONG MmPageFaultCount;                                         //0x3328
    volatile LONG MmCopyOnWriteCount;                                       //0x332c
    volatile LONG MmTransitionCount;                                        //0x3330
    volatile LONG MmCacheTransitionCount;                                   //0x3334
    volatile LONG MmDemandZeroCount;                                        //0x3338
    volatile LONG MmPageReadCount;                                          //0x333c
    volatile LONG MmPageReadIoCount;                                        //0x3340
    volatile LONG MmCacheReadCount;                                         //0x3344
    volatile LONG MmCacheIoCount;                                           //0x3348
    volatile LONG MmDirtyPagesWriteCount;                                   //0x334c
    volatile LONG MmDirtyWriteIoCount;                                      //0x3350
    volatile LONG MmMappedPagesWriteCount;                                  //0x3354
    volatile LONG MmMappedWriteIoCount;                                     //0x3358
    volatile ULONG CachedCommit;                                            //0x335c
    volatile ULONG CachedResidentAvailable;                                 //0x3360
    VOID* HyperPte;                                                         //0x3364
    UCHAR PrcbPad8[4];                                                      //0x3368
    UCHAR VendorString[13];                                                 //0x336c
    UCHAR InitialApicId;                                                    //0x3379
    UCHAR LogicalProcessorsPerPhysicalProcessor;                            //0x337a
    UCHAR PrcbPad9[5];                                                      //0x337b
    ULONG FeatureBits;                                                      //0x3380
    union _LARGE_INTEGER UpdateSignature;                                   //0x3388
    volatile ULONGLONG IsrTime;                                             //0x3390
    ULONGLONG RuntimeAccumulation;                                          //0x3398
    struct _PROCESSOR_POWER_STATE PowerState;                               //0x33a0
    struct _KDPC DpcWatchdogDpc;                                            //0x3468
    struct _KTIMER DpcWatchdogTimer;                                        //0x3488
    VOID* WheaInfo;                                                         //0x34b0
    VOID* EtwSupport;                                                       //0x34b4
    union _SLIST_HEADER InterruptObjectPool;                                //0x34b8
    union _SLIST_HEADER HypercallPageList;                                  //0x34c0
    VOID* HypercallPageVirtual;                                             //0x34c8
    VOID* VirtualApicAssist;                                                //0x34cc
    ULONGLONG* StatisticsPage;                                              //0x34d0
    VOID* RateControl;                                                      //0x34d4
    struct _CACHE_DESCRIPTOR Cache[5];                                      //0x34d8
    ULONG CacheCount;                                                       //0x3514
    ULONG CacheProcessorMask[5];                                            //0x3518
    struct _KAFFINITY_EX PackageProcessorSet;                               //0x352c
    ULONG PrcbPad91[1];                                                     //0x3538
    ULONG CoreProcessorSet;                                                 //0x353c
    struct _KDPC TimerExpirationDpc;                                        //0x3540
    ULONG SpinLockAcquireCount;                                             //0x3560
    ULONG SpinLockContentionCount;                                          //0x3564
    ULONG SpinLockSpinCount;                                                //0x3568
    ULONG IpiSendRequestBroadcastCount;                                     //0x356c
    ULONG IpiSendRequestRoutineCount;                                       //0x3570
    ULONG IpiSendSoftwareInterruptCount;                                    //0x3574
    ULONG ExInitializeResourceCount;                                        //0x3578
    ULONG ExReInitializeResourceCount;                                      //0x357c
    ULONG ExDeleteResourceCount;                                            //0x3580
    ULONG ExecutiveResourceAcquiresCount;                                   //0x3584
    ULONG ExecutiveResourceContentionsCount;                                //0x3588
    ULONG ExecutiveResourceReleaseExclusiveCount;                           //0x358c
    ULONG ExecutiveResourceReleaseSharedCount;                              //0x3590
    ULONG ExecutiveResourceConvertsCount;                                   //0x3594
    ULONG ExAcqResExclusiveAttempts;                                        //0x3598
    ULONG ExAcqResExclusiveAcquiresExclusive;                               //0x359c
    ULONG ExAcqResExclusiveAcquiresExclusiveRecursive;                      //0x35a0
    ULONG ExAcqResExclusiveWaits;                                           //0x35a4
    ULONG ExAcqResExclusiveNotAcquires;                                     //0x35a8
    ULONG ExAcqResSharedAttempts;                                           //0x35ac
    ULONG ExAcqResSharedAcquiresExclusive;                                  //0x35b0
    ULONG ExAcqResSharedAcquiresShared;                                     //0x35b4
    ULONG ExAcqResSharedAcquiresSharedRecursive;                            //0x35b8
    ULONG ExAcqResSharedWaits;                                              //0x35bc
    ULONG ExAcqResSharedNotAcquires;                                        //0x35c0
    ULONG ExAcqResSharedStarveExclusiveAttempts;                            //0x35c4
    ULONG ExAcqResSharedStarveExclusiveAcquiresExclusive;                   //0x35c8
    ULONG ExAcqResSharedStarveExclusiveAcquiresShared;                      //0x35cc
    ULONG ExAcqResSharedStarveExclusiveAcquiresSharedRecursive;             //0x35d0
    ULONG ExAcqResSharedStarveExclusiveWaits;                               //0x35d4
    ULONG ExAcqResSharedStarveExclusiveNotAcquires;                         //0x35d8
    ULONG ExAcqResSharedWaitForExclusiveAttempts;                           //0x35dc
    ULONG ExAcqResSharedWaitForExclusiveAcquiresExclusive;                  //0x35e0
    ULONG ExAcqResSharedWaitForExclusiveAcquiresShared;                     //0x35e4
    ULONG ExAcqResSharedWaitForExclusiveAcquiresSharedRecursive;            //0x35e8
    ULONG ExAcqResSharedWaitForExclusiveWaits;                              //0x35ec
    ULONG ExAcqResSharedWaitForExclusiveNotAcquires;                        //0x35f0
    ULONG ExSetResOwnerPointerExclusive;                                    //0x35f4
    ULONG ExSetResOwnerPointerSharedNew;                                    //0x35f8
    ULONG ExSetResOwnerPointerSharedOld;                                    //0x35fc
    ULONG ExTryToAcqExclusiveAttempts;                                      //0x3600
    ULONG ExTryToAcqExclusiveAcquires;                                      //0x3604
    ULONG ExBoostExclusiveOwner;                                            //0x3608
    ULONG ExBoostSharedOwners;                                              //0x360c
    ULONG ExEtwSynchTrackingNotificationsCount;                             //0x3610
    ULONG ExEtwSynchTrackingNotificationsAccountedCount;                    //0x3614
    struct _CONTEXT* Context;                                               //0x3618
    ULONG ContextFlags;                                                     //0x361c
    struct _XSAVE_AREA* ExtendedState;                                      //0x3620
};
  • +4 CurrentThread:当前CPU正在跑的线程。
  • +8 NextThread:将要切换的线程。
  • +C IdleThread:如果没有要切换的线程,CPU将要跑的空闲线程。

其余字段在后续分析内核代码时再了解。

2.EPROCESS结构

在3环下,每个进程都有一个PEB结构用来描述这个进程的一些信息。这些信息仅是为了3环更好的操作进程。而在0环,每个进程又有一个结构体用于描述该进程的所有信息:EPROCESS。

 

结构体成员列表:

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
//0x2c0 bytes (sizeof)
struct _EPROCESS
{
    struct _KPROCESS Pcb;                                                   //0x0
    struct _EX_PUSH_LOCK ProcessLock;                                       //0x98
    union _LARGE_INTEGER CreateTime;                                        //0xa0
    union _LARGE_INTEGER ExitTime;                                          //0xa8
    struct _EX_RUNDOWN_REF RundownProtect;                                  //0xb0
    VOID* UniqueProcessId;                                                  //0xb4
    struct _LIST_ENTRY ActiveProcessLinks;                                  //0xb8
    ULONG ProcessQuotaUsage[2];                                             //0xc0
    ULONG ProcessQuotaPeak[2];                                              //0xc8
    volatile ULONG CommitCharge;                                            //0xd0
    struct _EPROCESS_QUOTA_BLOCK* QuotaBlock;                               //0xd4
    struct _PS_CPU_QUOTA_BLOCK* CpuQuotaBlock;                              //0xd8
    ULONG PeakVirtualSize;                                                  //0xdc
    ULONG VirtualSize;                                                      //0xe0
    struct _LIST_ENTRY SessionProcessLinks;                                 //0xe4
    VOID* DebugPort;                                                        //0xec
    union
    {
        VOID* ExceptionPortData;                                            //0xf0
        ULONG ExceptionPortValue;                                           //0xf0
        ULONG ExceptionPortState:3;                                         //0xf0
    };
    struct _HANDLE_TABLE* ObjectTable;                                      //0xf4
    struct _EX_FAST_REF Token;                                              //0xf8
    ULONG WorkingSetPage;                                                   //0xfc
    struct _EX_PUSH_LOCK AddressCreationLock;                               //0x100
    struct _ETHREAD* RotateInProgress;                                      //0x104
    struct _ETHREAD* ForkInProgress;                                        //0x108
    ULONG HardwareTrigger;                                                  //0x10c
    struct _MM_AVL_TABLE* PhysicalVadRoot;                                  //0x110
    VOID* CloneRoot;                                                        //0x114
    volatile ULONG NumberOfPrivatePages;                                    //0x118
    volatile ULONG NumberOfLockedPages;                                     //0x11c
    VOID* Win32Process;                                                     //0x120
    struct _EJOB* volatile Job;                                             //0x124
    VOID* SectionObject;                                                    //0x128
    VOID* SectionBaseAddress;                                               //0x12c
    ULONG Cookie;                                                           //0x130
    ULONG Spare8;                                                           //0x134
    struct _PAGEFAULT_HISTORY* WorkingSetWatch;                             //0x138
    VOID* Win32WindowStation;                                               //0x13c
    VOID* InheritedFromUniqueProcessId;                                     //0x140
    VOID* LdtInformation;                                                   //0x144
    VOID* VdmObjects;                                                       //0x148
    ULONG ConsoleHostProcess;                                               //0x14c
    VOID* DeviceMap;                                                        //0x150
    VOID* EtwDataSource;                                                    //0x154
    VOID* FreeTebHint;                                                      //0x158
    union
    {
        struct _HARDWARE_PTE PageDirectoryPte;                              //0x160
        ULONGLONG Filler;                                                   //0x160
    };
    VOID* Session;                                                          //0x168
    UCHAR ImageFileName[15];                                                //0x16c
    UCHAR PriorityClass;                                                    //0x17b
    struct _LIST_ENTRY JobLinks;                                            //0x17c
    VOID* LockedPagesList;                                                  //0x184
    struct _LIST_ENTRY ThreadListHead;                                      //0x188
    VOID* SecurityPort;                                                     //0x190
    VOID* PaeTop;                                                           //0x194
    volatile ULONG ActiveThreads;                                           //0x198
    ULONG ImagePathHash;                                                    //0x19c
    ULONG DefaultHardErrorProcessing;                                       //0x1a0
    LONG LastThreadExitStatus;                                              //0x1a4
    struct _PEB* Peb;                                                       //0x1a8
    struct _EX_FAST_REF PrefetchTrace;                                      //0x1ac
    union _LARGE_INTEGER ReadOperationCount;                                //0x1b0
    union _LARGE_INTEGER WriteOperationCount;                               //0x1b8
    union _LARGE_INTEGER OtherOperationCount;                               //0x1c0
    union _LARGE_INTEGER ReadTransferCount;                                 //0x1c8
    union _LARGE_INTEGER WriteTransferCount;                                //0x1d0
    union _LARGE_INTEGER OtherTransferCount;                                //0x1d8
    ULONG CommitChargeLimit;                                                //0x1e0
    volatile ULONG CommitChargePeak;                                        //0x1e4
    VOID* AweInfo;                                                          //0x1e8
    struct _SE_AUDIT_PROCESS_CREATION_INFO SeAuditProcessCreationInfo;      //0x1ec
    struct _MMSUPPORT Vm;                                                   //0x1f0
    struct _LIST_ENTRY MmProcessLinks;                                      //0x25c
    VOID* HighestUserAddress;                                               //0x264
    ULONG ModifiedPageCount;                                                //0x268
    union
    {
        ULONG Flags2;                                                       //0x26c
        struct
        {
            ULONG JobNotReallyActive:1;                                     //0x26c
            ULONG AccountingFolded:1;                                       //0x26c
            ULONG NewProcessReported:1;                                     //0x26c
            ULONG ExitProcessReported:1;                                    //0x26c
            ULONG ReportCommitChanges:1;                                    //0x26c
            ULONG LastReportMemory:1;                                       //0x26c
            ULONG ReportPhysicalPageChanges:1;                              //0x26c
            ULONG HandleTableRundown:1;                                     //0x26c
            ULONG NeedsHandleRundown:1;                                     //0x26c
            ULONG RefTraceEnabled:1;                                        //0x26c
            ULONG NumaAware:1;                                              //0x26c
            ULONG ProtectedProcess:1;                                       //0x26c
            ULONG DefaultPagePriority:3;                                    //0x26c
            ULONG PrimaryTokenFrozen:1;                                     //0x26c
            ULONG ProcessVerifierTarget:1;                                  //0x26c
            ULONG StackRandomizationDisabled:1;                             //0x26c
            ULONG AffinityPermanent:1;                                      //0x26c
            ULONG AffinityUpdateEnable:1;                                   //0x26c
            ULONG PropagateNode:1;                                          //0x26c
            ULONG ExplicitAffinity:1;                                       //0x26c
        };
    };
    union
    {
        ULONG Flags;                                                        //0x270
        struct
        {
            ULONG CreateReported:1;                                         //0x270
            ULONG NoDebugInherit:1;                                         //0x270
            ULONG ProcessExiting:1;                                         //0x270
            ULONG ProcessDelete:1;                                          //0x270
            ULONG Wow64SplitPages:1;                                        //0x270
            ULONG VmDeleted:1;                                              //0x270
            ULONG OutswapEnabled:1;                                         //0x270
            ULONG Outswapped:1;                                             //0x270
            ULONG ForkFailed:1;                                             //0x270
            ULONG Wow64VaSpace4Gb:1;                                        //0x270
            ULONG AddressSpaceInitialized:2;                                //0x270
            ULONG SetTimerResolution:1;                                     //0x270
            ULONG BreakOnTermination:1;                                     //0x270
            ULONG DeprioritizeViews:1;                                      //0x270
            ULONG WriteWatch:1;                                             //0x270
            ULONG ProcessInSession:1;                                       //0x270
            ULONG OverrideAddressSpace:1;                                   //0x270
            ULONG HasAddressSpace:1;                                        //0x270
            ULONG LaunchPrefetched:1;                                       //0x270
            ULONG InjectInpageErrors:1;                                     //0x270
            ULONG VmTopDown:1;                                              //0x270
            ULONG ImageNotifyDone:1;                                        //0x270
            ULONG PdeUpdateNeeded:1;                                        //0x270
            ULONG VdmAllowed:1;                                             //0x270
            ULONG CrossSessionCreate:1;                                     //0x270
            ULONG ProcessInserted:1;                                        //0x270
            ULONG DefaultIoPriority:3;                                      //0x270
            ULONG ProcessSelfDelete:1;                                      //0x270
            ULONG SetTimerResolutionLink:1;                                 //0x270
        };
    };
    LONG ExitStatus;                                                        //0x274
    struct _MM_AVL_TABLE VadRoot;                                           //0x278
    struct _ALPC_PROCESS_CONTEXT AlpcContext;                               //0x298
    struct _LIST_ENTRY TimerResolutionLink;                                 //0x2a8
    ULONG RequestedTimerResolution;                                         //0x2b0
    ULONG ActiveThreadsHighWatermark;                                       //0x2b4
    ULONG SmallestTimerResolution;                                          //0x2b8
    struct _PO_DIAG_STACK_RECORD* TimerResolutionStackRecord;               //0x2bc
};
  • +0 Pcb:Kprocess结构体。参考下文。

  • +98 ProcessLock:进程锁。修改EPROCESS结构存放锁结构,防止同时修改。改完了置0.

  • +A0 CreateTime:进程的创建时间。

  • +A8 ExitTime:进程的退出时间。

  • +B0 RundownProtect:进程锁。该字段置值后,进程无法被访问、打开、结束,相当于保护。但是会容易卡死。

  • +B4 UniqueProcessId:进程ID。任务管理器中显示的进程ID就是这个。

  • +B8 ActiveProcessLinks:双向链表。包括了windows中所有活动的进程。全局变量“PsActiveProcessHead”指向了这个链表的头部。通过该全局变量可以遍历整条链表。

  • +C0 ProcessQuotaUsage:进程物理页相关统计信息。

  • +C8 ProcessQuotaPeak:进程物理页相关统计信息。

  • +D0 CommitCharge:进程虚拟内存相关统计信息。

  • +D4 QuotaBlock:进程虚拟内存相关统计信息。

  • +D8 CpuQuotaBlock:进程虚拟内存相关统计信息。

  • +E4 SessionProcessLinks:会话进程链表。保存了当前登录的用户的所有进程。

  • +EC DebugPort:调试相关。如果该进程处于调试状态,这里会有值(一个结构体),该结构体用于进程与调试器之间通信。通过循环清0可以达到反调试效果。

  • +F0 ExceptionPortData:调试相关。

  • +F4 ObjectTable:进程的句柄表。句柄相关章节再学。

  • +F8 Token:进程Token。

  • +FC WorkingSetPage:表明当前进程用了多少个物理页。

  • +16C ImageFileName:当前进程的进程名。

  • +188 ThreadListHead:当前进程内所有线程的链表。

  • +198 ActiveThreads:当前进程内活动的线程数量。

  • +1A8 Peb。就是3环下该进程的PEB。(PEB结构此处不赘述了,网上有非常多的PEB结构说明。)

  • +1EC SeAuditProcessCreationInfo:当前进程完整路径。

  • +26C Flags2:一个联合体,每个位影响该进程的一些属性。

    • ProtectedProcess:进程保护位。该位置1后该进程被保护。CE看不到图片,打不开了进程。OD附加进程列表遍历不到。一个最简单的进程保护。

      image-20210927155035191

  • +270 Flags:一个联合体,每个位影响该进程的一些属性。

    • ProcessExiting:进程退出标志位。置1后表明该进程已退出,但实际还在运行。可以达到反调试的效果。同时进程无法使用任务管理器结束。

    • ProcessDelete:进程退出标志位。置1后表明该进程已退出,但实际还在运行。可以达到反调试的效果。同时进程无法使用任务管理器结束。

      image-20210927153322421

    • BreakOnTermination:该位置1后,任务管理器结束进程时将提示“是否结束系统进程XXX”。结束后windbg将会断下。

      image-20210927152849916

    • VmTopDown:该位置1时,VirtualAlloc一类的申请内存函数将会从大地址开始申请。

    • ProcessInserted:该位置0后,OD附加进程列表找不到该进程。任务管理器结束不掉该进程。CE打不开该进程,无图标。

  • +274 ExitStatus:进程退出状态码。进程创建时默认值是250(0x103)。如果不是这个值基本上就是进程退出了。

  • +278 VadRoot:标识当前进程用户空间(低2G)中哪些地址没被分配。该成员指向了一个二叉树。

KPROCESS结构

Eprocess第一个成员是一个Kprocess结构。

 

Kprocess结构成员列表:

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
//0x98 bytes (sizeof)
struct _KPROCESS
{
    struct _DISPATCHER_HEADER Header;                                       //0x0
    struct _LIST_ENTRY ProfileListHead;                                     //0x10
    ULONG DirectoryTableBase;                                               //0x18
    struct _KGDTENTRY LdtDescriptor;                                        //0x1c
    struct _KIDTENTRY Int21Descriptor;                                      //0x24
    struct _LIST_ENTRY ThreadListHead;                                      //0x2c
    ULONG ProcessLock;                                                      //0x34
    struct _KAFFINITY_EX Affinity;                                          //0x38
    struct _LIST_ENTRY ReadyListHead;                                       //0x44
    struct _SINGLE_LIST_ENTRY SwapListEntry;                                //0x4c
    volatile struct _KAFFINITY_EX ActiveProcessors;                         //0x50
    union
    {
        struct
        {
            volatile LONG AutoAlignment:1;                                  //0x5c
            volatile LONG DisableBoost:1;                                   //0x5c
            volatile LONG DisableQuantum:1;                                 //0x5c
            volatile ULONG ActiveGroupsMask:1;                              //0x5c
            volatile LONG ReservedFlags:28;                                 //0x5c
        };
        volatile LONG ProcessFlags;                                         //0x5c
    };
    CHAR BasePriority;                                                      //0x60
    CHAR QuantumReset;                                                      //0x61
    UCHAR Visited;                                                          //0x62
    UCHAR Unused3;                                                          //0x63
    ULONG ThreadSeed[1];                                                    //0x64
    USHORT IdealNode[1];                                                    //0x68
    USHORT IdealGlobalNode;                                                 //0x6a
    union _KEXECUTE_OPTIONS Flags;                                          //0x6c
    UCHAR Unused1;                                                          //0x6d
    USHORT IopmOffset;                                                      //0x6e
    ULONG Unused4;                                                          //0x70
    union _KSTACK_COUNT StackCount;                                         //0x74
    struct _LIST_ENTRY ProcessListEntry;                                    //0x78
    volatile ULONGLONG CycleTime;                                           //0x80
    ULONG KernelTime;                                                       //0x88
    ULONG UserTime;                                                         //0x8c
    VOID* VdmTrapcHandler;                                                  //0x90
};
  • +0 Header:可等待对象头部。所有0环结构体只要以_DISPATCHER_HEADER结构开头的,都可以使用WaitForSingleObject等待。如互斥体、事件。

  • +10 ProfileListHead:性能分析相关,任务管理器,性能栏那些数据。

  • +18 DirectoryTableBase:页目录表基址。物理地址,指向页目录表,CR3中的值就从这里获取。

  • +2C ThreadListHead:当前进程的所有线程结构体链表。

  • +38 Affinity:亲核性。规定了当前进程内的所有线程可以在哪些CPU上跑,4字节,共32位,每一位对应一个CPU核。如000000A1,转换为二进制为1010 0001,则该进程中的线程只能在0、5、7号CPU上运行。因此32位系统最多支持32核CPU,64位系统支持64核CPU。该值仅为线程结构中的亲核性做初始化赋值使用,没有实际的限制功能。

    如果只有1个CPU,但此处值为2(0010),则该进程为一个“死”了的进程。

  • +44 ReadyListHead:当前进程内的就绪线程链表。

  • +4C SwapListEntry:交换到文件磁盘上时使用该链表。记录了哪些内存被交换到文件里。

  • +50 ActiveProcessors:当前进程内正在运行的线程运行在哪些CPU上。

  • +5C AutoAlignment:强制内存对齐。一般为0。

  • +5C DisableBoost:置1为关闭当前进程内所有线程的时间碎片。(置1后,不会由于时间中断触发线程切换)

  • +60 BasePriority:基础优先级。该进程内所有线程最初的优先级。

  • +61 QuantumReset:当前进程内线程的初始时间碎片。每一次时钟中断会将线程中的时间碎片减6,为0时,切换线程。线程从就绪变为运行时,会从这个值中取到初始的时间碎片。改大这个值会让该进程内的线程跑的更久。

  • +78 ProcessListEntry:系统内所有进程的链表。win7及以上此处为空,已弃用。

  • +80 CycleTime:当前进程执行了多少个指令周期。当进程结束时才会被赋值,指明了该进程存活了多久。

  • +88 KernelTime:(统计信息)当前进程在0环的运行时间。当进程结束时才会被赋值,指明了该进程存活了多久。

  • +8C UserTime:(统计信息)当前进程在3环的运行时间。当进程结束时才会被赋值,指明了该进程存活了多久。

  • +90 VdmTrapcHandler:虚拟8086模式时使用。

3.ETHREAD结构

与进程一样, 3环下有TEB描述某个线程。在0环,也有一个ETHREAD描述某个线程的所有信息。

 

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
123
124
125
126
127
128
//0x2b8 bytes (sizeof)
struct _ETHREAD
{
    struct _KTHREAD Tcb;                                                    //0x0
    union _LARGE_INTEGER CreateTime;                                        //0x200
    union
    {
        union _LARGE_INTEGER ExitTime;                                      //0x208
        struct _LIST_ENTRY KeyedWaitChain;                                  //0x208
    };
    LONG ExitStatus;                                                        //0x210
    union
    {
        struct _LIST_ENTRY PostBlockList;                                   //0x214
        struct
        {
            VOID* ForwardLinkShadow;                                        //0x214
            VOID* StartAddress;                                             //0x218
        };
    };
    union
    {
        struct _TERMINATION_PORT* TerminationPort;                          //0x21c
        struct _ETHREAD* ReaperLink;                                        //0x21c
        VOID* KeyedWaitValue;                                               //0x21c
    };
    ULONG ActiveTimerListLock;                                              //0x220
    struct _LIST_ENTRY ActiveTimerListHead;                                 //0x224
    struct _CLIENT_ID Cid;                                                  //0x22c
    union
    {
        struct _KSEMAPHORE KeyedWaitSemaphore;                              //0x234
        struct _KSEMAPHORE AlpcWaitSemaphore;                               //0x234
    };
    union _PS_CLIENT_SECURITY_CONTEXT ClientSecurity;                       //0x248
    struct _LIST_ENTRY IrpList;                                             //0x24c
    ULONG TopLevelIrp;                                                      //0x254
    struct _DEVICE_OBJECT* DeviceToVerify;                                  //0x258
    union _PSP_CPU_QUOTA_APC* CpuQuotaApc;                                  //0x25c
    VOID* Win32StartAddress;                                                //0x260
    VOID* LegacyPowerObject;                                                //0x264
    struct _LIST_ENTRY ThreadListEntry;                                     //0x268
    struct _EX_RUNDOWN_REF RundownProtect;                                  //0x270
    struct _EX_PUSH_LOCK ThreadLock;                                        //0x274
    ULONG ReadClusterSize;                                                  //0x278
    volatile LONG MmLockOrdering;                                           //0x27c
    union
    {
        ULONG CrossThreadFlags;                                             //0x280
        struct
        {
            ULONG Terminated:1;                                             //0x280
            ULONG ThreadInserted:1;                                         //0x280
            ULONG HideFromDebugger:1;                                       //0x280
            ULONG ActiveImpersonationInfo:1;                                //0x280
            ULONG Reserved:1;                                               //0x280
            ULONG HardErrorsAreDisabled:1;                                  //0x280
            ULONG BreakOnTermination:1;                                     //0x280
            ULONG SkipCreationMsg:1;                                        //0x280
            ULONG SkipTerminationMsg:1;                                     //0x280
            ULONG CopyTokenOnOpen:1;                                        //0x280
            ULONG ThreadIoPriority:3;                                       //0x280
            ULONG ThreadPagePriority:3;                                     //0x280
            ULONG RundownFail:1;                                            //0x280
            ULONG NeedsWorkingSetAging:1;                                   //0x280
        };
    };
    union
    {
        ULONG SameThreadPassiveFlags;                                       //0x284
        struct
        {
            ULONG ActiveExWorker:1;                                         //0x284
            ULONG ExWorkerCanWaitUser:1;                                    //0x284
            ULONG MemoryMaker:1;                                            //0x284
            ULONG ClonedThread:1;                                           //0x284
            ULONG KeyedEventInUse:1;                                        //0x284
            ULONG RateApcState:2;                                           //0x284
            ULONG SelfTerminate:1;                                          //0x284
        };
    };
    union
    {
        ULONG SameThreadApcFlags;                                           //0x288
        struct
        {
            UCHAR Spare:1;                                                  //0x288
            volatile UCHAR StartAddressInvalid:1;                           //0x288
            UCHAR EtwPageFaultCalloutActive:1;                              //0x288
            UCHAR OwnsProcessWorkingSetExclusive:1;                         //0x288
            UCHAR OwnsProcessWorkingSetShared:1;                            //0x288
            UCHAR OwnsSystemCacheWorkingSetExclusive:1;                     //0x288
            UCHAR OwnsSystemCacheWorkingSetShared:1;                        //0x288
            UCHAR OwnsSessionWorkingSetExclusive:1;                         //0x288
            UCHAR OwnsSessionWorkingSetShared:1;                            //0x289
            UCHAR OwnsProcessAddressSpaceExclusive:1;                       //0x289
            UCHAR OwnsProcessAddressSpaceShared:1;                          //0x289
            UCHAR SuppressSymbolLoad:1;                                     //0x289
            UCHAR Prefetching:1;                                            //0x289
            UCHAR OwnsDynamicMemoryShared:1;                                //0x289
            UCHAR OwnsChangeControlAreaExclusive:1;                         //0x289
            UCHAR OwnsChangeControlAreaShared:1;                            //0x289
            UCHAR OwnsPagedPoolWorkingSetExclusive:1;                       //0x28a
            UCHAR OwnsPagedPoolWorkingSetShared:1;                          //0x28a
            UCHAR OwnsSystemPtesWorkingSetExclusive:1;                      //0x28a
            UCHAR OwnsSystemPtesWorkingSetShared:1;                         //0x28a
            UCHAR TrimTrigger:2;                                            //0x28a
            UCHAR Spare1:2;                                                 //0x28a
            UCHAR PriorityRegionActive;                                     //0x28b
        };
    };
    UCHAR CacheManagerActive;                                               //0x28c
    UCHAR DisablePageFaultClustering;                                       //0x28d
    UCHAR ActiveFaultCount;                                                 //0x28e
    UCHAR LockOrderState;                                                   //0x28f
    ULONG AlpcMessageId;                                                    //0x290
    union
    {
        VOID* AlpcMessage;                                                  //0x294
        ULONG AlpcReceiveAttributeSet;                                      //0x294
    };
    struct _LIST_ENTRY AlpcWaitListEntry;                                   //0x298
    ULONG CacheManagerCount;                                                //0x2a0
    ULONG IoBoostCount;                                                     //0x2a4
    ULONG IrpListLock;                                                      //0x2a8
    VOID* ReservedForSynchTracking;                                         //0x2ac
    struct _SINGLE_LIST_ENTRY CmCallbackListHead;                           //0x2b0
};
  • +0 Tcb:KTHREAD成员,见下文。
  • +218 StartAddress:线程函数起始地址。
  • +22C Cid:当前线程的线程ID。为_CLIENT_ID结构,包含了线程ID和所属的进程ID。
  • +268 ThreadListEntry:当前进程内所有线程的双向链表。

KTHREAD结构

与进程一样,第一个成员为KTHREAD结构。

 

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
//0x200 bytes (sizeof)
struct _KTHREAD
{
    struct _DISPATCHER_HEADER Header;                                       //0x0
    volatile ULONGLONG CycleTime;                                           //0x10
    volatile ULONG HighCycleTime;                                           //0x18
    ULONGLONG QuantumTarget;                                                //0x20
    VOID* InitialStack;                                                     //0x28
    VOID* volatile StackLimit;                                              //0x2c
    VOID* KernelStack;                                                      //0x30
    ULONG ThreadLock;                                                       //0x34
    union _KWAIT_STATUS_REGISTER WaitRegister;                              //0x38
    volatile UCHAR Running;                                                 //0x39
    UCHAR Alerted[2];                                                       //0x3a
    union
    {
        struct
        {
            ULONG KernelStackResident:1;                                    //0x3c
            ULONG ReadyTransition:1;                                        //0x3c
            ULONG ProcessReadyQueue:1;                                      //0x3c
            ULONG WaitNext:1;                                               //0x3c
            ULONG SystemAffinityActive:1;                                   //0x3c
            ULONG Alertable:1;                                              //0x3c
            ULONG GdiFlushActive:1;                                         //0x3c
            ULONG UserStackWalkActive:1;                                    //0x3c
            ULONG ApcInterruptRequest:1;                                    //0x3c
            ULONG ForceDeferSchedule:1;                                     //0x3c
            ULONG QuantumEndMigrate:1;                                      //0x3c
            ULONG UmsDirectedSwitchEnable:1;                                //0x3c
            ULONG TimerActive:1;                                            //0x3c
            ULONG SystemThread:1;                                           //0x3c
            ULONG Reserved:18;                                              //0x3c
        };
        LONG MiscFlags;                                                     //0x3c
    };
    union
    {
        struct _KAPC_STATE ApcState;                                        //0x40
        struct
        {
            UCHAR ApcStateFill[23];                                         //0x40
            CHAR Priority;                                                  //0x57
        };
    };
    volatile ULONG NextProcessor;                                           //0x58
    volatile ULONG DeferredProcessor;                                       //0x5c
    ULONG ApcQueueLock;                                                     //0x60
    ULONG ContextSwitches;                                                  //0x64
    volatile UCHAR State;                                                   //0x68
    CHAR NpxState;                                                          //0x69
    UCHAR WaitIrql;                                                         //0x6a
    CHAR WaitMode;                                                          //0x6b
    volatile LONG WaitStatus;                                               //0x6c
    struct _KWAIT_BLOCK* WaitBlockList;                                     //0x70
    union
    {
        struct _LIST_ENTRY WaitListEntry;                                   //0x74
        struct _SINGLE_LIST_ENTRY SwapListEntry;                            //0x74
    };
    struct _KQUEUE* volatile Queue;                                         //0x7c
    ULONG WaitTime;                                                         //0x80
    union
    {
        struct
        {
            SHORT KernelApcDisable;                                         //0x84
            SHORT SpecialApcDisable;                                        //0x86
        };
        ULONG CombinedApcDisable;                                           //0x84
    };
    VOID* Teb;                                                              //0x88
    struct _KTIMER Timer;                                                   //0x90
    union
    {
        struct
        {
            volatile ULONG AutoAlignment:1;                                 //0xb8
            volatile ULONG DisableBoost:1;                                  //0xb8
            volatile ULONG EtwStackTraceApc1Inserted:1;                     //0xb8
            volatile ULONG EtwStackTraceApc2Inserted:1;                     //0xb8
            volatile ULONG CalloutActive:1;                                 //0xb8
            volatile ULONG ApcQueueable:1;                                  //0xb8
            volatile ULONG EnableStackSwap:1;                               //0xb8
            volatile ULONG GuiThread:1;                                     //0xb8
            volatile ULONG UmsPerformingSyscall:1;                          //0xb8
            volatile ULONG VdmSafe:1;                                       //0xb8
            volatile ULONG UmsDispatched:1;                                 //0xb8
            volatile ULONG ReservedFlags:21;                                //0xb8
        };
        volatile LONG ThreadFlags;                                          //0xb8
    };
    VOID* ServiceTable;                                                     //0xbc
    struct _KWAIT_BLOCK WaitBlock[4];                                       //0xc0
    struct _LIST_ENTRY QueueListEntry;                                      //0x120
    struct _KTRAP_FRAME* TrapFrame;                                         //0x128
    VOID* FirstArgument;                                                    //0x12c
    union
    {
        VOID* CallbackStack;                                                //0x130
        ULONG CallbackDepth;                                                //0x130
    };
    UCHAR ApcStateIndex;                                                    //0x134
    CHAR BasePriority;                                                      //0x135
    union
    {
        CHAR PriorityDecrement;                                             //0x136
        struct
        {
            UCHAR ForegroundBoost:4;                                        //0x136
            UCHAR UnusualBoost:4;                                           //0x136
        };
    };
    UCHAR Preempted;                                                        //0x137
    UCHAR AdjustReason;                                                     //0x138
    CHAR AdjustIncrement;                                                   //0x139
    CHAR PreviousMode;                                                      //0x13a
    CHAR Saturation;                                                        //0x13b
    ULONG SystemCallNumber;                                                 //0x13c
    ULONG FreezeCount;                                                      //0x140
    volatile struct _GROUP_AFFINITY UserAffinity;                           //0x144
    struct _KPROCESS* Process;                                              //0x150
    volatile struct _GROUP_AFFINITY Affinity;                               //0x154
    ULONG IdealProcessor;                                                   //0x160
    ULONG UserIdealProcessor;                                               //0x164
    struct _KAPC_STATE* ApcStatePointer[2];                                 //0x168
    union
    {
        struct _KAPC_STATE SavedApcState;                                   //0x170
        struct
        {
            UCHAR SavedApcStateFill[23];                                    //0x170
            UCHAR WaitReason;                                               //0x187
        };
    };
    CHAR SuspendCount;                                                      //0x188
    CHAR Spare1;                                                            //0x189
    UCHAR OtherPlatformFill;                                                //0x18a
    VOID* volatile Win32Thread;                                             //0x18c
    VOID* StackBase;                                                        //0x190
    union
    {
        struct _KAPC SuspendApc;                                            //0x194
        struct
        {
            UCHAR SuspendApcFill0[1];                                       //0x194
            UCHAR ResourceIndex;                                            //0x195
        };
        struct
        {
            UCHAR SuspendApcFill1[3];                                       //0x194
            UCHAR QuantumReset;                                             //0x197
        };
        struct
        {
            UCHAR SuspendApcFill2[4];                                       //0x194
            ULONG KernelTime;                                               //0x198
        };
        struct
        {
            UCHAR SuspendApcFill3[36];                                      //0x194
            struct _KPRCB* volatile WaitPrcb;                               //0x1b8
        };
        struct
        {
            UCHAR SuspendApcFill4[40];                                      //0x194
            VOID* LegoData;                                                 //0x1bc
        };
        struct
        {
            UCHAR SuspendApcFill5[47];                                      //0x194
            UCHAR LargeStack;                                               //0x1c3
        };
    };
    ULONG UserTime;                                                         //0x1c4
    union
    {
        struct _KSEMAPHORE SuspendSemaphore;                                //0x1c8
        UCHAR SuspendSemaphorefill[20];                                     //0x1c8
    };
    ULONG SListFaultCount;                                                  //0x1dc
    struct _LIST_ENTRY ThreadListEntry;                                     //0x1e0
    struct _LIST_ENTRY MutantListHead;                                      //0x1e8
    VOID* SListFaultAddress;                                                //0x1f0
    struct _KTHREAD_COUNTERS* ThreadCounters;                               //0x1f4
    struct _XSTATE_SAVE* XStateSave;                                        //0x1f8
};
  • +0 Header:可等待对象头部。
  • +28 InitialStack:线程切换相关。当前线程的栈底。栈底-29C是TrapFrame结构首地址。
  • +2C StackLimit:线程切换相关。当前线程的最大栈顶。ESP不能小于这个值。
  • +30 KernelStack:线程切换相关。线程切换时,存储当前线程切换时的ESP,被切换回来时,从这里恢复ESP。
  • +39 Running:线程状态,正在运行中为1,否则为0。
  • +3A Alerted:可警惕性。APC相关,后续APC章节学习。
  • +3C MiscFlags:
    • KernelStackResident:堆栈可扩展位。为1时,线程内核堆栈可以被扩大。0时无法扩大。
    • SystemThread:为1时,该线程为内核线程,否则为用户线程。
  • +40 ApcState:APC相关,后续APC章节学习。
  • +57 Priority:当前线程的优先级。如存储11,则优先级为11,当前线程存储在第11个就绪链表中。优先级数字越大,优先级越低。默认线程优先级为8,存储在第8个就绪链表中。
  • +60 ApcQueueLock:APC相关,后续APC章节学习。
  • +64 ContextSwitches:当前线程切换了多少次。
  • +68 State:线程状态。就绪、等待、运行等。
  • +88 Teb:3环的TEB。
  • +BC ServiceTable:系统服务表地址,系统调用章节已学过。
  • +C0 WaitBlock:当前线程正在等待的对象。
  • +128 TrapFrame:TrapFrame结构,进0环时保存3环寄存器的值,系统调用章节已学过。
  • +135 BasePriority:线程基础优先级。这个值就是所属进程的BasePriority值。
  • +13A PreviousMode:先前模式。一些内核函数会判断这个值。
  • +150 Process:该线程的父进程(创建该线程的进程)。
  • +168 ApcStatePointer:APC相关,后续APC章节学习。
  • +170 SavedApcState:APC相关,后续APC章节学习。
  • +18C Win32Thread:win32线程,如果该线程是UI图形线程,就会多一个win32线程结构体。
  • +1E0 ThreadListEntry:当前进程所有线程的双向链表。

4.OBJECT_HEADER

每一个内核对象都有一个OBJECT_HEADER结构,大小为0x18。将某个内核对象地址-0x18就是OBJECT_HEADER结构地址。

 

OBJECT_HEADER结构成员列表:

1
2
3
4
5
6
7
8
9
10
11
12
13
nt!_OBJECT_HEADER
   +0x000 PointerCount     : Int4B
   +0x004 HandleCount      : Int4B
   +0x004 NextToFree       : Ptr32 Void
   +0x008 Lock             : _EX_PUSH_LOCK
   +0x00c TypeIndex        : UChar
   +0x00d TraceFlags       : UChar
   +0x00e InfoMask         : UChar
   +0x00f Flags            : UChar
   +0x010 ObjectCreateInfo : Ptr32 _OBJECT_CREATE_INFORMATION
   +0x010 QuotaBlockCharged : Ptr32 Void
   +0x014 SecurityDescriptor : Ptr32 Void
   +0x018 Body             : _QUAD
  • PointerCount:对应的内核对象被使用了多少次。如调用ObXXXX函数都会将该值+1。该值为0时,对应的内核对象就会被释放。
  • HandleCount:句柄引用。
  • TypeIndex:对应的内核对象的类型。
  • Flags:详细作用未知。当此处的值被置为4时(对应的对象为进程对象时),对应的进程被保护,无法打开、附加。且不影响进程功能。仅对3环起作用。

5.线程链表

线程大体上可分为3种状态:等待、正在运行、就绪。系统上的所有未处于正在运行状态的线程都被存储在两种链表中:等待链表+就绪链表。

等待链表

全局变量KiWaitListHead是一个双向链表的头部,里面是所有等待执行的线程的ETHREAD结构,每个核都有一个等待链表。链表中每个节点指向ETHREAD中的KTHREAD->WaitListEntry。

 

当调用Sleep、WaitForSingleObject一类的等待函数时,该线程会被加入到这个链表中。

就绪链表(调度链表)

所有就绪的线程都会存储在就绪链表中,共有32个就绪链表(32位),所有核共享这32个链表,每个链表对应一个优先级(0~31)。全局变量KiDispatcherReadyListHead存储了这32个链表的起始位置。

扩展:进程、线程遍历

操作系统中所有的线程 = 所有核中等待链表中的所有线程 + 32个就绪链表中所有线程 + 所有核的KPCR中正在运行的线程。

 

而通过遍历线程可以找到每个线程所属的进程。即使断链也无法阻挡这种遍历。

6.线程切换-模拟版

在逆向windows线程切换逻辑之前,先自己写一个模拟的线程切换代码,感受下线程切换的大体思路。

 

滴水模拟线程切换源码:https://wwi.lanzoui.com/iKbe0vdd95g

 

首先初始化四个线程。然后观察初始化函数RegisterGMThread。

 

image-20211015144640033

RegisterGMThread

代码中定义了一个线程池,是一个全局数组变量,每个元素都是自定义的线程结构体。

 

image-20211015144820770

 

image-20211015144839452

 

initGMThread函数里首先为新线程分配一个堆栈空间。

 

image-20211015145100820

 

然后向分配出来的堆栈空间里压入了几个初始值,这些值皆是线程切换时要用到的数值,在创建完第一次被切换时这些值会作为初始值参与线程切换。而其中的push 9作用只是为了占用4个字节。这里需要配合后文线程切换函数才能体会到这4字节的作用。

 

image-20211015145210709

 

至此,线程初始化工作完成,我们接下来需要看看线程是怎么跑起来的,怎么切换的。

 

main函数中初始完四个线程结构后,进入死循环,每隔20毫秒调用一次线程切换函数Scheduling。这相当于Windows线程切换中的时钟中断。当执行了20毫秒后,强制切换当前线程。

 

image-20211015145435127

Scheduling

遍历线程池,找到第一个处于就绪状态的线程。随后调用SwitchContext开始切换线程。

 

image-20211015145611601

SwitchContext

保存当前线程的寄存器,并将当前线程的ESP单独存入线程结构体的KernelStack中。当线程被切换回来时拿着这个ESP可以继续执行代码。

 

image-20211015145820070

 

还原新线程的寄存器。

 

image-20211015150009359

 

最后执行个ret,此时的ret返回的地址就是线程初始化函数initGMThread压入的GMThreadStartup函数地址。

 

image-20211015150148429

GMThreadStartup

这个函数是线程函数的调度函数。由于在初始化时压入了线程结构体指针。因此可以直接使用这个结构体去调用线程函数。如果这个线程函数执行完,就会切换到下一个线程。

 

函数调用约定中,ESP为返回地址,ESP+4为第一个参数。因为上文线程初始化函数中push 9占用了4字节,所以这里ESP+4刚好指向了预先压入的线程结构体。这就是push 9占用四字节的妙处。

 

image-20211015150316692

 

然后我们还需要看看其中一个线程函数,发现里面有自定义的GMSleep函数。

 

image-20211015150500615

GMSleep

GMSleep函数会将当前线程设置为休眠状态,并设置休眠时间。在线程切换时会遍历线程判断休眠时间是否结束来恢复就绪状态。当线程调用GMSleep时代表主动提出休眠,此时会调用线程切换函数Scheduling将执行权交给下一个就绪线程。这就是主动切换。

 

image-20211015150632707

总结

这一份简单的模拟线程切换的Demo具有如下特点:

  • 每隔20毫秒,线程被强制切换。也就是被动切换。
  • 线程函数执行完毕,会主动切换到下个就绪线程。
  • 线程调用休眠函数,会主动切换到下个就绪线程。
  • 线程切换时,通过预先设计好的堆栈结构来传递参数。
  • 线程切换时,会保存原寄存器至堆栈中,并把保存现场后的ESP存入线程结构体。在被切换回来时,通过线程结构体的ESP可以恢复原寄存器,并继续执行原线程的剩余代码。
  • 所谓的创建线程,就是初始化一个线程结构体,放到线程链表中,这样就创建了一个线程。

7.Windows线程切换-就绪线程查询

KPRCB中ReadySummary成员(0x31EC)为就绪位图,4字节32位。每一位对应一条就绪链表。某一位为1则说明对应的就绪链表中有等待执行的线程。32条就绪链表存储在KPRCB中DispatcherReadyListHead成员。

 

如:ReadySummary值为5,二进制0101,说明第0号、第3号就绪链表中存在待执行线程。在线程切换时就会从这两个链表中取待切换的线程。

逆向KiFindReadyThread

KiFindReadyThread有三个函数,通过交叉引用回溯可以知道三个函数的意义:

  1. eax: KPRCB->ReadySummary 就绪位图
  2. ebp+8 : KPRCB指针,从fs:20取得。
  3. ebp+8: KPRCB指针,从KiProcesserBlock全局变量取得。

首先代码会解析就绪位图,找到优先级最高且包含就绪线程的就绪链表索引号。通过代码逻辑可以得知,就绪链表索引号越大,优先级越高。

 

image-20211201170213504

 

随后遍历就绪链表中所有线程,对比线程亲核性是否与当前核一致。只有当核组与核编号全部一样时才可以。若当前就绪链表内所有线程都不满足亲核性,则更换下一条就绪链表。若所有就绪链表中的线程都不满足,则返回0。

 

若成功找到一个满足亲核性的线程,则会将这个线程从就绪链表中摘除,然后继续判断该线程所在就绪链表是否为空(所谓空,为去掉空闲线程之后。CPU不会休息,所以系统准备了一个循环无意义线程让CPU保持活性),如果为空则将KPRCB中的就绪位图对应的位至0,代表这个就绪链表里没有就绪线程了。 然后会将找到的那个可用的线程的NextProcessor成员设置为当前核编号以准备运行。最终返回找到的线程的结构体首地址。

一个物理核为一组,里面有很多逻辑核。 线程的亲核性如果设置多核,那么这些核也都会属于一个核组。所以代码层会先判断核组,再判断具体的核。

 

image-20211201170644497

 

image-20211201170849185

结论

通过对KiFindReadyThread函数的逆向得知(仅对于实验中这个win7 X86版本):

  • 就绪链表编号越大,优先级越高,线程越容易被执行。
  • 线程亲核性决定了线程可以跑在哪个核上。如果恶意修改某个线程结构的亲核性为不存在的核,等同于杀死线程。
  • 没有就绪线程时,CPU会运行一个系统事先准备好的空线程。

Windows经常优化线程调度算法,不同版本系统的代码可能会有不同。

8.Windows线程切换

Windows线程切换有两种方式:主动切换(调用WaitForSingleObject、Sleep一类的延迟等待函数)、被动切换(CPU时钟中断)。

 

WRK中定义的线程状态枚举如下:

1
2
3
4
5
6
7
8
9
10
11
typedef enum _KTHREAD_STATE {
    Initialized,  //初始化状态
    Ready,        //就绪状态,此时线程在就绪链表中等待被取出。
    Running,    //运行状态
    Standby,    //备用状态,当一个线程被设置到KPRCB的NextThread成员时,为备用状态,线程切换时会直接切换到NextThread中的线程。
    Terminated,        //结束状态。
    Waiting,        //等待状态。
    Transition,        //交换状态。 当线程优先级很低,执行频率很低时,会被交换到磁盘上。此时为交换状态。内部细分为:正在换出、已经换出、正在换入、已经换入。
    DeferredReady,    //没用到
    GateWait    //没用到
} KTHREAD_STATE;

主动切换-KiSwapThread

Windows线程切换细节很多,目前的知识只要逆向主流程就可以,分支流程不需要太关注。

 

对KiSwapThread进行多次交叉引用,得出结论:绝大部分API底层都会调用WaitForSingleObject一类的函数,此时会调用KiSwapThread切换线程。

 

image-20211202101425592

 

image-20211202101624092

 

image-20211202101636922

 

通过交叉引用向上回溯,得知KiSwapThread有两个参数:

  • edx : Kprcb指针
  • eax : 当前线程结构体指针。

首先判断延迟就绪链表中是否有值,如果有值就唤醒里面的线程。

 

image-20211203155757777

 

然后是性能统计相关,不需要关注,直接跳过去。

 

image-20211203155841233

 

调用函数KiSearchForNewThread获取一个就绪线程。

 

image-20211203155933299

 

判断这个就绪线程是不是空闲线程,是不是与当前线程相同。

 

image-20211203160124379

 

如果就绪线程通过了上面的判断,则调用SwapContext。

 

image-20211203160216188

 

KiSwapContext中没有做什么事情,只是调用了SwapContext,传入新、老线程。

 

image-20211203161407617

SwapContext

首先判断新线程的运行状态,如果正在运行就执行自旋直到新线程处于非运行状态。

 

image-20211203161504187

 

随后将新线程运行状态置为 1 ,代表将要切换了。然后执行性能统计。

 

image-20211203161725140

 

然后处理浮点相关数据。

 

image-20211206104722055

 

切换堆栈,切换后再判断新老线程是否为同一个进程。如果不是同一个进程,再切换CR3。

 

image-20211206105811479

 

然后处理浮点相关,还原CR0、浮点寄存器一类的东西,不重要。

 

image-20211206112451776

 

随后处理DPC、APC,目前知识不够,暂时不用管这部分,处理完后就返回了。

 

image-20211206113545960

总结

WIndows的线程切换有很多细节,目前的知识点不足以把每一行代码的功能作用都分析透彻,总体分析完毕能得出以下结论:

  • 用户层绝大部分API的调用都会导致线程的切换。
  • Windows提供了一个空闲线程用于当无线程待运行时来保持CPU的运行。
  • 线程的运行状态存储在KPROCESS->Running中
  • 在切换线程时清空了GS寄存器
  • 线程的切换就是堆栈的切换
  • 一个线程的所属进程存储在KTHREAD->APCState->Process中
  • 本质上没有进程的切换,在切换线程时会做进程判断,顺带切换CR3。

被动切换-时钟中断

除了API主动切换线程,Windows还具备另外一种线程切换方式:时钟中断(可屏蔽)。接下来论证一下。

 

windbg输入命令 !idt 查看idt表中对应的函数,其中有一项名为hal!HalpHpetClockInterrupt

 

image-20211207133612926

 

该函数属于hal模块,但Windows系统对于不同的处理器提供了不同的hal模块。在Windbg中输入命令lm查看当前Windows使用的hal模块全名称。我这里的是halmacpi.dll

 

image-20211207133840415

 

定位至HalpHpetClockInterrupt函数,简单看一下函数的调用结构,可以发现函数内部共调用了HalBeginSystemInterrupt@12、HalpHpetClockInterruptWork@0、KeUpdateSystemTime@0三个函数。

 

image-20211207134306045

 

进入前两个函数发现没什么实际功能,最后一个函数用于调用ntoskrnl模块的KeUpdateSystemTime函数。

 

image-20211207134427927

 

image-20211207134441697

 

定位至ntoskrnl模块的KeUpdateSystemTime函数,发现这个函数非常长。慢慢往下翻,该函数会调用KeUpdateRunTime函数。

 

image-20211207135306678

 

KeUpdateRunTime函数内部会调用hal模块的HalRequestSoftwareInterrupt函数。该函数会触发软件中断。

 

image-20211207135316906

 

HalRequestSoftwareInterrupt内部调用KfLowerIrql函数。

 

image-20211207135709191

 

KfLowerIrql函数调用HalpCheckForSoftwareInterrupt函数。该函数用于检查软件中断。

 

image-20211207135740688

 

HalpCheckForSoftwareInterrupt函数内部会调用HalpDispatchSoftwareInterrupt来派发软件中断。

 

image-20211207142314192

 

再调用ntoskrnl的KiDispatchInterrupt函数来执行派发。

 

image-20211207142401359

 

而在KiDispatchInterrupt函数中会调用KiQueueReadyThread与SwapContext函数,因此会导致线程切换。

 

image-20211207142517525

总结

上文论证了时钟中断会导致线程切换,整体执行流程为:

1
2
3
4
5
6
7
8
9
hal!HalpHpetClockInterrupt
->nt!KeUpdateSystemTime
->nt!KeUpdateRunTime
->hal!HalRequestSoftwareInterrupt
->hal!KfLowerIrql
->hal!HalpCheckForSoftwareInterrupt
->hal!HalpDispatchSoftwareInterrupt
->nt!KiDispatchInterrupt
->SwapContext

通过对流程的分析,还可以得出另外一个结论:软件中断会导致线程的切换。保护模式章节提到过int X一类的软件中断本质为异常。因此,在Windows操作系统中,调用绝大部分API 以及 触发各种异常 均会导致线程的切换。如果想让自己的线程永远占有CPU,则不可以调用API、不能触发异常(内存访问也可能触发缺页异常,在用户层是看不出来的)。

9.总结及实际应用

windows的进程线程管理非常复杂,这里仅对主线功能进行了分析。目的是认识进程线程,摆脱传统的进程线程观念。

 

在Win7系统中,由于不存在PG,因此可以HOOK SwapContext,达到替换指定线程的GDT、IDT的效果,从而绕过一些防护检测。


【公告】 [2022大礼包]《看雪论坛精华22期》发布!收录近1000余篇精华优秀文章!

收藏
点赞0
打赏
分享
最新回复 (6)
雪    币: 985
活跃值: 活跃值 (1126)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
fengyunabc 活跃值 1 2021-12-7 17:03
2
0
Win7系统不存在PG??? 你确定???
雪    币: 9064
活跃值: 活跃值 (10788)
能力值: ( LV12,RANK:385 )
在线值:
发帖
回帖
粉丝
SSH山水画 活跃值 3 2021-12-7 17:28
3
0
fengyunabc Win7系统不存在PG??? 你确定???
32位
雪    币: 2351
活跃值: 活跃值 (739)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
ezre 活跃值 2021-12-8 23:28
4
0
请问你是看的滴水的教程吗?
雪    币: 9064
活跃值: 活跃值 (10788)
能力值: ( LV12,RANK:385 )
在线值:
发帖
回帖
粉丝
SSH山水画 活跃值 3 2021-12-9 09:12
5
0
ezre 请问你是看的滴水的教程吗?
滴水+火哥
雪    币: 558
活跃值: 活跃值 (202)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
JuneKill 活跃值 2021-12-12 14:59
6
0
SSH山水画 滴水+火哥
大佬, 是滴水初级+火哥中级么
雪    币: 668
活跃值: 活跃值 (199)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
gaoliangk 活跃值 2021-12-17 22:17
7
0
好啊好啊,海哥子弟
游客
登录 | 注册 方可回帖
返回