-
-
X86内核笔记_4_进程和线程
-
2021-12-7 15:06 16622
-
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附加进程列表遍历不到。一个最简单的进程保护。
+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 | / / 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。
RegisterGMThread
代码中定义了一个线程池,是一个全局数组变量,每个元素都是自定义的线程结构体。
initGMThread函数里首先为新线程分配一个堆栈空间。
然后向分配出来的堆栈空间里压入了几个初始值,这些值皆是线程切换时要用到的数值,在创建完第一次被切换时这些值会作为初始值参与线程切换。而其中的push 9作用只是为了占用4个字节。这里需要配合后文线程切换函数才能体会到这4字节的作用。
至此,线程初始化工作完成,我们接下来需要看看线程是怎么跑起来的,怎么切换的。
main函数中初始完四个线程结构后,进入死循环,每隔20毫秒调用一次线程切换函数Scheduling。这相当于Windows线程切换中的时钟中断。当执行了20毫秒后,强制切换当前线程。
Scheduling
遍历线程池,找到第一个处于就绪状态的线程。随后调用SwitchContext开始切换线程。
SwitchContext
保存当前线程的寄存器,并将当前线程的ESP单独存入线程结构体的KernelStack中。当线程被切换回来时拿着这个ESP可以继续执行代码。
还原新线程的寄存器。
最后执行个ret,此时的ret返回的地址就是线程初始化函数initGMThread压入的GMThreadStartup函数地址。
GMThreadStartup
这个函数是线程函数的调度函数。由于在初始化时压入了线程结构体指针。因此可以直接使用这个结构体去调用线程函数。如果这个线程函数执行完,就会切换到下一个线程。
函数调用约定中,ESP为返回地址,ESP+4为第一个参数。因为上文线程初始化函数中push 9占用了4字节,所以这里ESP+4刚好指向了预先压入的线程结构体。这就是push 9占用四字节的妙处。
然后我们还需要看看其中一个线程函数,发现里面有自定义的GMSleep函数。
GMSleep
GMSleep函数会将当前线程设置为休眠状态,并设置休眠时间。在线程切换时会遍历线程判断休眠时间是否结束来恢复就绪状态。当线程调用GMSleep时代表主动提出休眠,此时会调用线程切换函数Scheduling将执行权交给下一个就绪线程。这就是主动切换。
总结
这一份简单的模拟线程切换的Demo具有如下特点:
- 每隔20毫秒,线程被强制切换。也就是被动切换。
- 线程函数执行完毕,会主动切换到下个就绪线程。
- 线程调用休眠函数,会主动切换到下个就绪线程。
- 线程切换时,通过预先设计好的堆栈结构来传递参数。
- 线程切换时,会保存原寄存器至堆栈中,并把保存现场后的ESP存入线程结构体。在被切换回来时,通过线程结构体的ESP可以恢复原寄存器,并继续执行原线程的剩余代码。
- 所谓的创建线程,就是初始化一个线程结构体,放到线程链表中,这样就创建了一个线程。
7.Windows线程切换-就绪线程查询
KPRCB中ReadySummary成员(0x31EC)为就绪位图,4字节32位。每一位对应一条就绪链表。某一位为1则说明对应的就绪链表中有等待执行的线程。32条就绪链表存储在KPRCB中DispatcherReadyListHead成员。
如:ReadySummary值为5,二进制0101,说明第0号、第3号就绪链表中存在待执行线程。在线程切换时就会从这两个链表中取待切换的线程。
逆向KiFindReadyThread
KiFindReadyThread有三个函数,通过交叉引用回溯可以知道三个函数的意义:
- eax: KPRCB->ReadySummary 就绪位图
- ebp+8 : KPRCB指针,从fs:20取得。
- ebp+8: KPRCB指针,从KiProcesserBlock全局变量取得。
首先代码会解析就绪位图,找到优先级最高且包含就绪线程的就绪链表索引号。通过代码逻辑可以得知,就绪链表索引号越大,优先级越高。
随后遍历就绪链表中所有线程,对比线程亲核性是否与当前核一致。只有当核组与核编号全部一样时才可以。若当前就绪链表内所有线程都不满足亲核性,则更换下一条就绪链表。若所有就绪链表中的线程都不满足,则返回0。
若成功找到一个满足亲核性的线程,则会将这个线程从就绪链表中摘除,然后继续判断该线程所在就绪链表是否为空(所谓空,为去掉空闲线程之后。CPU不会休息,所以系统准备了一个循环无意义线程让CPU保持活性),如果为空则将KPRCB中的就绪位图对应的位至0,代表这个就绪链表里没有就绪线程了。 然后会将找到的那个可用的线程的NextProcessor成员设置为当前核编号以准备运行。最终返回找到的线程的结构体首地址。
一个物理核为一组,里面有很多逻辑核。 线程的亲核性如果设置多核,那么这些核也都会属于一个核组。所以代码层会先判断核组,再判断具体的核。
结论
通过对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切换线程。
通过交叉引用向上回溯,得知KiSwapThread有两个参数:
- edx : Kprcb指针
- eax : 当前线程结构体指针。
首先判断延迟就绪链表中是否有值,如果有值就唤醒里面的线程。
然后是性能统计相关,不需要关注,直接跳过去。
调用函数KiSearchForNewThread获取一个就绪线程。
判断这个就绪线程是不是空闲线程,是不是与当前线程相同。
如果就绪线程通过了上面的判断,则调用SwapContext。
KiSwapContext中没有做什么事情,只是调用了SwapContext,传入新、老线程。
SwapContext
首先判断新线程的运行状态,如果正在运行就执行自旋直到新线程处于非运行状态。
随后将新线程运行状态置为 1 ,代表将要切换了。然后执行性能统计。
然后处理浮点相关数据。
切换堆栈,切换后再判断新老线程是否为同一个进程。如果不是同一个进程,再切换CR3。
然后处理浮点相关,还原CR0、浮点寄存器一类的东西,不重要。
随后处理DPC、APC,目前知识不够,暂时不用管这部分,处理完后就返回了。
总结
WIndows的线程切换有很多细节,目前的知识点不足以把每一行代码的功能作用都分析透彻,总体分析完毕能得出以下结论:
- 用户层绝大部分API的调用都会导致线程的切换。
- Windows提供了一个空闲线程用于当无线程待运行时来保持CPU的运行。
- 线程的运行状态存储在KPROCESS->Running中
- 在切换线程时清空了GS寄存器
- 线程的切换就是堆栈的切换
- 一个线程的所属进程存储在KTHREAD->APCState->Process中
- 本质上没有进程的切换,在切换线程时会做进程判断,顺带切换CR3。
被动切换-时钟中断
除了API主动切换线程,Windows还具备另外一种线程切换方式:时钟中断(可屏蔽)。接下来论证一下。
windbg输入命令 !idt 查看idt表中对应的函数,其中有一项名为hal!HalpHpetClockInterrupt
。
该函数属于hal模块,但Windows系统对于不同的处理器提供了不同的hal模块。在Windbg中输入命令lm
查看当前Windows使用的hal模块全名称。我这里的是halmacpi.dll
定位至HalpHpetClockInterrupt函数,简单看一下函数的调用结构,可以发现函数内部共调用了HalBeginSystemInterrupt@12、HalpHpetClockInterruptWork@0、KeUpdateSystemTime@0三个函数。
进入前两个函数发现没什么实际功能,最后一个函数用于调用ntoskrnl模块的KeUpdateSystemTime函数。
定位至ntoskrnl模块的KeUpdateSystemTime函数,发现这个函数非常长。慢慢往下翻,该函数会调用KeUpdateRunTime函数。
KeUpdateRunTime函数内部会调用hal模块的HalRequestSoftwareInterrupt函数。该函数会触发软件中断。
HalRequestSoftwareInterrupt内部调用KfLowerIrql函数。
KfLowerIrql函数调用HalpCheckForSoftwareInterrupt函数。该函数用于检查软件中断。
HalpCheckForSoftwareInterrupt函数内部会调用HalpDispatchSoftwareInterrupt来派发软件中断。
再调用ntoskrnl的KiDispatchInterrupt函数来执行派发。
而在KiDispatchInterrupt函数中会调用KiQueueReadyThread与SwapContext函数,因此会导致线程切换。
总结
上文论证了时钟中断会导致线程切换,整体执行流程为:
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的效果,从而绕过一些防护检测。
赞赏
|
|
---|---|
|
Win7系统不存在PG??? 你确定???
|
|
32位 ![]() |
|
请问你是看的滴水的教程吗?
|
|
滴水+火哥 |
|
大佬, 是滴水初级+火哥中级么 |
|
好啊好啊,海哥子弟
![]() |
![]() |