1.进程结构体(EPROCESS)
实际上进程和线程在操作系统中就是一个结构体,当操作系统需要创建一个进程或者线程的时候本质就是申请一块内存,填充结构体。每个windows进程在0环都有一个对应的结构体。这个结构体叫做EPROCESS
。这个结构体的结构如下:
kd> dt _EPROCESS ntdll!_EPROCESS +0x000 Pcb : _KPROCESS //这也是一个结构体,具体解释见# 1.1节 +0x06c ProcessLock : _EX_PUSH_LOCK +0x070 CreateTime : _LARGE_INTEGER //进程创建时间 +0x078 ExitTime : _LARGE_INTEGER //进程退出时间 +0x080 RundownProtect : _EX_RUNDOWN_REF +0x084 UniqueProcessId : Ptr32 Void //任务管理器中显示的进程ID号 +0x088 ActiveProcessLinks : _LIST_ENTRY //活动进程链表。这是一个双向链表,操作系统中所有活动进程都在这个双向链表中。内核中有一个PsActiveProcessHead全局变量,该变量指向了这个双向链表的头。这个成员和隐藏进程有关。 +0x090 QuotaUsage : [3] Uint4B //物理页的相关统计信息 +0x09c QuotaPeak : [3] Uint4B //物理页的相关统计信息 +0x0a8 CommitCharge : Uint4B //虚拟内存相关的统计信息 +0x0ac PeakVirtualSize : Uint4B //虚拟内存相关的统计信息 +0x0b0 VirtualSize : Uint4B //虚拟内存相关的统计信息 +0x0b4 SessionProcessLinks : _LIST_ENTRY +0x0bc DebugPort : Ptr32 Void //调试相关的 +0x0c0 ExceptionPort : Ptr32 Void //调试相关的 +0x0c4 ObjectTable : Ptr32 _HANDLE_TABLE //句柄表,存储了该进程还使用了哪些其他的内核对象 +0x0c8 Token : _EX_FAST_REF +0x0cc WorkingSetLock : _FAST_MUTEX +0x0ec WorkingSetPage : Uint4B +0x0f0 AddressCreationLock : _FAST_MUTEX +0x110 HyperSpaceLock : Uint4B +0x114 ForkInProgress : Ptr32 _ETHREAD +0x118 HardwareTrigger : Uint4B +0x11c VadRoot : Ptr32 Void //这个成员指向了一个平衡二叉树,标识用户空间的2G内存中哪些地址被使用了。跟模块隐藏有关! +0x120 VadHint : Ptr32 Void +0x124 CloneRoot : Ptr32 Void +0x128 NumberOfPrivatePages : Uint4B +0x12c NumberOfLockedPages : Uint4B +0x130 Win32Process : Ptr32 Void +0x134 Job : Ptr32 _EJOB +0x138 SectionObject : Ptr32 Void +0x13c SectionBaseAddress : Ptr32 Void +0x140 QuotaBlock : Ptr32 _EPROCESS_QUOTA_BLOCK +0x144 WorkingSetWatch : Ptr32 _PAGEFAULT_HISTORY +0x148 Win32WindowStation : Ptr32 Void +0x14c InheritedFromUniqueProcessId : Ptr32 Void +0x150 LdtInformation : Ptr32 Void +0x154 VadFreeHint : Ptr32 Void +0x158 VdmObjects : Ptr32 Void +0x15c DeviceMap : Ptr32 Void +0x160 PhysicalVadList : _LIST_ENTRY +0x168 PageDirectoryPte : _HARDWARE_PTE_X86 +0x168 Filler : Uint8B +0x170 Session : Ptr32 Void +0x174 ImageFileName : [16] UChar //当前进程的镜像名字 +0x184 JobLinks : _LIST_ENTRY +0x18c LockedPagesList : Ptr32 Void +0x190 ThreadListHead : _LIST_ENTRY +0x198 SecurityPort : Ptr32 Void +0x19c PaeTop : Ptr32 Void +0x1a0 ActiveThreads : Uint4B //活动线程的数量 +0x1a4 GrantedAccess : Uint4B +0x1a8 DefaultHardErrorProcessing : Uint4B +0x1ac LastThreadExitStatus : Int4B +0x1b0 Peb : Ptr32 _PEB //这是一个在三环中保存了进程信息的一个结构体,具体见# 1.3中 +0x1b4 PrefetchTrace : _EX_FAST_REF +0x1b8 ReadOperationCount : _LARGE_INTEGER +0x1c0 WriteOperationCount : _LARGE_INTEGER +0x1c8 OtherOperationCount : _LARGE_INTEGER +0x1d0 ReadTransferCount : _LARGE_INTEGER +0x1d8 WriteTransferCount : _LARGE_INTEGER +0x1e0 OtherTransferCount : _LARGE_INTEGER +0x1e8 CommitChargeLimit : Uint4B +0x1ec CommitChargePeak : Uint4B +0x1f0 AweInfo : Ptr32 Void +0x1f4 SeAuditProcessCreationInfo : _SE_AUDIT_PROCESS_CREATION_INFO +0x1f8 Vm : _MMSUPPORT +0x238 LastFaultCount : Uint4B +0x23c ModifiedPageCount : Uint4B +0x240 NumberOfVads : Uint4B +0x244 JobStatus : Uint4B +0x248 Flags : Uint4B +0x248 CreateReported : Pos 0, 1 Bit +0x248 NoDebugInherit : Pos 1, 1 Bit +0x248 ProcessExiting : Pos 2, 1 Bit +0x248 ProcessDelete : Pos 3, 1 Bit +0x248 Wow64SplitPages : Pos 4, 1 Bit +0x248 VmDeleted : Pos 5, 1 Bit +0x248 OutswapEnabled : Pos 6, 1 Bit +0x248 Outswapped : Pos 7, 1 Bit +0x248 ForkFailed : Pos 8, 1 Bit +0x248 HasPhysicalVad : Pos 9, 1 Bit +0x248 AddressSpaceInitialized : Pos 10, 2 Bits +0x248 SetTimerResolution : Pos 12, 1 Bit +0x248 BreakOnTermination : Pos 13, 1 Bit +0x248 SessionCreationUnderway : Pos 14, 1 Bit +0x248 WriteWatch : Pos 15, 1 Bit +0x248 ProcessInSession : Pos 16, 1 Bit +0x248 OverrideAddressSpace : Pos 17, 1 Bit +0x248 HasAddressSpace : Pos 18, 1 Bit +0x248 LaunchPrefetched : Pos 19, 1 Bit +0x248 InjectInpageErrors : Pos 20, 1 Bit +0x248 VmTopDown : Pos 21, 1 Bit +0x248 Unused3 : Pos 22, 1 Bit +0x248 Unused4 : Pos 23, 1 Bit +0x248 VdmAllowed : Pos 24, 1 Bit +0x248 Unused : Pos 25, 5 Bits +0x248 Unused1 : Pos 30, 1 Bit +0x248 Unused2 : Pos 31, 1 Bit +0x24c ExitStatus : Int4B +0x250 NextPageColor : Uint2B +0x252 SubSystemMinorVersion : UChar +0x253 SubSystemMajorVersion : UChar +0x252 SubSystemVersion : Uint2B +0x254 PriorityClass : UChar +0x255 WorkingSetAcquiredUnsafe : UChar +0x258 Cookie : Uint4B
1.1 _KPROCESS结构体
_KPROCESS
结构体的结构如下:
kd> dt _KPROCESS ntdll!_KPROCESS +0x000 Header : _DISPATCHER_HEADER //以_DISPATCHER_HEADER对象开头的程序是一个可等待对象 +0x010 ProfileListHead : _LIST_ENTRY +0x018 DirectoryTableBase : [2] Uint4B //这个成员名称叫页目录表基址,也就是运行时填写到CR3寄存器里的地址。 +0x020 LdtDescriptor : _KGDTENTRY +0x028 Int21Descriptor : _KIDTENTRY +0x030 IopmOffset : Uint2B +0x032 Iopl : UChar +0x033 Unused : UChar +0x034 ActiveProcessors : Uint4B +0x038 KernelTime : Uint4B //在0环运行的时间 +0x03c UserTime : Uint4B //在3环运行的时间 +0x040 ReadyListHead : _LIST_ENTRY +0x048 SwapListEntry : _SINGLE_LIST_ENTRY +0x04c VdmTrapcHandler : Ptr32 Void +0x050 ThreadListHead : _LIST_ENTRY +0x058 ProcessLock : Uint4B +0x05c Affinity : Uint4B //这个成员规定了进程里面所有线程能在哪个CPU上运行。32位每一位表示一个CPU,为1则可以在这个CPU上运行。 +0x060 StackCount : Uint2B +0x062 BasePriority : Char //基础优先级,该进程中创建所有线程最起码的优先级都是这个值 +0x063 ThreadQuantum : Char +0x064 AutoAlignment : UChar +0x065 State : UChar +0x066 ThreadSeed : UChar +0x067 DisableBoost : UChar +0x068 PowerState : UChar +0x069 DisableQuantum : UChar +0x06a IdealNode : UChar +0x06b Flags : _KEXECUTE_OPTIONS +0x06b ExecuteOptions : UChar
1.2 EPROCESS的ActiveProcessLinks
元素
活动进程链表。这是一个双向链表,操作系统中所有活动进程都在这个双向链表中。内核中有一个PsActiveProcessHead全局变量,该变量指向了这个双向链表的头。 我们可以使用如下方式查看这个列表
kd> dd PsActiveProcessHead #找到链表头 8055b158 817bd8b8 8120e830 00000001 f04e6a6c 8055b168 00000000 00040001 00000000 8055b174 8055b178 8055b174 00000000 7c920000 00000000 8055b188 00000000 00000000 00000000 00000000 8055b198 8052894c 00000000 00000000 00000000 8055b1a8 813efb68 813efb68 00000000 00000000 8055b1b8 00000000 00000000 00000001 f9df7d50 8055b1c8 00000000 00040001 00000000 8055b1d4 kd> dt _EPROCESS 817bd8b8-0x88 #查看链表头的第一个_EPROCESS结构体 ntdll!_EPROCESS +0x000 Pcb : _KPROCESS +0x06c ProcessLock : _EX_PUSH_LOCK +0x070 CreateTime : _LARGE_INTEGER 0x0 +0x078 ExitTime : _LARGE_INTEGER 0x0 +0x080 RundownProtect : _EX_RUNDOWN_REF +0x084 UniqueProcessId : 0x00000004 Void +0x088 ActiveProcessLinks : _LIST_ENTRY [ 0x81472d30 - 0x8055b158 ] ......略
1.3 EPROCESS的PEB
元素
PEB是一个在三环保存进程信息的结构体,结构体如下:
kd> dt _PEB ntdll!_PEB +0x000 InheritedAddressSpace : UChar +0x001 ReadImageFileExecOptions : UChar +0x002 BeingDebugged : UChar //通过检查这个参数也可达到一定程度的反调试,这个值如果是1表示当前进程在被调试。 +0x003 SpareBool : UChar +0x004 Mutant : Ptr32 Void +0x008 ImageBaseAddress : Ptr32 Void +0x00c Ldr : Ptr32 _PEB_LDR_DATA //这是一个结构体,这个结构体中的双向链表记录了当前进程中有多少个模块。 +0x010 ProcessParameters : Ptr32 _RTL_USER_PROCESS_PARAMETERS +0x014 SubSystemData : Ptr32 Void +0x018 ProcessHeap : Ptr32 Void +0x01c FastPebLock : Ptr32 _RTL_CRITICAL_SECTION +0x020 FastPebLockRoutine : Ptr32 Void +0x024 FastPebUnlockRoutine : Ptr32 Void +0x028 EnvironmentUpdateCount : Uint4B +0x02c KernelCallbackTable : Ptr32 Void +0x030 SystemReserved : [1] Uint4B +0x034 AtlThunkSListPtr32 : Uint4B +0x038 FreeList : Ptr32 _PEB_FREE_BLOCK +0x03c TlsExpansionCounter : Uint4B +0x040 TlsBitmap : Ptr32 Void +0x044 TlsBitmapBits : [2] Uint4B +0x04c ReadOnlySharedMemoryBase : Ptr32 Void +0x050 ReadOnlySharedMemoryHeap : Ptr32 Void +0x054 ReadOnlyStaticServerData : Ptr32 Ptr32 Void +0x058 AnsiCodePageData : Ptr32 Void +0x05c OemCodePageData : Ptr32 Void +0x060 UnicodeCaseTableData : Ptr32 Void +0x064 NumberOfProcessors : Uint4B +0x068 NtGlobalFlag : Uint4B +0x070 CriticalSectionTimeout : _LARGE_INTEGER +0x078 HeapSegmentReserve : Uint4B +0x07c HeapSegmentCommit : Uint4B +0x080 HeapDeCommitTotalFreeThreshold : Uint4B +0x084 HeapDeCommitFreeBlockThreshold : Uint4B +0x088 NumberOfHeaps : Uint4B +0x08c MaximumNumberOfHeaps : Uint4B +0x090 ProcessHeaps : Ptr32 Ptr32 Void +0x094 GdiSharedHandleTable : Ptr32 Void +0x098 ProcessStarterHelper : Ptr32 Void +0x09c GdiDCAttributeList : Uint4B +0x0a0 LoaderLock : Ptr32 Void +0x0a4 OSMajorVersion : Uint4B +0x0a8 OSMinorVersion : Uint4B +0x0ac OSBuildNumber : Uint2B +0x0ae OSCSDVersion : Uint2B +0x0b0 OSPlatformId : Uint4B +0x0b4 ImageSubsystem : Uint4B +0x0b8 ImageSubsystemMajorVersion : Uint4B +0x0bc ImageSubsystemMinorVersion : Uint4B +0x0c0 ImageProcessAffinityMask : Uint4B +0x0c4 GdiHandleBuffer : [34] Uint4B +0x14c PostProcessInitRoutine : Ptr32 void +0x150 TlsExpansionBitmap : Ptr32 Void +0x154 TlsExpansionBitmapBits : [32] Uint4B +0x1d4 SessionId : Uint4B +0x1d8 AppCompatFlags : _ULARGE_INTEGER +0x1e0 AppCompatFlagsUser : _ULARGE_INTEGER +0x1e8 pShimData : Ptr32 Void +0x1ec AppCompatInfo : Ptr32 Void +0x1f0 CSDVersion : _UNICODE_STRING +0x1f8 ActivationContextData : Ptr32 Void +0x1fc ProcessAssemblyStorageMap : Ptr32 Void +0x200 SystemDefaultActivationContextData : Ptr32 Void +0x204 SystemAssemblyStorageMap : Ptr32 Void +0x208 MinimumStackCommit : Uint4B
2.线程结构体(ETHREAD)
每一个线程都会有一个ETHREAD
结构体保存在零环,有多少个线程就有多少个这样的结构体。获取当前线程的ETHREAD可以使用PsGetCurrentThread 函数,其实0环时,fs:[00000124h] 这里存放的是当前线程的ETHREAD,有ETHREAD
,偏移0x220就是EPROCESS
。了。线程结构体的结构体如下:
kd> dt _ETHREAD ntdll!_ETHREAD +0x000 Tcb : _KTHREAD //这是一个结构体,具体内容见2.1节 +0x1c0 CreateTime : _LARGE_INTEGER +0x1c0 NestedFaultCount : Pos 0, 2 Bits +0x1c0 ApcNeeded : Pos 2, 1 Bit +0x1c8 ExitTime : _LARGE_INTEGER +0x1c8 LpcReplyChain : _LIST_ENTRY +0x1c8 KeyedWaitChain : _LIST_ENTRY +0x1d0 ExitStatus : Int4B +0x1d0 OfsChain : Ptr32 Void +0x1d4 PostBlockList : _LIST_ENTRY +0x1dc TerminationPort : Ptr32 _TERMINATION_PORT +0x1dc ReaperLink : Ptr32 _ETHREAD +0x1dc KeyedWaitValue : Ptr32 Void +0x1e0 ActiveTimerListLock : Uint4B +0x1e4 ActiveTimerListHead : _LIST_ENTRY +0x1ec Cid : _CLIENT_ID //当前进程的编号和当前线程的编号 +0x1f4 LpcReplySemaphore : _KSEMAPHORE +0x1f4 KeyedWaitSemaphore : _KSEMAPHORE +0x208 LpcReplyMessage : Ptr32 Void +0x208 LpcWaitingOnPort : Ptr32 Void +0x20c ImpersonationInfo : Ptr32 _PS_IMPERSONATION_INFORMATION +0x210 IrpList : _LIST_ENTRY +0x218 TopLevelIrp : Uint4B +0x21c DeviceToVerify : Ptr32 _DEVICE_OBJECT +0x220 ThreadsProcess : Ptr32 _EPROCESS //指向当前线程所属进程 +0x224 StartAddress : Ptr32 Void +0x228 Win32StartAddress : Ptr32 Void +0x228 LpcReceivedMessageId : Uint4B +0x22c ThreadListEntry : _LIST_ENTRY //双向链表,该线程所属进程的所有线程都在这个双向链表中。 +0x234 RundownProtect : _EX_RUNDOWN_REF +0x238 ThreadLock : _EX_PUSH_LOCK +0x23c LpcReplyMessageId : Uint4B +0x240 ReadClusterSize : Uint4B +0x244 GrantedAccess : Uint4B +0x248 CrossThreadFlags : Uint4B +0x248 Terminated : Pos 0, 1 Bit +0x248 DeadThread : Pos 1, 1 Bit +0x248 HideFromDebugger : Pos 2, 1 Bit +0x248 ActiveImpersonationInfo : Pos 3, 1 Bit +0x248 SystemThread : Pos 4, 1 Bit +0x248 HardErrorsAreDisabled : Pos 5, 1 Bit +0x248 BreakOnTermination : Pos 6, 1 Bit +0x248 SkipCreationMsg : Pos 7, 1 Bit +0x248 SkipTerminationMsg : Pos 8, 1 Bit +0x24c SameThreadPassiveFlags : Uint4B +0x24c ActiveExWorker : Pos 0, 1 Bit +0x24c ExWorkerCanWaitUser : Pos 1, 1 Bit +0x24c MemoryMaker : Pos 2, 1 Bit +0x250 SameThreadApcFlags : Uint4B +0x250 LpcReceivedMsgIdValid : Pos 0, 1 Bit +0x250 LpcExitThreadCalled : Pos 1, 1 Bit +0x250 AddressSpaceOwner : Pos 2, 1 Bit +0x254 ForwardClusterOnly : UChar +0x255 DisablePageFaultClustering : UChar
2.1 ETHREAD结构体中的KTHREAD
KTHREAD
结构体的结构如下:
ntdll!_KTHREAD +0x000 Header : _DISPATCHER_HEADER //以这个_DISPATCHER_HEADER开头的内核对象就是可等待对象 +0x010 MutantListHead : _LIST_ENTRY +0x018 InitialStack : Ptr32 Void //和线程切换有关,维护堆栈信息的。 +0x01c StackLimit : Ptr32 Void //和线程切换有关,维护堆栈信息的。 +0x020 Teb : Ptr32 Void //Thread Environment Block,线程环境块,大小为4KB,位于用户地址空间。在三环时,fs寄存器指向的就是TEB。 +0x024 TlsArray : Ptr32 Void +0x028 KernelStack : Ptr32 Void //和线程切换有关,维护堆栈信息的,这里面这个值就是ESP0。 +0x02c DebugActive : UChar //如果值为-1则不能使用dr0-dr7这几个调试寄存器。 +0x02d State : UChar //线程状态,是就绪还是等待还是运行 +0x02e Alerted : [2] UChar +0x030 Iopl : UChar +0x031 NpxState : UChar +0x032 Saturation : Char +0x033 Priority : Char +0x034 ApcState : _KAPC_STATE //APC相关的。 +0x04c ContextSwitches : Uint4B +0x050 IdleSwapBlock : UChar +0x051 Spare0 : [3] UChar +0x054 WaitStatus : Int4B +0x058 WaitIrql : UChar +0x059 WaitMode : Char +0x05a WaitNext : UChar +0x05b WaitReason : UChar +0x05c WaitBlockList : Ptr32 _KWAIT_BLOCK +0x060 WaitListEntry : _LIST_ENTRY +0x060 SwapListEntry : _SINGLE_LIST_ENTRY +0x068 WaitTime : Uint4B +0x06c BasePriority : Char //线程优先级,初始值就是KPROCESS->BasePriority的值。以后可以通过KeSetBasePriorityThread()函数来重新设定。 +0x06d DecrementCount : UChar +0x06e PriorityDecrement : Char +0x06f Quantum : Char +0x070 WaitBlock : [4] _KWAIT_BLOCK //存储的是等待(WaitForSingleObject)的哪个对象 +0x0d0 LegoData : Ptr32 Void +0x0d4 KernelApcDisable : Uint4B +0x0d8 UserAffinity : Uint4B +0x0dc SystemAffinityActive : UChar +0x0dd PowerState : UChar +0x0de NpxIrql : UChar +0x0df InitialNode : UChar +0x0e0 ServiceTable : Ptr32 Void //指向系统服务表基址 +0x0e4 Queue : Ptr32 _KQUEUE +0x0e8 ApcQueueLock : Uint4B //APC相关的。 +0x0f0 Timer : _KTIMER +0x118 QueueListEntry : _LIST_ENTRY +0x120 SoftAffinity : Uint4B +0x124 Affinity : Uint4B +0x128 Preempted : UChar +0x129 ProcessReadyQueue : UChar +0x12a KernelStackResident : UChar +0x12b NextProcessor : UChar +0x12c CallbackStack : Ptr32 Void +0x130 Win32Thread : Ptr32 Void +0x134 TrapFrame : Ptr32 _KTRAP_FRAME //指向进0环的时候三环寄存器的值 +0x138 ApcStatePointer : [2] Ptr32 _KAPC_STATE //APC相关的。 +0x140 PreviousMode : Char //先前模式,某些内核函数会根据这个的值来判断当前程序是三环调用还是0环调用的 +0x141 EnableStackSwap : UChar +0x142 LargeStack : UChar +0x143 ResourceIndex : UChar +0x144 KernelTime : Uint4B +0x148 UserTime : Uint4B +0x14c SavedApcState : _KAPC_STATE //APC相关的。 +0x164 Alertable : UChar +0x165 ApcStateIndex : UChar +0x166 ApcQueueable : UChar +0x167 AutoAlignment : UChar +0x168 StackBase : Ptr32 Void +0x16c SuspendApc : _KAPC +0x19c SuspendSemaphore : _KSEMAPHORE +0x1b0 ThreadListEntry : _LIST_ENTRY //双向链表,一个进程的所有线程都在这个双向链表里。 +0x1b8 FreezeCount : Char +0x1b9 SuspendCount : Char +0x1ba IdealProcessor : UChar +0x1bb DisableBoost : UChar
线程双向链表如下图所示:
3.KPCR(CPU控制区)
当线程从三环进入到0环的时候,FS:[0]指向KPCR(三环的时候FS:[0]指向TEB)。每一个CPU核都有一个KPCR。KPCR中存储了CPU本身的一些重要数据,例如:GDT表位置,IDT表,线程信息。KPCR结构体结构如下:
kd> dt _KPCR nt!_KPCR +0x000 NtTib : _NT_TIB //见3.1节 +0x01c SelfPcr : Ptr32 _KPCR //指向KPCR自己 +0x020 Prcb : Ptr32 _KPRCB //存的指针指向PrcbData,也就是0x120偏移的地方 +0x024 Irql : UChar +0x028 IRR : Uint4B +0x02c IrrActive : Uint4B +0x030 IDR : Uint4B +0x034 KdVersionBlock : Ptr32 Void +0x038 IDT : Ptr32 _KIDTENTRY //存储的IDT表的基址,每个CPU都有一套IDT表 +0x03c GDT : Ptr32 _KGDTENTRY //存储的GDT表的基址,每个CPU都有一套GDT表 +0x040 TSS : Ptr32 _KTSS //指针,指向TSS,每个CPU都有一套TSS +0x044 MajorVersion : Uint2B +0x046 MinorVersion : Uint2B +0x048 SetMember : Uint4B +0x04c StallScaleFactor : Uint4B +0x050 DebugActive : UChar +0x051 Number : UChar //当前CPU编号是多少,编号从0开始,0,1,2,.... +0x052 Spare0 : UChar +0x053 SecondLevelCacheAssociativity : UChar +0x054 VdmAlert : Uint4B +0x058 KernelReserved : [14] Uint4B +0x090 SecondLevelCacheSize : Uint4B +0x094 HalReserved : [16] Uint4B +0x0d4 InterruptMode : Uint4B +0x0d8 Spare1 : UChar +0x0dc KernelReserved2 : [17] Uint4B +0x120 PrcbData : _KPRCB //拓展结构体,存储了一些拓展信息,具体见3.2。
3.1 KPCR结构体的NtTib
NtTib结构体是KPCR的第一个成员,结构如下:
kd> dt _NT_TIB ntdll!_NT_TIB +0x000 ExceptionList : Ptr32 _EXCEPTION_REGISTRATION_RECORD //指向0环的异常处理程序链表 +0x004 StackBase : Ptr32 Void //当前线程的栈底 +0x008 StackLimit : Ptr32 Void //当前线程的栈的限制 +0x00c SubSystemTib : Ptr32 Void +0x010 FiberData : Ptr32 Void +0x010 Version : Uint4B +0x014 ArbitraryUserPointer : Ptr32 Void +0x018 Self : Ptr32 _NT_TIB //指向当前TIB自己的指针,主要是为了编程的时候方便
3.2 KPCR的PrcbData结构体
PrcbData是KPCR的最后一个结构体,叫做拓展结构体,其结构如下:
kd> dt _KPRCB ntdll!_KPRCB +0x000 MinorVersion : Uint2B +0x002 MajorVersion : Uint2B +0x004 CurrentThread : Ptr32 _KTHREAD //指向当前CPU线程 +0x008 NextThread : Ptr32 _KTHREAD //指向切换的时候要切换到下一个线程是谁 +0x00c IdleThread : Ptr32 _KTHREAD //指向如果没有要切换的线程,空闲线程是谁 +0x010 Number : Char +0x011 Reserved : Char +0x012 BuildType : Uint2B +0x014 SetMember : Uint4B +0x018 CpuType : Char +0x019 CpuID : Char +0x01a CpuStep : Uint2B +0x01c ProcessorState : _KPROCESSOR_STATE +0x33c KernelReserved : [16] Uint4B +0x37c HalReserved : [16] Uint4B +0x3bc PrcbPad0 : [92] UChar +0x418 LockQueue : [16] _KSPIN_LOCK_QUEUE +0x498 PrcbPad1 : [8] UChar +0x4a0 NpxThread : Ptr32 _KTHREAD +0x4a4 InterruptCount : Uint4B +0x4a8 KernelTime : Uint4B +0x4ac UserTime : Uint4B +0x4b0 DpcTime : Uint4B +0x4b4 DebugDpcTime : Uint4B +0x4b8 InterruptTime : Uint4B +0x4bc AdjustDpcThreshold : Uint4B +0x4c0 PageColor : Uint4B +0x4c4 SkipTick : Uint4B +0x4c8 MultiThreadSetBusy : UChar +0x4c9 Spare2 : [3] UChar +0x4cc ParentNode : Ptr32 _KNODE +0x4d0 MultiThreadProcessorSet : Uint4B +0x4d4 MultiThreadSetMaster : Ptr32 _KPRCB +0x4d8 ThreadStartCount : [2] Uint4B +0x4e0 CcFastReadNoWait : Uint4B +0x4e4 CcFastReadWait : Uint4B +0x4e8 CcFastReadNotPossible : Uint4B +0x4ec CcCopyReadNoWait : Uint4B +0x4f0 CcCopyReadWait : Uint4B +0x4f4 CcCopyReadNoWaitMiss : Uint4B +0x4f8 KeAlignmentFixupCount : Uint4B +0x4fc KeContextSwitches : Uint4B +0x500 KeDcacheFlushCount : Uint4B +0x504 KeExceptionDispatchCount : Uint4B +0x508 KeFirstLevelTbFills : Uint4B +0x50c KeFloatingEmulationCount : Uint4B +0x510 KeIcacheFlushCount : Uint4B +0x514 KeSecondLevelTbFills : Uint4B +0x518 KeSystemCalls : Uint4B +0x51c SpareCounter0 : [1] Uint4B +0x520 PPLookasideList : [16] _PP_LOOKASIDE_LIST +0x5a0 PPNPagedLookasideList : [32] _PP_LOOKASIDE_LIST +0x6a0 PPPagedLookasideList : [32] _PP_LOOKASIDE_LIST +0x7a0 PacketBarrier : Uint4B +0x7a4 ReverseStall : Uint4B +0x7a8 IpiFrame : Ptr32 Void +0x7ac PrcbPad2 : [52] UChar +0x7e0 CurrentPacket : [3] Ptr32 Void +0x7ec TargetSet : Uint4B +0x7f0 WorkerRoutine : Ptr32 void +0x7f4 IpiFrozen : Uint4B +0x7f8 PrcbPad3 : [40] UChar +0x820 RequestSummary : Uint4B +0x824 SignalDone : Ptr32 _KPRCB +0x828 PrcbPad4 : [56] UChar +0x860 DpcListHead : _LIST_ENTRY +0x868 DpcStack : Ptr32 Void +0x86c DpcCount : Uint4B +0x870 DpcQueueDepth : Uint4B +0x874 DpcRoutineActive : Uint4B +0x878 DpcInterruptRequested : Uint4B +0x87c DpcLastCount : Uint4B +0x880 DpcRequestRate : Uint4B +0x884 MaximumDpcQueueDepth : Uint4B +0x888 MinimumDpcRate : Uint4B +0x88c QuantumEnd : Uint4B +0x890 PrcbPad5 : [16] UChar +0x8a0 DpcLock : Uint4B +0x8a4 PrcbPad6 : [28] UChar +0x8c0 CallDpc : _KDPC +0x8e0 ChainedInterruptList : Ptr32 Void +0x8e4 LookasideIrpFloat : Int4B +0x8e8 SpareFields0 : [6] Uint4B +0x900 VendorString : [13] UChar +0x90d InitialApicId : UChar +0x90e LogicalProcessorsPerPhysicalProcessor : UChar +0x910 MHz : Uint4B +0x914 FeatureBits : Uint4B +0x918 UpdateSignature : _LARGE_INTEGER +0x920 NpxSaveArea : _FX_SAVE_AREA +0xb30 PowerState : _PROCESSOR_POWER_STATE
4.等待链表和调度链表
线程一共有三种状态,就绪、等待、运行。正在运行的线程存储在KPCR中,就绪和等待链表存在33个链表中。1个等待链表和32个就调度链表。xp和win7都是32个。64位的win7有64个链表。服务器版本中的windows,等待链表也是一个,但是调度链表头数组有多少个核就有多少个这个数组。
4.1 等待链表
有一个叫kiWaitListHead
的全局变量中存储了等待链表的头。如果一个线程比如调用了sleep()
、WaitForSingleObject()
等函数的时候,线程就在这个等待链表里。阻塞中的线程都在这个链表里。查看这个全局变量值方式如下:
kd> dd kiWaitListHead L2 80553d88 817b6e08 816f8918
这个值其实是指向了线程结构体ETHREAD
的第一个结构体KTHREAD
当中偏移0x60位置的 WaitListEntry\SwapListEntry 。因此通过这个kiWaitListHead
我们就可以得到第一个线程,过程如下:
kd> dt _ETHREAD 817b6e08-60 //找到等待链表头的线程对应的结构体 ntdll!_ETHREAD +0x000 Tcb : _KTHREAD +0x1c0 CreateTime : _LARGE_INTEGER 0xeab767c`17687fe0 +0x1c0 NestedFaultCount : 0y00 +0x1c0 ApcNeeded : 0y0 +0x1c8 ExitTime : _LARGE_INTEGER 0x817b6f70`817b6f70 +0x1c8 LpcReplyChain : _LIST_ENTRY [ 0x817b6f70 - 0x817b6f70 ] +0x1c8 KeyedWaitChain : _LIST_ENTRY [ 0x817b6f70 - 0x817b6f70 ] +0x1d0 ExitStatus : 0n0 +0x1d0 OfsChain : (null) +0x1d4 PostBlockList : _LIST_ENTRY [ 0x817b6f7c - 0x817b6f7c ] +0x1dc TerminationPort : 0xe2563800 _TERMINATION_PORT +0x1dc ReaperLink : 0xe2563800 _ETHREAD +0x1dc KeyedWaitValue : 0xe2563800 Void +0x1e0 ActiveTimerListLock : 0 +0x1e4 ActiveTimerListHead : _LIST_ENTRY [ 0x817b6f8c - 0x817b6f8c ] +0x1ec Cid : _CLIENT_ID +0x1f4 LpcReplySemaphore : _KSEMAPHORE +0x1f4 KeyedWaitSemaphore : _KSEMAPHORE +0x208 LpcReplyMessage : (null) +0x208 LpcWaitingOnPort : (null) +0x20c ImpersonationInfo : (null) +0x210 IrpList : _LIST_ENTRY [ 0x817b6fb8 - 0x817b6fb8 ] +0x218 TopLevelIrp : 0 +0x21c DeviceToVerify : (null) +0x220 ThreadsProcess : 0x810867c0 _EPROCESS //根据这个值我们可以找到该线程对应的进程结构体 +0x224 StartAddress : 0x7c8106e9 Void +0x228 Win32StartAddress : 0x769ae43b Void +0x228 LpcReceivedMessageId : 0x769ae43b +0x22c ThreadListEntry : _LIST_ENTRY [ 0x817b6d5c - 0x817b73cc ] +0x234 RundownProtect : _EX_RUNDOWN_REF +0x238 ThreadLock : _EX_PUSH_LOCK +0x23c LpcReplyMessageId : 0 +0x240 ReadClusterSize : 7 +0x244 GrantedAccess : 0x1f03ff +0x248 CrossThreadFlags : 0 +0x248 Terminated : 0y0 +0x248 DeadThread : 0y0 +0x248 HideFromDebugger : 0y0 +0x248 ActiveImpersonationInfo : 0y0 +0x248 SystemThread : 0y0 +0x248 HardErrorsAreDisabled : 0y0 +0x248 BreakOnTermination : 0y0 +0x248 SkipCreationMsg : 0y0 +0x248 SkipTerminationMsg : 0y0 +0x24c SameThreadPassiveFlags : 0 +0x24c ActiveExWorker : 0y0 +0x24c ExWorkerCanWaitUser : 0y0 +0x24c MemoryMaker : 0y0 +0x250 SameThreadApcFlags : 0 +0x250 LpcReceivedMsgIdValid : 0y0 +0x250 LpcExitThreadCalled : 0y0 +0x250 AddressSpaceOwner : 0y0 +0x254 ForwardClusterOnly : 0 '' +0x255 DisablePageFaultClustering : 0 ''
kd> dt _EPROCESS 0x810867c0 //查看该线程对应的进程结构体 ntdll!_EPROCESS +0x000 Pcb : _KPROCESS +0x06c ProcessLock : _EX_PUSH_LOCK +0x070 CreateTime : _LARGE_INTEGER 0x1d56ecf`82d2d61e +0x078 ExitTime : _LARGE_INTEGER 0x0 +0x080 RundownProtect : _EX_RUNDOWN_REF +0x084 UniqueProcessId : 0x00000430 Void +0x088 ActiveProcessLinks : _LIST_ENTRY [ 0x8055b158 - 0x816bb448 ] +0x090 QuotaUsage : [3] 0x16f8 +0x09c QuotaPeak : [3] 0x1798 +0x0a8 CommitCharge : 0x598 +0x0ac PeakVirtualSize : 0x346c000 +0x0b0 VirtualSize : 0x346c000 +0x0b4 SessionProcessLinks : _LIST_ENTRY [ 0xf9ef6014 - 0x816bb474 ] +0x0bc DebugPort : (null) +0x0c0 ExceptionPort : 0xe15caac0 Void +0x0c4 ObjectTable : 0xe255fc30 _HANDLE_TABLE +0x0c8 Token : _EX_FAST_REF +0x0cc WorkingSetLock : _FAST_MUTEX +0x0ec WorkingSetPage : 0xf6f +0x0f0 AddressCreationLock : _FAST_MUTEX +0x110 HyperSpaceLock : 0 +0x114 ForkInProgress : (null) +0x118 HardwareTrigger : 0 +0x11c VadRoot : 0x818b3a00 Void +0x120 VadHint : 0x8191d8d0 Void +0x124 CloneRoot : (null) +0x128 NumberOfPrivatePages : 0x1be +0x12c NumberOfLockedPages : 0 +0x130 Win32Process : 0xe21de470 Void +0x134 Job : (null) +0x138 SectionObject : 0xe16e7ae0 Void +0x13c SectionBaseAddress : 0x00400000 Void +0x140 QuotaBlock : 0x81085148 _EPROCESS_QUOTA_BLOCK +0x144 WorkingSetWatch : (null) +0x148 Win32WindowStation : 0x00000034 Void +0x14c InheritedFromUniqueProcessId : 0x0000046c Void +0x150 LdtInformation : (null) +0x154 VadFreeHint : (null) +0x158 VdmObjects : (null) +0x15c DeviceMap : 0xe1e3dbe0 Void +0x160 PhysicalVadList : _LIST_ENTRY [ 0x81086920 - 0x81086920 ] +0x168 PageDirectoryPte : _HARDWARE_PTE_X86 +0x168 Filler : 0 +0x170 Session : 0xf9ef6000 Void +0x174 ImageFileName : [16] "wuauclt.exe" +0x184 JobLinks : _LIST_ENTRY [ 0x0 - 0x0 ] +0x18c LockedPagesList : (null) +0x190 ThreadListHead : _LIST_ENTRY [ 0x817b7c8c - 0x8157efd4 ] +0x198 SecurityPort : (null) +0x19c PaeTop : 0xf9ff92c0 Void +0x1a0 ActiveThreads : 6 +0x1a4 GrantedAccess : 0x1f07fb +0x1a8 DefaultHardErrorProcessing : 0x8000 +0x1ac LastThreadExitStatus : 0n0 +0x1b0 Peb : 0x7ffdd000 _PEB +0x1b4 PrefetchTrace : _EX_FAST_REF +0x1b8 ReadOperationCount : _LARGE_INTEGER 0x4 +0x1c0 WriteOperationCount : _LARGE_INTEGER 0x2 +0x1c8 OtherOperationCount : _LARGE_INTEGER 0x206 +0x1d0 ReadTransferCount : _LARGE_INTEGER 0xb6c4 +0x1d8 WriteTransferCount : _LARGE_INTEGER 0x90 +0x1e0 OtherTransferCount : _LARGE_INTEGER 0x14f12 +0x1e8 CommitChargeLimit : 0 +0x1ec CommitChargePeak : 0x598 +0x1f0 AweInfo : (null) +0x1f4 SeAuditProcessCreationInfo : _SE_AUDIT_PROCESS_CREATION_INFO +0x1f8 Vm : _MMSUPPORT +0x238 LastFaultCount : 0 +0x23c ModifiedPageCount : 0 +0x240 NumberOfVads : 0x7d +0x244 JobStatus : 0 +0x248 Flags : 0xd0800 +0x248 CreateReported : 0y0 +0x248 NoDebugInherit : 0y0 +0x248 ProcessExiting : 0y0 +0x248 ProcessDelete : 0y0 +0x248 Wow64SplitPages : 0y0 +0x248 VmDeleted : 0y0 +0x248 OutswapEnabled : 0y0 +0x248 Outswapped : 0y0 +0x248 ForkFailed : 0y0 +0x248 HasPhysicalVad : 0y0 +0x248 AddressSpaceInitialized : 0y10 +0x248 SetTimerResolution : 0y0 +0x248 BreakOnTermination : 0y0 +0x248 SessionCreationUnderway : 0y0 +0x248 WriteWatch : 0y0 +0x248 ProcessInSession : 0y1 +0x248 OverrideAddressSpace : 0y0 +0x248 HasAddressSpace : 0y1 +0x248 LaunchPrefetched : 0y1 +0x248 InjectInpageErrors : 0y0 +0x248 VmTopDown : 0y0 +0x248 Unused3 : 0y0 +0x248 Unused4 : 0y0 +0x248 VdmAllowed : 0y0 +0x248 Unused : 0y00000 (0) +0x248 Unused1 : 0y0 +0x248 Unused2 : 0y0 +0x24c ExitStatus : 0n259 +0x250 NextPageColor : 0x44f7 +0x252 SubSystemMinorVersion : 0 '' +0x253 SubSystemMajorVersion : 0x4 '' +0x252 SubSystemVersion : 0x400 +0x254 PriorityClass : 0x2 '' +0x255 WorkingSetAcquiredUnsafe : 0 '' +0x258 Cookie : 0x831e4ccd
4.2 调度链表
KiDispatcherReadyListHead数组中存储了32个调度链表的头,查看调度链表列表方法如下:
kd> dd KiDispatcherReadyListHead L70 80554820 80554820 80554820 80554828 80554828 80554830 80554830 80554830 80554838 80554838 80554840 80554840 80554840 80554848 80554848 80554850 80554850 80554850 80554858 80554858 80554860 80554860 80554860 80554868 80554868 80554870 80554870 80554870 80554878 80554878 80554880 80554880 80554880 80554888 80554888 80554890 80554890 80554890 80554898 80554898 805548a0 805548a0 805548a0 805548a8 805548a8 805548b0 805548b0 805548b0 805548b8 805548b8 805548c0 805548c0 805548c0 805548c8 805548c8 805548d0 805548d0 805548d0 805548d8 805548d8 805548e0 805548e0 805548e0 805548e8 805548e8 805548f0 805548f0 805548f0 805548f8 805548f8 80554900 80554900 80554900 80554908 80554908 80554910 80554910 80554910 80554918 80554918 80554920 00000000 00000000 00000000 00000000 80554930 00000000 00000000 00000000 00000000 80554940 00000000 00000000 00000000 00000000 80554950 00000000 e1004000 00000000 00000000 80554960 00000001 f9567c98 00000002 00040001 80554970 00000000 80554974 80554974 00000000 80554980 00000000 819f0708 819f08d8 00000000 80554990 00000000 00000000 00000000 00000000 805549a0 0032c001 00000000 0032d001 00000000 805549b0 0032e001 00000000 0032f001 00000000 805549c0 f9ff92e0 001e0064 00000000 00000010 805549d0 00000000 00000000 00000000 00000000
调度链表是双向链表,一共三十二个。这三十二个链表代表不同的优先级别。
5.实验:
5.1 EPROCESS.ActiveProcessLinks断链隐藏进程
这里是以notepad.exe作为实验对象,驱动程序代码如下:
#include <Ntddk.h> UCHAR targetProcessName[] = "notepad.exe"; LONG Res; typedef struct _EPROCESS{ UCHAR part1[0x88]; LIST_ENTRY ActiveProcessLinks; UCHAR part2[0xE4]; UCHAR ImageFileName[0x16]; } EPORCESS; VOID HiddenProcess(UCHAR* targetProcessName){ EPORCESS** pCurrentProcessEprocessAddr=NULL; EPORCESS* pCurrentProcessEprocess=NULL; EPORCESS* pTmpProcessEprocess; EPORCESS* pTargetProcessEprocess; EPORCESS* pTargetProcessPreEprocess; EPORCESS* pTargetProcessNextEprocess; __asm{ mov eax,fs:[0x124] //获取当前线程的ETHREAD结构体 mov pCurrentProcessEprocessAddr,eax add pCurrentProcessEprocessAddr,0x220 //ETHREAD结构体偏移0x220的位置存的就是EPROCESS结构体的地址 } pCurrentProcessEprocess = *pCurrentProcessEprocessAddr; //DbgPrint("targetProcessName:%S\n",targetProcessName.Buffer); //DbgPrint("pCurrentProcessEprocess addr:%x\n",pCurrentProcessEprocess); //DbgPrint("pCurrentProcessEprocess ActiveProcessLinks Flink:%x\n",pCurrentProcessEprocess->ActiveProcessLinks.Flink); //DbgPrint("pCurrentProcessEprocess ActiveProcessLinks Blink:%x\n",pCurrentProcessEprocess->ActiveProcessLinks.Blink); //DbgPrint("pCurrentProcessEprocess ImageFileName:%s\n",pCurrentProcessEprocess->ImageFileName); pTmpProcessEprocess = (EPORCESS*)((ULONG)(pCurrentProcessEprocess->ActiveProcessLinks.Flink)-0x88); while(pTmpProcessEprocess!=pCurrentProcessEprocess){/*查找目标进程的EPROCESS*/ DbgPrint("%s\n",pTmpProcessEprocess->ImageFileName); pTmpProcessEprocess = (EPORCESS*)((ULONG)(pTmpProcessEprocess->ActiveProcessLinks.Flink)-0x88); if(strcmp(targetProcessName,pTmpProcessEprocess->ImageFileName)==0){ //DbgPrint("find target P!\n"); pTargetProcessEprocess = pTmpProcessEprocess; break; } } /*对目标进程进行双向断链*/ DbgPrint("pTargetProcessEprocess:%x\n",pTargetProcessEprocess); pTargetProcessPreEprocess=(EPORCESS*)((ULONG)(pTargetProcessEprocess->ActiveProcessLinks.Blink)-0x88); //获取目标程序的链表前一个 pTargetProcessNextEprocess=(EPORCESS*)((ULONG)(pTargetProcessEprocess->ActiveProcessLinks.Flink)-0x88); //获取目标程序的链表下一个 pTargetProcessPreEprocess->ActiveProcessLinks.Flink = ((ULONG)pTargetProcessNextEprocess+0x88); //将前一个进程的下一个进程指向目标进程的下一个进程 pTargetProcessNextEprocess->ActiveProcessLinks.Blink = ((ULONG)pTargetProcessPreEprocess+0x88); //将下一个进程的前一个进程指向目标进程的前一个进程 } VOID DriverUnload(PDRIVER_OBJECT driver) { DbgPrint("驱动程序已停止!\n\r"); } NTSTATUS DriverEntry(PDRIVER_OBJECT driver,PUNICODE_STRING reg_path) { DbgPrint("驱动程序已加载!\n\r"); HiddenProcess(targetProcessName); driver->DriverUnload = DriverUnload; return STATUS_SUCCESS; }
最终实验效果如下图所示: 这里可以看到这个进程在任务列表里已经成功隐藏。
5.2.断链隐藏线程
5.3.模拟线程切换
参考:
-
https://blog.csdn.net/qq_18059143/article/details/103394926 进程与线程之模拟线程切换
-
http://blog.initm.com/threadswitch.shtml [ThreadSwitch]模拟windows线程切换