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
| struct _KPCR { union { struct _NT_TIB NtTib; struct { struct _EXCEPTION_REGISTRATION_RECORD* Used_ExceptionList; VOID* Used_StackBase; VOID* Spare2; VOID* TssCopy; ULONG ContextSwitches; ULONG SetMemberCopy; VOID* Used_Self; }; }; struct _KPCR* SelfPcr; struct _KPRCB* Prcb; UCHAR Irql; ULONG IRR; ULONG IrrActive; ULONG IDR; VOID* KdVersionBlock; struct _KIDTENTRY* IDT; struct _KGDTENTRY* GDT; struct _KTSS* TSS; USHORT MajorVersion; USHORT MinorVersion; ULONG SetMember; ULONG StallScaleFactor; UCHAR SpareUnused; UCHAR Number; UCHAR Spare0; UCHAR SecondLevelCacheAssociativity; ULONG VdmAlert; ULONG KernelReserved[14]; ULONG SecondLevelCacheSize; ULONG HalReserved[16]; ULONG InterruptMode; UCHAR Spare1; ULONG KernelReserved2[17]; struct _KPRCB PrcbData; };
|
- +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
| struct _KPRCB { USHORT MinorVersion; USHORT MajorVersion; struct _KTHREAD* CurrentThread; struct _KTHREAD* NextThread; struct _KTHREAD* IdleThread; UCHAR LegacyNumber; UCHAR NestingLevel; USHORT BuildType; CHAR CpuType; CHAR CpuID; union { USHORT CpuStep; struct { UCHAR CpuStepping; UCHAR CpuModel; }; }; struct _KPROCESSOR_STATE ProcessorState; ULONG KernelReserved[16]; ULONG HalReserved[16]; ULONG CFlushSize; UCHAR CoresPerPhysicalProcessor; UCHAR LogicalProcessorsPerCore; UCHAR PrcbPad0[2]; ULONG MHz; UCHAR CpuVendor; UCHAR GroupIndex; USHORT Group; ULONG GroupSetMember; ULONG Number; UCHAR PrcbPad1[72]; struct _KSPIN_LOCK_QUEUE LockQueue[17]; struct _KTHREAD* NpxThread; ULONG InterruptCount; ULONG KernelTime; ULONG UserTime; ULONG DpcTime; ULONG DpcTimeCount; ULONG InterruptTime; ULONG AdjustDpcThreshold; ULONG PageColor; UCHAR DebuggerSavedIRQL; UCHAR NodeColor; UCHAR PrcbPad20[2]; ULONG NodeShiftedColor; struct _KNODE* ParentNode; ULONG SecondaryColorMask; ULONG DpcTimeLimit; ULONG PrcbPad21[2]; ULONG CcFastReadNoWait; ULONG CcFastReadWait; ULONG CcFastReadNotPossible; ULONG CcCopyReadNoWait; ULONG CcCopyReadWait; ULONG CcCopyReadNoWaitMiss; volatile LONG MmSpinLockOrdering; volatile LONG IoReadOperationCount; volatile LONG IoWriteOperationCount; volatile LONG IoOtherOperationCount; union _LARGE_INTEGER IoReadTransferCount; union _LARGE_INTEGER IoWriteTransferCount; union _LARGE_INTEGER IoOtherTransferCount; ULONG CcFastMdlReadNoWait; ULONG CcFastMdlReadWait; ULONG CcFastMdlReadNotPossible; ULONG CcMapDataNoWait; ULONG CcMapDataWait; ULONG CcPinMappedDataCount; ULONG CcPinReadNoWait; ULONG CcPinReadWait; ULONG CcMdlReadNoWait; ULONG CcMdlReadWait; ULONG CcLazyWriteHotSpots; ULONG CcLazyWriteIos; ULONG CcLazyWritePages; ULONG CcDataFlushes; ULONG CcDataPages; ULONG CcLostDelayedWrites; ULONG CcFastReadResourceMiss; ULONG CcCopyReadWaitMiss; ULONG CcFastMdlReadResourceMiss; ULONG CcMapDataNoWaitMiss; ULONG CcMapDataWaitMiss; ULONG CcPinReadNoWaitMiss; ULONG CcPinReadWaitMiss; ULONG CcMdlReadNoWaitMiss; ULONG CcMdlReadWaitMiss; ULONG CcReadAheadIos; ULONG KeAlignmentFixupCount; ULONG KeExceptionDispatchCount; ULONG KeSystemCalls; ULONG AvailableTime; ULONG PrcbPad22[2]; struct _PP_LOOKASIDE_LIST PPLookasideList[16]; struct _GENERAL_LOOKASIDE_POOL PPNPagedLookasideList[32]; struct _GENERAL_LOOKASIDE_POOL PPPagedLookasideList[32]; volatile ULONG PacketBarrier; volatile LONG ReverseStall; VOID* IpiFrame; UCHAR PrcbPad3[52]; VOID* volatile CurrentPacket[3]; volatile ULONG TargetSet; VOID (* volatileWorkerRoutine)(VOID* arg1, VOID* arg2, VOID* arg3, VOID* arg4); volatile ULONG IpiFrozen; UCHAR PrcbPad4[40]; volatile ULONG RequestSummary; struct _KPRCB* volatile SignalDone; UCHAR PrcbPad50[56]; struct _KDPC_DATA DpcData[2]; VOID* DpcStack; LONG MaximumDpcQueueDepth; ULONG DpcRequestRate; ULONG MinimumDpcRate; ULONG DpcLastCount; ULONG PrcbLock; struct _KGATE DpcGate; UCHAR ThreadDpcEnable; volatile UCHAR QuantumEnd; volatile UCHAR DpcRoutineActive; volatile UCHAR IdleSchedule; union { volatile LONG DpcRequestSummary; SHORT DpcRequestSlot[2]; struct { SHORT NormalDpcState; union { volatile USHORT DpcThreadActive:1; SHORT ThreadDpcState; }; }; }; volatile ULONG TimerHand; ULONG LastTick; LONG MasterOffset; ULONG PrcbPad41[2]; ULONG PeriodicCount; ULONG PeriodicBias; ULONGLONG TickOffset; struct _KTIMER_TABLE TimerTable; struct _KDPC CallDpc; LONG ClockKeepAlive; UCHAR ClockCheckSlot; UCHAR ClockPollCycle; UCHAR PrcbPad6[2]; LONG DpcWatchdogPeriod; LONG DpcWatchdogCount; LONG ThreadWatchdogPeriod; LONG ThreadWatchdogCount; volatile LONG KeSpinLockOrdering; ULONG PrcbPad70[1]; struct _LIST_ENTRY WaitListHead; ULONG WaitLock; ULONG ReadySummary; ULONG QueueIndex; struct _SINGLE_LIST_ENTRY DeferredReadyListHead; ULONGLONG StartCycles; volatile ULONGLONG CycleTime; volatile ULONG HighCycleTime; ULONG PrcbPad71; ULONGLONG PrcbPad72[2]; struct _LIST_ENTRY DispatcherReadyListHead[32]; VOID* ChainedInterruptList; LONG LookasideIrpFloat; volatile LONG MmPageFaultCount; volatile LONG MmCopyOnWriteCount; volatile LONG MmTransitionCount; volatile LONG MmCacheTransitionCount; volatile LONG MmDemandZeroCount; volatile LONG MmPageReadCount; volatile LONG MmPageReadIoCount; volatile LONG MmCacheReadCount; volatile LONG MmCacheIoCount; volatile LONG MmDirtyPagesWriteCount; volatile LONG MmDirtyWriteIoCount; volatile LONG MmMappedPagesWriteCount; volatile LONG MmMappedWriteIoCount; volatile ULONG CachedCommit; volatile ULONG CachedResidentAvailable; VOID* HyperPte; UCHAR PrcbPad8[4]; UCHAR VendorString[13]; UCHAR InitialApicId; UCHAR LogicalProcessorsPerPhysicalProcessor; UCHAR PrcbPad9[5]; ULONG FeatureBits; union _LARGE_INTEGER UpdateSignature; volatile ULONGLONG IsrTime; ULONGLONG RuntimeAccumulation; struct _PROCESSOR_POWER_STATE PowerState; struct _KDPC DpcWatchdogDpc; struct _KTIMER DpcWatchdogTimer; VOID* WheaInfo; VOID* EtwSupport; union _SLIST_HEADER InterruptObjectPool; union _SLIST_HEADER HypercallPageList; VOID* HypercallPageVirtual; VOID* VirtualApicAssist; ULONGLONG* StatisticsPage; VOID* RateControl; struct _CACHE_DESCRIPTOR Cache[5]; ULONG CacheCount; ULONG CacheProcessorMask[5]; struct _KAFFINITY_EX PackageProcessorSet; ULONG PrcbPad91[1]; ULONG CoreProcessorSet; struct _KDPC TimerExpirationDpc; ULONG SpinLockAcquireCount; ULONG SpinLockContentionCount; ULONG SpinLockSpinCount; ULONG IpiSendRequestBroadcastCount; ULONG IpiSendRequestRoutineCount; ULONG IpiSendSoftwareInterruptCount; ULONG ExInitializeResourceCount; ULONG ExReInitializeResourceCount; ULONG ExDeleteResourceCount; ULONG ExecutiveResourceAcquiresCount; ULONG ExecutiveResourceContentionsCount; ULONG ExecutiveResourceReleaseExclusiveCount; ULONG ExecutiveResourceReleaseSharedCount; ULONG ExecutiveResourceConvertsCount; ULONG ExAcqResExclusiveAttempts; ULONG ExAcqResExclusiveAcquiresExclusive; ULONG ExAcqResExclusiveAcquiresExclusiveRecursive; ULONG ExAcqResExclusiveWaits; ULONG ExAcqResExclusiveNotAcquires; ULONG ExAcqResSharedAttempts; ULONG ExAcqResSharedAcquiresExclusive; ULONG ExAcqResSharedAcquiresShared; ULONG ExAcqResSharedAcquiresSharedRecursive; ULONG ExAcqResSharedWaits; ULONG ExAcqResSharedNotAcquires; ULONG ExAcqResSharedStarveExclusiveAttempts; ULONG ExAcqResSharedStarveExclusiveAcquiresExclusive; ULONG ExAcqResSharedStarveExclusiveAcquiresShared; ULONG ExAcqResSharedStarveExclusiveAcquiresSharedRecursive; ULONG ExAcqResSharedStarveExclusiveWaits; ULONG ExAcqResSharedStarveExclusiveNotAcquires; ULONG ExAcqResSharedWaitForExclusiveAttempts; ULONG ExAcqResSharedWaitForExclusiveAcquiresExclusive; ULONG ExAcqResSharedWaitForExclusiveAcquiresShared; ULONG ExAcqResSharedWaitForExclusiveAcquiresSharedRecursive; ULONG ExAcqResSharedWaitForExclusiveWaits; ULONG ExAcqResSharedWaitForExclusiveNotAcquires; ULONG ExSetResOwnerPointerExclusive; ULONG ExSetResOwnerPointerSharedNew; ULONG ExSetResOwnerPointerSharedOld; ULONG ExTryToAcqExclusiveAttempts; ULONG ExTryToAcqExclusiveAcquires; ULONG ExBoostExclusiveOwner; ULONG ExBoostSharedOwners; ULONG ExEtwSynchTrackingNotificationsCount; ULONG ExEtwSynchTrackingNotificationsAccountedCount; struct _CONTEXT* Context; ULONG ContextFlags; struct _XSAVE_AREA* ExtendedState; };
|
- +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
| struct _EPROCESS { struct _KPROCESS Pcb; struct _EX_PUSH_LOCK ProcessLock; union _LARGE_INTEGER CreateTime; union _LARGE_INTEGER ExitTime; struct _EX_RUNDOWN_REF RundownProtect; VOID* UniqueProcessId; struct _LIST_ENTRY ActiveProcessLinks; ULONG ProcessQuotaUsage[2]; ULONG ProcessQuotaPeak[2]; volatile ULONG CommitCharge; struct _EPROCESS_QUOTA_BLOCK* QuotaBlock; struct _PS_CPU_QUOTA_BLOCK* CpuQuotaBlock; ULONG PeakVirtualSize; ULONG VirtualSize; struct _LIST_ENTRY SessionProcessLinks; VOID* DebugPort; union { VOID* ExceptionPortData; ULONG ExceptionPortValue; ULONG ExceptionPortState:3; }; struct _HANDLE_TABLE* ObjectTable; struct _EX_FAST_REF Token; ULONG WorkingSetPage; struct _EX_PUSH_LOCK AddressCreationLock; struct _ETHREAD* RotateInProgress; struct _ETHREAD* ForkInProgress; ULONG HardwareTrigger; struct _MM_AVL_TABLE* PhysicalVadRoot; VOID* CloneRoot; volatile ULONG NumberOfPrivatePages; volatile ULONG NumberOfLockedPages; VOID* Win32Process; struct _EJOB* volatile Job; VOID* SectionObject; VOID* SectionBaseAddress; ULONG Cookie; ULONG Spare8; struct _PAGEFAULT_HISTORY* WorkingSetWatch; VOID* Win32WindowStation; VOID* InheritedFromUniqueProcessId; VOID* LdtInformation; VOID* VdmObjects; ULONG ConsoleHostProcess; VOID* DeviceMap; VOID* EtwDataSource; VOID* FreeTebHint; union { struct _HARDWARE_PTE PageDirectoryPte; ULONGLONG Filler; }; VOID* Session; UCHAR ImageFileName[15]; UCHAR PriorityClass; struct _LIST_ENTRY JobLinks; VOID* LockedPagesList; struct _LIST_ENTRY ThreadListHead; VOID* SecurityPort; VOID* PaeTop; volatile ULONG ActiveThreads; ULONG ImagePathHash; ULONG DefaultHardErrorProcessing; LONG LastThreadExitStatus; struct _PEB* Peb; struct _EX_FAST_REF PrefetchTrace; union _LARGE_INTEGER ReadOperationCount; union _LARGE_INTEGER WriteOperationCount; union _LARGE_INTEGER OtherOperationCount; union _LARGE_INTEGER ReadTransferCount; union _LARGE_INTEGER WriteTransferCount; union _LARGE_INTEGER OtherTransferCount; ULONG CommitChargeLimit; volatile ULONG CommitChargePeak; VOID* AweInfo; struct _SE_AUDIT_PROCESS_CREATION_INFO SeAuditProcessCreationInfo; struct _MMSUPPORT Vm; struct _LIST_ENTRY MmProcessLinks; VOID* HighestUserAddress; ULONG ModifiedPageCount; union { ULONG Flags2; struct { ULONG JobNotReallyActive:1; ULONG AccountingFolded:1; ULONG NewProcessReported:1; ULONG ExitProcessReported:1; ULONG ReportCommitChanges:1; ULONG LastReportMemory:1; ULONG ReportPhysicalPageChanges:1; ULONG HandleTableRundown:1; ULONG NeedsHandleRundown:1; ULONG RefTraceEnabled:1; ULONG NumaAware:1; ULONG ProtectedProcess:1; ULONG DefaultPagePriority:3; ULONG PrimaryTokenFrozen:1; ULONG ProcessVerifierTarget:1; ULONG StackRandomizationDisabled:1; ULONG AffinityPermanent:1; ULONG AffinityUpdateEnable:1; ULONG PropagateNode:1; ULONG ExplicitAffinity:1; }; }; union { ULONG Flags; struct { ULONG CreateReported:1; ULONG NoDebugInherit:1; ULONG ProcessExiting:1; ULONG ProcessDelete:1; ULONG Wow64SplitPages:1; ULONG VmDeleted:1; ULONG OutswapEnabled:1; ULONG Outswapped:1; ULONG ForkFailed:1; ULONG Wow64VaSpace4Gb:1; ULONG AddressSpaceInitialized:2; ULONG SetTimerResolution:1; ULONG BreakOnTermination:1; ULONG DeprioritizeViews:1; ULONG WriteWatch:1; ULONG ProcessInSession:1; ULONG OverrideAddressSpace:1; ULONG HasAddressSpace:1; ULONG LaunchPrefetched:1; ULONG InjectInpageErrors:1; ULONG VmTopDown:1; ULONG ImageNotifyDone:1; ULONG PdeUpdateNeeded:1; ULONG VdmAllowed:1; ULONG CrossSessionCreate:1; ULONG ProcessInserted:1; ULONG DefaultIoPriority:3; ULONG ProcessSelfDelete:1; ULONG SetTimerResolutionLink:1; }; }; LONG ExitStatus; struct _MM_AVL_TABLE VadRoot; struct _ALPC_PROCESS_CONTEXT AlpcContext; struct _LIST_ENTRY TimerResolutionLink; ULONG RequestedTimerResolution; ULONG ActiveThreadsHighWatermark; ULONG SmallestTimerResolution; struct _PO_DIAG_STACK_RECORD* TimerResolutionStackRecord; };
|
- +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附加进程列表遍历不到。一个最简单的进程保护。
+270 Flags:一个联合体,每个位影响该进程的一些属性。
- ProcessExiting:进程退出标志位。置1后表明该进程已退出,但实际还在运行。可以达到反调试的效果。同时进程无法使用任务管理器结束。
- ProcessDelete:进程退出标志位。置1后表明该进程已退出,但实际还在运行。可以达到反调试的效果。同时进程无法使用任务管理器结束。
BreakOnTermination:该位置1后,任务管理器结束进程时将提示“是否结束系统进程XXX”。结束后windbg将会断下。
- 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
| struct _KPROCESS { struct _DISPATCHER_HEADER Header; struct _LIST_ENTRY ProfileListHead; ULONG DirectoryTableBase; struct _KGDTENTRY LdtDescriptor; struct _KIDTENTRY Int21Descriptor; struct _LIST_ENTRY ThreadListHead; ULONG ProcessLock; struct _KAFFINITY_EX Affinity; struct _LIST_ENTRY ReadyListHead; struct _SINGLE_LIST_ENTRY SwapListEntry; volatile struct _KAFFINITY_EX ActiveProcessors; union { struct { volatile LONG AutoAlignment:1; volatile LONG DisableBoost:1; volatile LONG DisableQuantum:1; volatile ULONG ActiveGroupsMask:1; volatile LONG ReservedFlags:28; }; volatile LONG ProcessFlags; }; CHAR BasePriority; CHAR QuantumReset; UCHAR Visited; UCHAR Unused3; ULONG ThreadSeed[1]; USHORT IdealNode[1]; USHORT IdealGlobalNode; union _KEXECUTE_OPTIONS Flags; UCHAR Unused1; USHORT IopmOffset; ULONG Unused4; union _KSTACK_COUNT StackCount; struct _LIST_ENTRY ProcessListEntry; volatile ULONGLONG CycleTime; ULONG KernelTime; ULONG UserTime; VOID* VdmTrapcHandler; };
|
+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
| struct _ETHREAD { struct _KTHREAD Tcb; union _LARGE_INTEGER CreateTime; union { union _LARGE_INTEGER ExitTime; struct _LIST_ENTRY KeyedWaitChain; }; LONG ExitStatus; union { struct _LIST_ENTRY PostBlockList; struct { VOID* ForwardLinkShadow; VOID* StartAddress; }; }; union { struct _TERMINATION_PORT* TerminationPort; struct _ETHREAD* ReaperLink; VOID* KeyedWaitValue; }; ULONG ActiveTimerListLock; struct _LIST_ENTRY ActiveTimerListHead; struct _CLIENT_ID Cid; union { struct _KSEMAPHORE KeyedWaitSemaphore; struct _KSEMAPHORE AlpcWaitSemaphore; }; union _PS_CLIENT_SECURITY_CONTEXT ClientSecurity; struct _LIST_ENTRY IrpList; ULONG TopLevelIrp; struct _DEVICE_OBJECT* DeviceToVerify; union _PSP_CPU_QUOTA_APC* CpuQuotaApc; VOID* Win32StartAddress; VOID* LegacyPowerObject; struct _LIST_ENTRY ThreadListEntry; struct _EX_RUNDOWN_REF RundownProtect; struct _EX_PUSH_LOCK ThreadLock; ULONG ReadClusterSize; volatile LONG MmLockOrdering; union { ULONG CrossThreadFlags; struct { ULONG Terminated:1; ULONG ThreadInserted:1; ULONG HideFromDebugger:1; ULONG ActiveImpersonationInfo:1; ULONG Reserved:1; ULONG HardErrorsAreDisabled:1; ULONG BreakOnTermination:1; ULONG SkipCreationMsg:1; ULONG SkipTerminationMsg:1; ULONG CopyTokenOnOpen:1; ULONG ThreadIoPriority:3; ULONG ThreadPagePriority:3; ULONG RundownFail:1; ULONG NeedsWorkingSetAging:1; }; }; union { ULONG SameThreadPassiveFlags; struct { ULONG ActiveExWorker:1; ULONG ExWorkerCanWaitUser:1; ULONG MemoryMaker:1; ULONG ClonedThread:1; ULONG KeyedEventInUse:1; ULONG RateApcState:2; ULONG SelfTerminate:1; }; }; union { ULONG SameThreadApcFlags; struct { UCHAR Spare:1; volatile UCHAR StartAddressInvalid:1; UCHAR EtwPageFaultCalloutActive:1; UCHAR OwnsProcessWorkingSetExclusive:1; UCHAR OwnsProcessWorkingSetShared:1; UCHAR OwnsSystemCacheWorkingSetExclusive:1; UCHAR OwnsSystemCacheWorkingSetShared:1; UCHAR OwnsSessionWorkingSetExclusive:1; UCHAR OwnsSessionWorkingSetShared:1; UCHAR OwnsProcessAddressSpaceExclusive:1; UCHAR OwnsProcessAddressSpaceShared:1; UCHAR SuppressSymbolLoad:1; UCHAR Prefetching:1; UCHAR OwnsDynamicMemoryShared:1; UCHAR OwnsChangeControlAreaExclusive:1; UCHAR OwnsChangeControlAreaShared:1; UCHAR OwnsPagedPoolWorkingSetExclusive:1; UCHAR OwnsPagedPoolWorkingSetShared:1; UCHAR OwnsSystemPtesWorkingSetExclusive:1; UCHAR OwnsSystemPtesWorkingSetShared:1; UCHAR TrimTrigger:2; UCHAR Spare1:2; UCHAR PriorityRegionActive; }; }; UCHAR CacheManagerActive; UCHAR DisablePageFaultClustering; UCHAR ActiveFaultCount; UCHAR LockOrderState; ULONG AlpcMessageId; union { VOID* AlpcMessage; ULONG AlpcReceiveAttributeSet; }; struct _LIST_ENTRY AlpcWaitListEntry; ULONG CacheManagerCount; ULONG IoBoostCount; ULONG IrpListLock; VOID* ReservedForSynchTracking; struct _SINGLE_LIST_ENTRY CmCallbackListHead; };
|
- +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
| struct _KTHREAD { struct _DISPATCHER_HEADER Header; volatile ULONGLONG CycleTime; volatile ULONG HighCycleTime; ULONGLONG QuantumTarget; VOID* InitialStack; VOID* volatile StackLimit; VOID* KernelStack; ULONG ThreadLock; union _KWAIT_STATUS_REGISTER WaitRegister; volatile UCHAR Running; UCHAR Alerted[2]; union { struct { ULONG KernelStackResident:1; ULONG ReadyTransition:1; ULONG ProcessReadyQueue:1; ULONG WaitNext:1; ULONG SystemAffinityActive:1; ULONG Alertable:1; ULONG GdiFlushActive:1; ULONG UserStackWalkActive:1; ULONG ApcInterruptRequest:1; ULONG ForceDeferSchedule:1; ULONG QuantumEndMigrate:1; ULONG UmsDirectedSwitchEnable:1; ULONG TimerActive:1; ULONG SystemThread:1; ULONG Reserved:18; }; LONG MiscFlags; }; union { struct _KAPC_STATE ApcState; struct { UCHAR ApcStateFill[23]; CHAR Priority; }; }; volatile ULONG NextProcessor; volatile ULONG DeferredProcessor; ULONG ApcQueueLock; ULONG ContextSwitches; volatile UCHAR State; CHAR NpxState; UCHAR WaitIrql; CHAR WaitMode; volatile LONG WaitStatus; struct _KWAIT_BLOCK* WaitBlockList; union { struct _LIST_ENTRY WaitListEntry; struct _SINGLE_LIST_ENTRY SwapListEntry; }; struct _KQUEUE* volatile Queue; ULONG WaitTime; union { struct { SHORT KernelApcDisable; SHORT SpecialApcDisable; }; ULONG CombinedApcDisable; }; VOID* Teb; struct _KTIMER Timer; union { struct { volatile ULONG AutoAlignment:1; volatile ULONG DisableBoost:1; volatile ULONG EtwStackTraceApc1Inserted:1; volatile ULONG EtwStackTraceApc2Inserted:1; volatile ULONG CalloutActive:1; volatile ULONG ApcQueueable:1; volatile ULONG EnableStackSwap:1; volatile ULONG GuiThread:1; volatile ULONG UmsPerformingSyscall:1; volatile ULONG VdmSafe:1; volatile ULONG UmsDispatched:1; volatile ULONG ReservedFlags:21; }; volatile LONG ThreadFlags; }; VOID* ServiceTable; struct _KWAIT_BLOCK WaitBlock[4]; struct _LIST_ENTRY QueueListEntry; struct _KTRAP_FRAME* TrapFrame; VOID* FirstArgument; union { VOID* CallbackStack; ULONG CallbackDepth; }; UCHAR ApcStateIndex; CHAR BasePriority; union { CHAR PriorityDecrement; struct { UCHAR ForegroundBoost:4; UCHAR UnusualBoost:4; }; }; UCHAR Preempted; UCHAR AdjustReason; CHAR AdjustIncrement; CHAR PreviousMode; CHAR Saturation; ULONG SystemCallNumber; ULONG FreezeCount; volatile struct _GROUP_AFFINITY UserAffinity; struct _KPROCESS* Process; volatile struct _GROUP_AFFINITY Affinity; ULONG IdealProcessor; ULONG UserIdealProcessor; struct _KAPC_STATE* ApcStatePointer[2]; union { struct _KAPC_STATE SavedApcState; struct { UCHAR SavedApcStateFill[23]; UCHAR WaitReason; }; }; CHAR SuspendCount; CHAR Spare1; UCHAR OtherPlatformFill; VOID* volatile Win32Thread; VOID* StackBase; union { struct _KAPC SuspendApc; struct { UCHAR SuspendApcFill0[1]; UCHAR ResourceIndex; }; struct { UCHAR SuspendApcFill1[3]; UCHAR QuantumReset; }; struct { UCHAR SuspendApcFill2[4]; ULONG KernelTime; }; struct { UCHAR SuspendApcFill3[36]; struct _KPRCB* volatile WaitPrcb; }; struct { UCHAR SuspendApcFill4[40]; VOID* LegoData; }; struct { UCHAR SuspendApcFill5[47]; UCHAR LargeStack; }; }; ULONG UserTime; union { struct _KSEMAPHORE SuspendSemaphore; UCHAR SuspendSemaphorefill[20]; }; ULONG SListFaultCount; struct _LIST_ENTRY ThreadListEntry; struct _LIST_ENTRY MutantListHead; VOID* SListFaultAddress; struct _KTHREAD_COUNTERS* ThreadCounters; struct _XSTATE_SAVE* XStateSave; };
|
- +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:当前进程所有线程的双向链表。
每一个内核对象都有一个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。
RegisterGMThread
代码中定义了一个线程池,是一个全局数组变量,每个元素都是自定义的线程结构体。
initGMThread函数里首先为新线程分配一个堆栈空间。
然后向分配出来的堆栈空间里压入了几个初始值,这些值皆是线程切换时要用到的数值,在创建完第一次被切换时这些值会作为初始值参与线程切换。而其中的push 9作用只是为了占用4个字节。这里需要配合后文线程切换函数才能体会到这4字节的作用。
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 jaytp@qq.com