1、EPROCESS
进程结构,每个进程都有这样一个结构。EPROCESS中还有一个KPROCESS,其中EPROCESS被称为执行体
,主要是给R3进行访问;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 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; };
|
Pcb:Kprocess结构体。内核成员,见下文。
ProcessLock:R3进程锁。修改EPROCESS结构存放锁结构,防止同时修改。改完了置0.
CreateTime:进程的创建时间。
ExitTime:进程的退出时间。
RundownProtect:进程锁。该字段置值后,进程无法被访问、打开、结束,相当于保护。但是会容易卡死。

UniqueProcessId:进程ID。任务管理器中显示的进程ID就是这个。
ActiveProcessLinks:双向链表。包括了windows中所有活动的进程。全局变量“PsActiveProcessHead”指向了这个链表的头部。通过该全局变量可以遍历整条链表。

ProcessQuotaUsage:进程物理页相关统计信息。
ProcessQuotaPeak:进程物理页相关统计信息。
CommitCharge:进程虚拟内存相关统计信息。
QuotaBlock:进程虚拟内存相关统计信息。
CpuQuotaBlock:进程虚拟内存相关统计信息。
SessionProcessLinks:会话进程链表。保存了当前登录的用户的所有进程。
DebugPort:调试相关。如果该进程处于调试状态,这里会有值(一个结构体),该结构体用于进程与调试器之间通信。通过循环清0可以达到反调试效果。
ExceptionPortData:调试相关。
ObjectTable:进程的句柄表。句柄相关章节再学。
Token:进程Token,外边的提权实际上就是拷贝这个位置的Token。System/Administror
WorkingSetPage:表明当前进程用了多少个物理页。
ImageFileName:当前进程的进程名,但是只有15个字节,要获取完整的可以获取SeAuditProcessCreationInfo
。
ThreadListHead:当前进程内所有线程的链表。
ActiveThreads:当前进程内活动的线程数量。
Peb。就是3环下该进程的PEB。(PEB结构此处不赘述了,网上有非常多的PEB结构说明。)
SeAuditProcessCreationInfo:当前进程完整路径。函数SeLocateProcessImageName
就是获取的这个位置。
Flags2:一个联合体,每个位影响该进程的一些属性。
- ProtectedProcess:进程保护位。该位置1后该进程被保护。CE看不到图片,打不开了进程。OD附加进程列表遍历不到。一个最简单的进程保护。

+Flags:一个联合体,每个位影响该进程的一些属性。
ProcessExiting:进程退出标志位。置1后表明该进程已退出,但实际还在运行。可以达到反调试的效果。同时进程无法使用任务管理器结束。
ProcessDelete:进程退出标志位。置1后表明该进程已退出,但实际还在运行。可以达到反调试的效果。同时进程无法使用任务管理器结束。

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

VmTopDown:该位置1时,VirtualAlloc一类的申请内存函数将会从大地址开始申请。
ProcessInserted:该位置0后,OD附加进程列表找不到该进程。任务管理器结束不掉该进程。CE打不开该进程,无图标。
ExitStatus:进程退出状态码。进程创建时默认值是250(0x103)。如果不是这个值基本上就是进程退出了。
VadRoot:标识当前进程用户空间(低2G)中哪些地址没被分配。该成员指向了一个二叉树。
2.1 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; };
|
Header:可等待对象头部。所有0环结构体只要以_DISPATCHER_HEADER结构开头的,都可以使用WaitForSingleObject等待。如互斥体、事件。
ProfileListHead:性能分析相关,任务管理器,性能栏那些数据。
DirectoryTableBase:页目录表基址。物理地址,指向页目录表,CR3中的值就从这里获取。
LdtDescriptor:进程LDT描述符。
Int21Descriptor:为了兼容DOS下可通过Int21调用系统功能。
ThreadListHead:当前进程的所有线程结构体链表。这个位置- KTHREAD->ThreadListHead == KTHREAD
ProcessLock:进程锁,作用和EPROCESS中的一样,但这个是RO用的。
Affinity:亲核性。规定了当前进程内的所有线程可以在哪些CPU上跑,4字节,共32位,每一位对应一个CPU核。如000000A1,转换为二进制为1010 0001,则该进程中的线程只能在0、5、7号CPU上运行。因此32位系统最多支持32核CPU,64位系统支持64核CPU。该值仅为线程结构中的亲核性做初始化赋值使用,没有实际的限制功能。
如果只有1个CPU,但此处值为2(0010),则该进程为一个“死”了的进程。
ReadyListHead:当前进程内的就绪线程链表,保存的值指向了ETHREAD->WaitListEntry
地址。当进程被换出内存以后,所属的线程一旦就绪就会加入到这个链表中,然后换入进程,并将就绪线程链表全部加入全局的就绪线程链表。
SwapListEntry:当进程被换出内存时会通过这个位置将进程加入到KiProcessOutSwapListHead
,换入时加入到KiProcessInSwapListHead
。
ActiveProcessors:当前进程内正在运行的线程运行在哪些CPU上。
AutoAlignment:强制内存对齐。一般为0。
DisableBoost:置1为关闭当前进程内所有线程的时间碎片。(置1后,不会由于时间中断触发线程切换)
BasePriority:基础优先级。该进程内所有线程最初的优先级。
QuantumReset:当前进程内线程的初始时间碎片。每一次时钟中断会将线程中的时间碎片减6,为0时,切换线程。线程从就绪变为运行时,会从这个值中取到初始的时间碎片。改大这个值会让该进程内的线程跑的更久。
ProcessListEntry:系统内所有进程的链表。win7及以上此处为空,已弃用。
Flags:进程NX位的局部开关。结构为_KEXECUTE_OPTIONS的联合体
1 2 3 4 5 6 7 8 9 10 11 12 13
| union _KEXECUTE_OPTIONS { UCHAR ExecuteDisable:1; UCHAR ExecuteEnable:1; UCHAR DisableThunkEmulation:1; UCHAR Permanent:1; UCHAR ExecuteDispatchEnable:1; UCHAR ImageDispatchEnable:1; UCHAR DisableExceptionChainValidation:1; UCHAR Spare:1; volatile UCHAR ExecuteOptions; };
|
- ExecuteOptions:写1,数据段可以当做代码执行。写0数据段不能当做代码执行。
某些检测弱的游戏可以通过对这个置1,然后申请一段可读可写内存作为shellcode执行
。
CycleTime:当前进程执行了多少个指令周期。当进程结束时才会被赋值,指明了该进程存活了多久。
KernelTime:(统计信息)当前进程在0环的运行时间。当进程结束时才会被赋值,指明了该进程存活了多久。
UserTime:(统计信息)当前进程在3环的运行时间。当进程结束时才会被赋值,指明了该进程存活了多久。
VdmTrapcHandler:虚拟8086模式时使用。
2、ETHREAD
与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
| 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; };
|
- Tcb:KTHREAD成员,见下文。
- StartAddress:线程函数起始地址。
- Cid:当前线程的线程ID。为_CLIENT_ID结构,包含了线程ID和所属的进程ID。
- Win32StartAddress:GUI线程函数起始地址。如果一个线程属于GUI线程则这个位置为真实的线程起始地址,否则为null。
- ThreadListEntry:当前进程内所有线程的双向链表。
- RundownProtect:与EPROCESS效果一致。
- ThreadLock:与EPROCESS效果一致。
2.1 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; };
|
- Header:可等待对象头部。
- InitialStack:线程切换相关。当前线程的栈底。栈底-29C是TrapFrame结构首地址。
- StackLimit:线程切换相关。当前线程的最大栈顶。ESP不能小于这个值。
- KernelStack:线程切换相关。线程切换时,存储当前线程切换时的ESP,被切换回来时,从这里恢复ESP。
- ThreadLock:跟上边的一致
- Running:线程状态,正在运行中为1,否则为0。
- Alerted:可警惕性。APC相关,后续APC章节学习。
- MiscFlags:
- KernelStackResident:堆栈可扩展位。为1时,线程内核堆栈可以被扩大。0时无法扩大。
- SystemThread:为1时,该线程为内核线程,否则为用户线程。
- ApcState:APC相关,后续APC章节学习。
- Priority:当前线程的优先级。如存储11,则优先级为11,当前线程存储在第11个就绪链表中。
优先级数字越大,优先级越低
。默认线程优先级为8,存储在第8个就绪链表中。
- NextProcessor:线程下次运行在哪个核上,如果为0,则随机。
- ApcQueueLock:APC相关,后续APC章节学习。
- ContextSwitches:当前线程切换了多少次。
- State:线程状态。就绪、等待、运行等。
- Teb:3环的TEB。
- EnableStackSwap:内核栈是否可以换出内存。
- ServiceTable:系统服务表地址,系统调用章节已学过。
- WaitBlock:当前线程正在等待的对象,由KPROCESS->ReadyThreadList指向。
- TrapFrame:TrapFrame结构,进0环时保存3环寄存器的值,系统调用章节已学过。
- BasePriority:线程基础优先级。这个值就是所属进程的BasePriority值。
- PreviousMode:先前模式。一些内核函数会判断这个值。
- FreezeCount:被挂起的次数。如果一直为0则无法被恢复。
- Process:该线程的父进程(创建该线程的进程)。
- ApcStatePointer:APC相关,后续APC章节学习。
- SavedApcState:APC相关,后续APC章节学习。
- Win32Thread:win32线程,如果该线程是UI图形线程,就会多一个win32线程结构体。
- ThreadListEntry:当前进程所有线程的双向链表。这个位置- KPROCESS->ThreadListEntry == KPROCESS
2.2 线程伪装
使用pchunter
随便查看一个进程的线程。

然后使用Windbg查看对应的ETHREAD
结构体。

由于该进程具有GUI,因此Win32StartAddress
不为null。然后将这个位置的值修改位其他线程的入口。


回到虚拟机重新查看线程所属的模块。

可以看到已经被伪装。
2.3 杀死进程
杀死进程实际上等同于杀死线程,如果一个进程里没有任何线程在执行则进程等于结束。而线程只能自己杀死自己
,原理是利用APC插入一个函数到线程中,这个函数的作用就是杀死自己,然后当线程调度后会执行这个函数就把自己杀死了。
杀死进程有三种方法:
- 调用API杀死
- 清空进程中所有的线程链表。(API本质上就是这样)
- 暴力抹除进程内存。(把进程代码直接抹除或者设置为不可执行,程序就会保存退出)
2.3.1 NtTerminateProcess逆向
首先会判断EPROCESS.RundownProtect位,如果为1则不允许结束。这个位在上边有介绍。

然后就是结束所有的线程。

PspTerminateAllThreads
中实际上就是遍历线程后调用PspTerminateThreadByPointer
结束,进入PspTerminateThreadByPointer
。

这里需要补充的是,由于EPROCESS、KPROCESS、ETHREAD、KTHREAD都有一个ThreadListEntry。他们之间的关系如下
EPROCESS->ThreadListEntry指向的位置是ETHREAD->ThreadListEntry
KPROCESS->ThreadListEntry指向的位置是KTHREAD->ThreadListEntry
因此如果要遍历线程需要上边对应的关系去减掉对应ThreadListEntry在*THREAD中的偏移(*表示K或者E),才能拿到线程头
3、KPCR
FS段,R0下叫做KPCR(内核进程控制区),R3下叫做PEB(进程环境块)。每一个核独有一个,这个结构记录了这个核的CPU信息。内核变量KeNumberProcessors
用于记录当前机器有多少个核。

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; };
|
NtTib:
- Used_ExceptionList:异常处理程序链表。
- Used_StackBase:当前线程的栈底。
- Spare2/StackLimit:当前线程的堆栈大小。
- Used_Self:指向NtTib自身,也是KPCR自身(fs:[0x18])。
TssCopy:0x40处TSS的初始值。
SelfPcr:指向KPCR自身。与UsedSelf不同,SelfPcr必然指向KPCR自身,UsedSelf有时候会指向TEB。
Prcb:KPRCB结构指针,实际上指向的是0x120的PrcbData。
KdVersionBlock:只有第一个核有值,其他核为0;


并且这个位置的值大有用处!!!!这个KdVersionBlock对应的结构为_DBGKD_GET_VERSION64
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| struct _DBGKD_GET_VERSION64 { USHORT MajorVersion; USHORT MinorVersion; UCHAR ProtocolVersion; UCHAR KdSecondaryVersion; USHORT Flags; USHORT MachineType; UCHAR MaxPacketType; UCHAR MaxStateChange; UCHAR MaxManipulate; UCHAR Simulation; USHORT Unused[1]; ULONGLONG KernBase; ULONGLONG PsLoadedModuleList; ULONGLONG DebuggerDataList; };
|

- KernBase:ntoskrnl.exe的基地址
- PsLoadedModuleList:模块链表。
- DebuggerDataList:最牛逼的东西,里边存着很多公开/未公开的内容。使用
dds
查看。

可以看到里边有很多东西,比如句柄表PspCidTable
,对于他的这个结构在WRK有给出部分(由于系统一直在更新,所以内容也一直在添加)。_KDDEBUGGER_DATA64


IDT:当前线程的IDT表地址。
GDT:当前线程的GDT表地址。
TSS:指向当前线程的TSS表。
SetNumber:当前CPU编号。从1开始。
Number:当前CPU编号。从0开始。
PrcbData:KPRCB结构,扩展结构,见后文。
3.1 KPRCB
内核进程控制区域块。内核变量KiProcessorBlock
中保存了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; };
|
- CurrentThread:当前CPU正在跑的线程。
- NextThread:将要切换的线程。
- IdleThread:如果没有要切换的线程,CPU将要跑的空闲线程。
- DispatcherReadyListHead:线程就绪位,共32位,哪一位为1说明哪一个核上有线程在跑。
3.2 代码获取KiProcessorBlock
由于KiProcessorBlock
是未公开的变量,因此不能直接使用。但是可以通过上边的KdVersionBlock
进行获取。由于只有0核下这个成员才有值,因此需要将当前的运行线程切换到0核,可以通过函数KeSetSystemAffinityThread
指定当前线程到0核执行。
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
| #include <ntifs.h> #include <intrin.h>
typedef struct _DBGKD_GET_VERSION64 { USHORT MajorVersion; USHORT MinorVersion; UCHAR ProtocolVersion; UCHAR KdSecondaryVersion; USHORT Flags; USHORT MachineType; UCHAR MaxPacketType; UCHAR MaxStateChange; UCHAR MaxManipulate; UCHAR Simulation; USHORT Unused[1]; ULONGLONG KernBase; ULONGLONG PsLoadedModuleList; ULONGLONG DebuggerDataList; }DBGKD_GET_VERSION64, *PDBGKD_GET_VERSION64;
VOID unloaddrv(PDRIVER_OBJECT pDrv) {
}
NTSTATUS DriverEntry(PDRIVER_OBJECT pDrv,PUNICODE_STRING pReg) { pDrv->DriverUnload = unloaddrv;
KeSetSystemAffinityThread(0); PKPCR kpcr = (PKPCR)__readfsdword(0x1C); PDBGKD_GET_VERSION64 pdbgVer = (PDBGKD_GET_VERSION64)kpcr->KdVersionBlock; ULONG_PTR DbgDataList = *(PULONG_PTR)(pdbgVer->DebuggerDataList); DbgPrint("DbgDataList=%p\n", DbgDataList); ULONG_PTR KiProcessorBlock = *(PULONG_PTR)(DbgDataList + 0x218); DbgPrint("KiProcessorBlock=%p\n", KiProcessorBlock); KeRevertToUserAffinityThread(); return STATUS_SUCCESS; }
|

每一个对象都有一个对象头,然后接着才是对象类型的结构内容。

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| struct _OBJECT_HEADER { LONG PointerCount; union { LONG HandleCount; VOID* NextToFree; }; struct _EX_PUSH_LOCK Lock; UCHAR TypeIndex; UCHAR TraceFlags; UCHAR InfoMask; UCHAR Flags; union { struct _OBJECT_CREATE_INFORMATION* ObjectCreateInfo; VOID* QuotaBlockCharged; }; VOID* SecurityDescriptor; struct _QUAD Body; };
|
- PointerCount:对应的内核对象被使用了多少次。如调用ObXXXX函数都会将该值+1。该值为0时,对应的内核对象就会被释放。
- HandleCount:句柄引用。
- TypeIndex:对应的内核对象的类型。
- Flags:详细作用未知。当此处的值被置为4时(对应的对象为进程对象时),对应的进程被保护,无法打开、附加。且不影响进程功能。仅对3环起作用。
- Body:接着实际对象类型的结构数据,比如EPROCESS,ETHREAD等等。因此一个对象
-0x18
可以得到对象头的首地址。
5、Window查询就绪线程函数
KPRCB中ReadySummary成员(0x31EC)为就绪位图,4字节32位。每一位对应一条就绪链表。某一位为1则说明对应的就绪链表中有等待执行的线程。32条就绪链表存储在KPRCB中DispatcherReadyListHead成员。如:ReadySummary值为5,二进制0101,说明第0号、第3号就绪链表中存在待执行线程。在线程切换时就会从这两个链表中取待切换的线程。
Windows中KiFindReadyThread
用来查询就绪函数。

通过对函数的交叉引用可知前一个参数为ReadySummary后两个都为KPRCB指针。

bsr从低->高扫描源操作数第一个为1的位置,下标保存到目的操作数。
bx = 0x10 -> 0001 0000
bsr ax,bx -> ax = 4
- 没有就绪线程时,CPU会运行一个系统事先准备好的空线程。(Ide)
- 线程亲核性决定了线程可以跑在哪个核上。如果恶意修改某个线程结构的亲核性为不存在的核,等同于杀死线程。
6、Windows交换线程函数
Windows中有两种线程切换方式,一种是主动切换(WaitForSingleObject、Sleep),另一种是被动切换(CPU时钟)。
线程状态(来自WKR):
1 2 3 4 5 6 7 8 9 10 11
| ypedef enum _KTHREAD_STATE { Initialized, Ready, Running, Standby, Terminated, Waiting, Transition, DeferredReady, GateWait } KTHREAD_STATE;
|
6.1 主动切换
1
| WaitForSingleObject->NtWaitForSingleObject->KiCommitThreadWait->KiSwapThread
|
1
| Sleep->SleepEx->RtlDelayExecution->NtDelayExecution->KiCommitThreadWait->KiSwapThread
|
6.1.1 KiSwapThread逆向



KiSwapThread
只是做了查询就绪函数,实际上线程交换是在KiSwapContext
中
6.1.2 KiSearchForNewThread逆向



KiSearchForNewThread
函数主要是对KiSwapThread
调用时出入的KPRCB参数进行查找就绪函数,如果当前核找不到则切换到其他核找。
6.1.3 SwapContext逆向

首先将新线程的状态设置为就绪,然后获取新线程的堆栈作为SwapContext_PatchXSave
参数调用。

接着是判断新旧线程是否来自同一个进程。如果是同一个进程则进行切换环境。

如果不是同一个进程则会切换CR3操作之类的。

1、用户层绝大部分API的调用都会导致线程的切换
2、本质上没有进程切换,只是在线程切换时如果不是同一进程则会顺带CR3进行处理。
6.2 被动切换
被动切换实际上是CPU时钟切换,windbg使用!idt
中断表,其中有一项名为hal!HalpHpetClockInterrupt
。

可以看到属于hal模块,因为CPU操作属于硬件操作。hal负责与硬件进行操作。Windows系统对于不同的处理器提供了不同的hal模块。在Windbg中输入命令lm
查看当前Windows使用的hal模块全名称。

ida打开后跳转到HalpHpetClockInterrupt
.

简单分析后实际上有用的也就KeUpdateSystemTime
函数,进入查看。

发现来自导入表。

回到ntotkrnl查看该函数。

函数很长,实际上有用的是最后的返回函数。

继续回到hal查看HalRequestSoftwareInterrupt

进入KfLowerIrql
.

进入HalpCheckForSoftwareInterrupt
.

进入HalpDispatchSoftwareInterrupt

回到ntoskrnl进入KiDispatchInterrupt
.

CPU时钟的调用流程如下:
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
|
只是简单跟了一下~~~~。
另外,当软件发生异常的时候(实际上就是中断),就会进行线程切换。因此,在Windows操作系统中,调用绝大部分API 以及 触发各种异常 均会导致线程的切换。如果想让自己的线程永远占有CPU,则不可以调用API、不能触发异常(内存访问也可能触发缺页异常,在用户层是看不出来的)。