JIURL玩玩Win2k进程线程篇 ETHREAD
作者: JIURL
日期: 2003-7-30
每个线程都有一个 ETHREAD 结构。Win2k Build 2195 中 ETHREAD 结构定义如下
kd> !strct ethread
!strct ethread
struct _ETHREAD (sizeof=584)
+000 struct _KTHREAD Tcb
+000 struct _DISPATCHER_HEADER Header
+000 byte Type
+001 byte Absolute
+002 byte Size
+003 byte Inserted
+004 int32 SignalState
+008 struct _LIST_ENTRY WaitListHead
+008 struct _LIST_ENTRY *Flink
+00c struct _LIST_ENTRY *Blink
+010 struct _LIST_ENTRY MutantListHead
+010 struct _LIST_ENTRY *Flink
+014 struct _LIST_ENTRY *Blink
+018 void *InitialStack
+01c void *StackLimit
+020 void *Teb
+024 void *TlsArray
+028 void *KernelStack
+02c byte DebugActive
+02d byte State
+02e byte Alerted[2]
+030 byte Iopl
+031 byte NpxState
+032 char Saturation
+033 char Priority
+034 struct _KAPC_STATE ApcState
+034 struct _LIST_ENTRY ApcListHead[2]
struct _LIST_ENTRY *Flink
struct _LIST_ENTRY *Blink
+044 struct _KPROCESS *Process
+048 byte KernelApcInProgress
+049 byte KernelApcPending
+04a byte UserApcPending
+04c uint32 ContextSwitches
+050 int32 WaitStatus
+054 byte WaitIrql
+055 char WaitMode
+056 byte WaitNext
+057 byte WaitReason
+058 struct _KWAIT_BLOCK *WaitBlockList
+05c struct _LIST_ENTRY WaitListEntry
+05c struct _LIST_ENTRY *Flink
+060 struct _LIST_ENTRY *Blink
+064 uint32 WaitTime
+068 char BasePriority
+069 byte DecrementCount
+06a char PriorityDecrement
+06b char Quantum
+06c struct _KWAIT_BLOCK WaitBlock[4]
struct _LIST_ENTRY WaitListEntry
struct _LIST_ENTRY *Flink
struct _LIST_ENTRY *Blink
struct _KTHREAD *Thread
void *Object
struct _KWAIT_BLOCK *NextWaitBlock
uint16 WaitKey
uint16 WaitType
+0cc void *LegoData
+0d0 uint32 KernelApcDisable
+0d4 uint32 UserAffinity
+0d8 byte SystemAffinityActive
+0d9 byte PowerState
+0da byte NpxIrql
+0db byte Pad[1]
+0dc void *ServiceTable
+0e0 struct _KQUEUE *Queue
+0e4 uint32 ApcQueueLock
+0e8 struct _KTIMER Timer
+0e8 struct _DISPATCHER_HEADER Header
+0e8 byte Type
+0e9 byte Absolute
+0ea byte Size
+0eb byte Inserted
+0ec int32 SignalState
+0f0 struct _LIST_ENTRY WaitListHead
+0f0 struct _LIST_ENTRY *Flink
+0f4 struct _LIST_ENTRY *Blink
+0f8 union _ULARGE_INTEGER DueTime
+0f8 uint32 LowPart
+0fc uint32 HighPart
+0f8 struct __unnamed12 u
+0f8 uint32 LowPart
+0fc uint32 HighPart
+0f8 uint64 QuadPart
+100 struct _LIST_ENTRY TimerListEntry
+100 struct _LIST_ENTRY *Flink
+104 struct _LIST_ENTRY *Blink
+108 struct _KDPC *Dpc
+10c int32 Period
+110 struct _LIST_ENTRY QueueListEntry
+110 struct _LIST_ENTRY *Flink
+114 struct _LIST_ENTRY *Blink
+118 uint32 Affinity
+11c byte Preempted
+11d byte ProcessReadyQueue
+11e byte KernelStackResident
+11f byte NextProcessor
+120 void *CallbackStack
+124 void *Win32Thread
+128 struct _KTRAP_FRAME *TrapFrame
+12c struct _KAPC_STATE *ApcStatePointer[2]
+134 char PreviousMode
+135 byte EnableStackSwap
+136 byte LargeStack
+137 byte ResourceIndex
+138 uint32 KernelTime
+13c uint32 UserTime
+140 struct _KAPC_STATE SavedApcState
+140 struct _LIST_ENTRY ApcListHead[2]
struct _LIST_ENTRY *Flink
struct _LIST_ENTRY *Blink
+150 struct _KPROCESS *Process
+154 byte KernelApcInProgress
+155 byte KernelApcPending
+156 byte UserApcPending
+158 byte Alertable
+159 byte ApcStateIndex
+15a byte ApcQueueable
+15b byte AutoAlignment
+15c void *StackBase
+160 struct _KAPC SuspendApc
+160 int16 Type
+162 int16 Size
+164 uint32 Spare0
+168 struct _KTHREAD *Thread
+16c struct _LIST_ENTRY ApcListEntry
+16c struct _LIST_ENTRY *Flink
+170 struct _LIST_ENTRY *Blink
+174 function *KernelRoutine
+178 function *RundownRoutine
+17c function *NormalRoutine
+180 void *NormalContext
+184 void *SystemArgument1
+188 void *SystemArgument2
+18c char ApcStateIndex
+18d char ApcMode
+18e byte Inserted
+190 struct _KSEMAPHORE SuspendSemaphore
+190 struct _DISPATCHER_HEADER Header
+190 byte Type
+191 byte Absolute
+192 byte Size
+193 byte Inserted
+194 int32 SignalState
+198 struct _LIST_ENTRY WaitListHead
+198 struct _LIST_ENTRY *Flink
+19c struct _LIST_ENTRY *Blink
+1a0 int32 Limit
+1a4 struct _LIST_ENTRY ThreadListEntry
+1a4 struct _LIST_ENTRY *Flink
+1a8 struct _LIST_ENTRY *Blink
+1ac char FreezeCount
+1ad char SuspendCount
+1ae byte IdealProcessor
+1af byte DisableBoost
+1b0 union _LARGE_INTEGER CreateTime
+1b0 uint32 LowPart
+1b4 int32 HighPart
+1b0 struct __unnamed3 u
+1b0 uint32 LowPart
+1b4 int32 HighPart
+1b0 int64 QuadPart
+1b0 bits0-1 NestedFaultCount
+1b0 bits2-2 ApcNeeded
+1b8 union _LARGE_INTEGER ExitTime
+1b8 uint32 LowPart
+1bc int32 HighPart
+1b8 struct __unnamed3 u
+1b8 uint32 LowPart
+1bc int32 HighPart
+1b8 int64 QuadPart
+1b8 struct _LIST_ENTRY LpcReplyChain
+1b8 struct _LIST_ENTRY *Flink
+1bc struct _LIST_ENTRY *Blink
+1c0 int32 ExitStatus
+1c0 void *OfsChain
+1c4 struct _LIST_ENTRY PostBlockList
+1c4 struct _LIST_ENTRY *Flink
+1c8 struct _LIST_ENTRY *Blink
+1cc struct _LIST_ENTRY TerminationPortList
+1cc struct _LIST_ENTRY *Flink
+1d0 struct _LIST_ENTRY *Blink
+1d4 uint32 ActiveTimerListLock
+1d8 struct _LIST_ENTRY ActiveTimerListHead
+1d8 struct _LIST_ENTRY *Flink
+1dc struct _LIST_ENTRY *Blink
+1e0 struct _CLIENT_ID Cid
+1e0 void *UniqueProcess
+1e4 void *UniqueThread
+1e8 struct _KSEMAPHORE LpcReplySemaphore
+1e8 struct _DISPATCHER_HEADER Header
+1e8 byte Type
+1e9 byte Absolute
+1ea byte Size
+1eb byte Inserted
+1ec int32 SignalState
+1f0 struct _LIST_ENTRY WaitListHead
+1f0 struct _LIST_ENTRY *Flink
+1f4 struct _LIST_ENTRY *Blink
+1f8 int32 Limit
+1fc void *LpcReplyMessage
+200 uint32 LpcReplyMessageId
+204 uint32 PerformanceCountLow
+208 struct _PS_IMPERSONATION_INFORMATION *ImpersonationInfo
+20c struct _LIST_ENTRY IrpList
+20c struct _LIST_ENTRY *Flink
+210 struct _LIST_ENTRY *Blink
+214 uint32 TopLevelIrp
+218 struct _DEVICE_OBJECT *DeviceToVerify
+21c uint32 ReadClusterSize
+220 byte ForwardClusterOnly
+221 byte DisablePageFaultClustering
+222 byte DeadThread
+223 byte HideFromDebugger
+224 uint32 HasTerminated
+228 uint32 GrantedAccess
+22c struct _EPROCESS *ThreadsProcess
+230 void *StartAddress
+234 void *Win32StartAddress
+234 uint32 LpcReceivedMessageId
+238 byte LpcExitThreadCalled
+239 byte HardErrorsAreDisabled
+23a byte LpcReceivedMsgIdValid
+23b byte ActiveImpersonationInfo
+23c int32 PerformanceCountHigh
+240 struct _LIST_ENTRY ThreadListEntry
+240 struct _LIST_ENTRY *Flink
+244 struct _LIST_ENTRY *Blink
struct _KTRAP_FRAME (sizeof=140)
+00 uint32 DbgEbp
+04 uint32 DbgEip
+08 uint32 DbgArgMark
+0c uint32 DbgArgPointer
+10 uint32 TempSegCs
+14 uint32 TempEsp
+18 uint32 Dr0
+1c uint32 Dr1
+20 uint32 Dr2
+24 uint32 Dr3
+28 uint32 Dr6
+2c uint32 Dr7
+30 uint32 SegGs
+34 uint32 SegEs
+38 uint32 SegDs
+3c uint32 Edx
+40 uint32 Ecx
+44 uint32 Eax
+48 uint32 PreviousPreviousMode
+4c struct _EXCEPTION_REGISTRATION_RECORD *ExceptionList
+50 uint32 SegFs
+54 uint32 Edi
+58 uint32 Esi
+5c uint32 Ebx
+60 uint32 Ebp
+64 uint32 ErrCode
+68 uint32 Eip
+6c uint32 SegCs
+70 uint32 EFlags
+74 uint32 HardwareEsp
+78 uint32 HardwareSegSs
+7c uint32 V86Es
+80 uint32 V86Ds
+84 uint32 V86Fs
+88 uint32 V86Gs
遍历一个进程的所有线程
一个进程的所有线程通过 LIST_ENTRY 结构链在了一个双向循环链表上。
一个链表是以 EPROCESS 结构的 KPROCESS Pcb 中的 ThreadListHead 为链表的链表头。链上的每一项是一个线程的 KTHREAD ETHREAD 结构的 Tcb 中的 ThreadListEntry 。
另一个链表是以 EPROCESS 结构中的 ThreadListHead 为链表的链表头。链上的每一项是一个线程的 ETHREAD 结构中的 ThreadListEntry 。
通过这两个链表中的任何一个,都可以找到一个进程的所有线程的 ETHREAD 结构,当然找到 ETHREAD 结构,就可以找到 ETHREAD 结构中的 KTHREAD。
KTHREAD 链表
struct _EPROCESS (sizeof=648)
+000 struct _KPROCESS Pcb
+050 struct _LIST_ENTRY ThreadListHead
+050 struct _LIST_ENTRY *Flink
+054 struct _LIST_ENTRY *Blink
struct _ETHREAD (sizeof=584)
+000 struct _KTHREAD Tcb
+1a4 struct _LIST_ENTRY ThreadListEntry
+1a4 struct _LIST_ENTRY *Flink
+1a8 struct _LIST_ENTRY *Blink
ETHREAD 链表
struct _EPROCESS (sizeof=648)
+270 struct _LIST_ENTRY ThreadListHead
+270 struct _LIST_ENTRY *Flink
+274 struct _LIST_ENTRY *Blink
struct _ETHREAD (sizeof=584)
+240 struct _LIST_ENTRY ThreadListEntry
+240 struct _LIST_ENTRY *Flink
+244 struct _LIST_ENTRY *Blink
线程ID和线程所在进程的进程ID
+1e0 struct _CLIENT_ID Cid
+1e0 void *UniqueProcess
+1e4 void *UniqueThread
线程所在进程
+000 struct _KTHREAD Tcb
+034 struct _KAPC_STATE ApcState
+044 struct _KPROCESS *Process
+22c struct _EPROCESS *ThreadsProcess
KTHREAD 偏移 +044 处的 KPROCESS *Process ,是指向线程所在进程的 KPROCESS 结构的指针。
KTHREAD 偏移 +22c 处的 EPROCESS *ThreadsProcess ,是指向线程所在进程的 EPROCESS 结构的指针。
我们 KPROCESS 结构在 EPROCESS 结构中,并且位于 EPROCESS 结构开始处。+044 *Process 和
+22c *ThreadsProcess 指向的是同一地址。
线程内核模式下的堆栈
+018 void *InitialStack
+15c void *StackBase
+01c void *StackLimit
一个线程,有两个自己的堆栈(Stack)。一个是内核模式下的堆栈,一个是用户模式下的堆栈。当线程在内核模式,也就是 ring0 下,执行代码的时候,使用的是内核模式堆栈。当线程在用户模式下,也就是 ring3 下,执行代码的时候,使用的是用户模式堆栈。某些只在内核模式运行的线程没有用户模式堆栈,比如 System 进程(PID为8的进程)的一些线程。
一个线程的内核模式堆栈,位于系统地址空间。该线程 ETHREAD 结构偏移 +018 处的 InitialStack 是该线程内核模式堆栈的最高地址,也就是开始地址,堆栈是向下增长的。该线程 ETHREAD 结构偏移 +15c 处的 StackBase 也指向该线程内核模式堆栈的最高地址。该线程 ETHREAD 结构偏移 +01c 处的 StackLimit 是该线程内核模式堆栈的最低地址。
线程的用户模式堆栈的信息在线程TEB中。
下面我们举一个使用两个堆栈的例子
比如一个应用程序调用 kernel32.dll 中的API CloseHandle()。
这时 esp 和 ebp 都是在用户模式堆栈上。(用户模式堆栈的信息在线程TEB中)。
kernel32!CloseHandle 调用 ntdll.dll!NtClose。
ntdll.dll!NtClose 会执行 INT 2E 指令,到中断之前,一直是在 ring3 下,使用的是用户模式堆栈(esp 和 ebp 都是在用户模式堆栈上)。产生 2e 中断。
CPU 处理 2e 中断,将转去执行 2e 中断的中断处理程序 ntoskrnl!KiSystemService。当转到ntoskrnl!KiSystemService 时,CPU 已经把当前特权级从 ring3 变为 ring0 ,使用的堆栈也变成了内核模式堆栈(esp 和 ebp 在内核模式堆栈上)。ntoskrnl!KiSystemService 最终会调用 ntoskrnl!NtClose 完成处理。
线程TEB
+020 void *Teb
线程所执行的代码
+230 void *StartAddress
StartAddress 就是这个线程所执行代码的开始地址
线程对象的对象体
需要说明的是 ETHREAD 就是线程对象的对象体,象其他类型的对象一样,ETHREAD 之前也有对象头。使用 kd 可以很容易看到这一点
kd> !thread 8141eda0 0
!thread 8141eda0 0
THREAD 8141eda0 Cid 8.4 Teb: 00000000 Win32Thread: 00000000 WAIT
kd> !object 8141eda0
!object 8141eda0
Object: 8141eda0 Type: (814523e0) Thread
ObjectHeader: 8141ed88
HandleCount: 0 PointerCount: 3
根据 ETHREAD 的地址,kd 可以正确分析出对象类型是线程,说明了 ETHREAD 的确是对象体。
欢迎交流,欢迎交朋友,