线程

3.线程

线程介绍

线程是需要上下文环境的

线程一定绑定在某个进程上的

内核线程只有一个堆栈(在内核中创建线程如果不指定进程的话,默认是绑定在system进程)

R3中线程有2个堆栈,在R3进R0的时候会切换堆栈,这时候用的就不是R3的堆栈而是R0的(R0和R3的上下文环境)

线程没有cr3的概念,只有绑定在哪个进程上面的概念

内核空间是所有进程共享的

R3下,描述线程用的是TEB

R0下,描述线程用的是KTHREAD或者ETHREAD

线程在内核态的时候是可以跑在其他的进程上

线程在WinXP的时候是32个链表

线程在Win7 之后的时候不是32个链表,而是每一个32个链表,放到KPCR

线程在单核情况下本质就是32个链表组成的数组

线程在就绪状态下会插入11号链表中

线程结构

windbg查看进程线程

获得指定进程的线程

!process 0 0

!process 进程地址

 THREAD 88a04538  Cid 0d78.0cb4  Teb: 7ffdd000 Win32Thread: 00000000 WAIT: (UserRequest) UserMode Alertable
            86df6b20  SynchronizationTimer
            86e13d58  SynchronizationTimer
            86e65290  SynchronizationTimer

因为是R3(UserMode)的所以有TEB

dt _kthread线程地址

kd> dt _kthread 88a04538
ntdll!_KTHREAD
   +0x000 Header           : _DISPATCHER_HEADER
   +0x010 CycleTime        : 0x827a0
   +0x018 HighCycleTime    : 0
   +0x020 QuantumTarget    : 0x11d245d4//总耗时的时间碎片
   +0x028 InitialStack     : 0x838c4ed0 Void//栈底
   +0x02c StackLimit       : 0x838c2000 Void/栈顶
   +0x030 KernelStack      : 0x838c4648 Void/栈保存的切换前的ESP
   +0x034 ThreadLock       : 0//锁
   +0x038 WaitRegister     : _KWAIT_STATUS_REGISTER
   +0x039 Running          : 0 ''//是否在运行中的状态,运行中是1
   +0x03a Alerted          : [2]  ""//可警惕
   +0x03c KernelStackResident : 0y0//线程是否可以扩张
   +0x03c ReadyTransition  : 0y0
   +0x03c ProcessReadyQueue : 0y0
   +0x03c WaitNext         : 0y0
   +0x03c SystemAffinityActive : 0y0
   +0x03c Alertable        : 0y1//唤醒,标注当前线程是否可以被唤醒
   +0x03c GdiFlushActive   : 0y0//GDI是否活动刷新
   +0x03c UserStackWalkActive : 0y0//用户层的堆栈活动
   +0x03c ApcInterruptRequest : 0y0//是否允许apc中断,如果1的话,硬件中断不会触发apc,有成员的时候才会触发apc
   +0x03c ForceDeferSchedule : 0y0
   +0x03c QuantumEndMigrate : 0y0
   +0x03c UmsDirectedSwitchEnable : 0y0
   +0x03c TimerActive      : 0y0
   +0x03c SystemThread     : 0y0//判断自己是否是内核线程,1代表内核线程
   +0x03c Reserved         : 0y000000000000000000 (0)
   +0x03c MiscFlags        : 0n32
   +0x040 ApcState         : _KAPC_STATE//apc状态
   +0x040 ApcStateFill     : [23]  "xE???"
   +0x057 Priority         : 10 ''//优先级,当前线程的优先级的级别
   +0x058 NextProcessor    : 0//根据亲核性,下次切换线程线程跑在哪个核上
   +0x05c DeferredProcessor : 0//如果没有指定下一次泡在那个核上,那么就按照这个默认的
   +0x060 ApcQueueLock     : 0
   +0x064 ContextSwitches  : 0xb//当前线程切换了多少次
   +0x068 State            : 0x5 ''//状态,线程的状态
   +0x069 NpxState         : 0 ''
   +0x06a WaitIrql         : 0 ''//等待相关的
   +0x06b WaitMode         : 1 ''//等待相关的
   +0x06c WaitStatus       : 0n2//等待相关的
   +0x070 WaitBlockList    : 0x88a045f8 _KWAIT_BLOCK//等待相关的
   +0x074 WaitListEntry    : _LIST_ENTRY [ 0x87e7ddbc - 0x80b9e300 ]//等待相关的
   +0x074 SwapListEntry    : _SINGLE_LIST_ENTRY
   +0x07c Queue            : (null) //队列
   +0x080 WaitTime         : 0x390dc
   +0x084 KernelApcDisable : 0n0
   +0x086 SpecialApcDisable : 0n0
   +0x084 CombinedApcDisable : 0
   +0x088 Teb              : 0x7ffdd000 Void//TEB
   +0x090 Timer            : _KTIMER//定时器
   +0x0b8 AutoAlignment    : 0y0
   +0x0b8 DisableBoost     : 0y0
   +0x0b8 EtwStackTraceApc1Inserted : 0y0
   +0x0b8 EtwStackTraceApc2Inserted : 0y0
   +0x0b8 CalloutActive    : 0y0
   +0x0b8 ApcQueueable     : 0y1
   +0x0b8 EnableStackSwap  : 0y1
   +0x0b8 GuiThread        : 0y0
   +0x0b8 UmsPerformingSyscall : 0y0
   +0x0b8 VdmSafe          : 0y0
   +0x0b8 UmsDispatched    : 0y0
   +0x0b8 ReservedFlags    : 0y000000000000000000000 (0)
   +0x0b8 ThreadFlags      : 0n96
   +0x0bc ServiceTable     : 0x84185b00 Void
   +0x0c0 WaitBlock        : [4] _KWAIT_BLOCK
   +0x120 QueueListEntry   : _LIST_ENTRY [ 0x0 - 0x0 ]
   +0x128 TrapFrame        : 0x838c4c34 _KTRAP_FRAME
   +0x12c FirstArgument    : 0x00000003 Void
   +0x130 CallbackStack    : (null) 
   +0x130 CallbackDepth    : 0
   +0x134 ApcStateIndex    : 0 ''
   +0x135 BasePriority     : 8 ''
   +0x136 PriorityDecrement : 2 ''
   +0x136 ForegroundBoost  : 0y0010
   +0x136 UnusualBoost     : 0y0000
   +0x137 Preempted        : 0 ''//抢占(windows的抢占机制),标记为1可以抢占其他线程
   +0x138 AdjustReason     : 0 ''
   +0x139 AdjustIncrement  : 0 ''
   +0x13a PreviousMode     : 1 ''
   +0x13b Saturation       : 0 ''
   +0x13c SystemCallNumber : 0x185
   +0x140 FreezeCount      : 0
   +0x144 UserAffinity     : _GROUP_AFFINITY
   +0x150 Process          : 0x88b3f030 _KPROCESS//谁创建了这个线程
   +0x154 Affinity         : _GROUP_AFFINITY
   +0x160 IdealProcessor   : 0
   +0x164 UserIdealProcessor : 0
   +0x168 ApcStatePointer  : [2] 0x88a04578 _KAPC_STATE
   +0x170 SavedApcState    : _KAPC_STATE
   +0x170 SavedApcStateFill : [23]  "???"
   +0x187 WaitReason       : 0x6 ''
   +0x188 SuspendCount     : 0 ''
   +0x189 Spare1           : 0 ''
   +0x18a OtherPlatformFill : 0 ''
   +0x18c Win32Thread      : (null) //win32线程,如果是UI线程,那么会多一个Win32结构体
   +0x190 StackBase        : 0x838c5000 Void
   +0x194 SuspendApc       : _KAPC
   +0x194 SuspendApcFill0  : [1]  "???"
   +0x195 ResourceIndex    : 0 ''
   +0x194 SuspendApcFill1  : [3]  "???"
   +0x197 QuantumReset     : 0x12 ''
   +0x194 SuspendApcFill2  : [4]  "???"
   +0x198 KernelTime       : 0
   +0x194 SuspendApcFill3  : [36]  "???"
   +0x1b8 WaitPrcb         : (null) 
   +0x194 SuspendApcFill4  : [40]  "???"
   +0x1bc LegoData         : (null) 
   +0x194 SuspendApcFill5  : [47]  "???"
   +0x1c3 LargeStack       : 0 ''
   +0x1c4 UserTime         : 0
   +0x1c8 SuspendSemaphore : _KSEMAPHORE
   +0x1c8 SuspendSemaphorefill : [20]  "???"
   +0x1dc SListFaultCount  : 0
   +0x1e0 ThreadListEntry  : _LIST_ENTRY [ 0x88b3f05c - 0x86df4f28 ]//创建这个线程的进程创建的所有线程的列表
   +0x1e8 MutantListHead   : _LIST_ENTRY [ 0x88a04720 - 0x88a04720 ]
   +0x1f0 SListFaultAddress : (null) 
   +0x1f4 ThreadCounters   : (null) 
   +0x1f8 XStateSave       : (null) 

内核态的线程的堆栈

+0x028 InitialStack     : 0x838c4ed0 Void
+0x02c StackLimit       : 0x838c2000 Void
+0x030 KernelStack      : 0x838c4648 Void

内核线程的

为什么这个栈底并不在底部,看下面的KiFastCallEntry

ebp减去了29ch

每一个线程在创建堆栈的时候预留了29c个位置

这预留的29c = trap_frame + 浮点

所以如果要求出整个栈的栈底的话需要InitialStack + 29c

trap_frame 作用:fastcall进内核的时候需要提供一个存储环境的地方

浮点 线程切换的时候使用

KernelStack并不是常用的pop/push的那个ESP,而是线程切换的时候将老线程的esp保存在这个里,线程换恢复再从这里取出,恢复堆栈(类似Linux中的prev ebp

Alerted 可警惕

+0x03a Alerted          : [2]  ""//可警惕

数组是0代表是0环的可警惕,数组是1是3环的可警惕

可警惕的程度代表当线程正处在一种可以被唤醒的假等待

Sleep是死等,SleepEx是带有警惕性的等待

KernelStackResident 线程扩张

默认情况下线程的栈被创建的时候只有12k(0x3000)但是整个太小了,再调用UI的时候不够,需要扩张

而这个KernelStackResident记录了线程是否允许拓张,为1代表可以扩张

Alertable 是否可以唤醒

这个相当于一个开关,当他置为1的时候,不一定可以唤醒,在此情况下加上了可警惕就绝对可以唤醒

ApcState apc状态

kd> dt _kapc_state
ntdll!_KAPC_STATE
   +0x000 ApcListHead      : [2] _LIST_ENTRY
   +0x010 Process          : Ptr32 _KPROCESS//当先线程的上下文环境是谁
   +0x014 KernelApcInProgress : UChar
   +0x015 KernelApcPending : UChar
   +0x016 UserApcPending   : UChar

Process

Process :当前线程的进程所属是谁

假设A进程的0x1234指向的是AB进程的0x1234指向的是B,那么如何正确的让A进程读B进程的地址,也就是如何知道读的是不是B进程

CR3是绑定在进程上的,可以通过改变CR3来让改变线程的上下文环境,让线程跑到其他进程

Priority 线程优先级

线程初始优先级是8

数字越大,优先级越低

posted @ 2024-05-18 17:24  MuRKuo  阅读(31)  评论(0编辑  收藏  举报