KiSwapThread线程切换


KiSwapThread线程切换

KiSwapThread是通过切换线程上下文来实现线程切换的函数

KiSwapThread主函数

0040AB8A        mov     edi, edi
0040AB8C        push    esi
0040AB8D        push    edi
0040AB8E        mov     eax, large fs:_KPCR.Prcb ; 获取KPRCB
0040AB94        mov     esi, eax
0040AB96        mov     eax, [esi+_KPRCB.NextThread] ; 获取下一个线程
0040AB99        test    eax, eax
0040AB9B        mov     edi, [esi+_KPRCB.CurrentThread] ; 获取当前线程
0040AB9E        jnz     loc_4109B9
0040ABA4        push    ebx
0040ABA5        movsx   ebx, [esi+_KPRCB.Number]
0040ABA9        xor     edx, edx
0040ABAB        mov     ecx, ebx
0040ABAD        call    @KiFindReadyThread@8 ; 找到一个准备执行的线程
0040ABB2        test    eax, eax
0040ABB4        jz      loc_4107BE      ; 获取空闲线程
0040ABBA
0040ABBA loc_40ABBA:
0040ABBA        pop     ebx
0040ABBB loc_40ABBB:
0040ABBB        mov     ecx, eax        ; 找到的线程
0040ABBD        call    @KiSwapContext@4 ; 执行线程上下文切换
0040ABC2        test    al, al
0040ABC4        mov     cl, [edi+58h]   ; NewIrql
0040ABC7        mov     edi, [edi+54h]
0040ABCA        mov     esi, ds:__imp_@KfLowerIrql@4 ; KfLowerIrql(x)
0040ABD0        jnz     loc_41BC56
0040ABD6
0040ABD6 loc_40ABD6:
0040ABD6        call    esi ; KfLowerIrql(x) ; KfLowerIrql(x)
0040ABD8        mov     eax, edi
0040ABDA        pop     edi
0040ABDB        pop     esi
0040ABDC        retn

KiSwapContext

.text:0040580E                 sub     esp, 10h        ; 栈分配空间
.text:00405811                 mov     [esp+0Ch], ebx  ; push
.text:00405815                 mov     [esp+8], esi
.text:00405819                 mov     [esp+4], edi
.text:0040581D                 mov     [esp], ebp
.text:00405820                 mov     ebx, large fs:_KPCR.SelfPcr ; 获取当前KPCR
.text:00405827                 mov     esi, ecx
.text:00405829                 mov     edi, [ebx+_KPCR.PrcbData.CurrentThread] ; 指向当前线程
.text:0040582F                 mov     [ebx+_KPCR.PrcbData.CurrentThread], esi ; 将找到的线程放入_kpcr中的当前线程
.text:00405835                 mov     cl, [edi+_KTHREAD.WaitIrql] ; 中断请求级别
.text:00405838                 call    SwapContext     ; esi新线程
.text:00405838                                         ; edi老线程
.text:0040583D                 mov     ebp, [esp]      ; 相当于POP新线程的寄存器
.text:00405840                 mov     edi, [esp+4]
.text:00405844                 mov     esi, [esp+8]
.text:00405848                 mov     ebx, [esp+0Ch]
.text:0040584C                 add     esp, 10h
.text:0040584F                 retn

SwapContext

.text:00405932                 or      cl, cl          ; 判断cl是否为0
.text:00405934                 mov     es:[esi+_KTHREAD.State], Running
.text:00405939                 pushf                   ; 保存原来线程的eflags
.text:0040593A                 lea     ecx, [ebx+(_KPCR.PrcbData.LockQueue.Next+8)]
.text:00405940                 call    @KeAcquireQueuedSpinLockAtDpcLevel@4 ; 锁队列,链表
.text:00405945                 lea     ecx, [ebx+_KPCR.PrcbData.LockQueue]
.text:0040594B                 call    @KeReleaseQueuedSpinLockFromDpcLevel@4 
.text:00405950 loc_405950:                             ; CODE XREF: KiIdleLoop()+7C↓j
.text:00405950                 mov     ecx, [ebx+_KPCR.NtTib.ExceptionList]
.text:00405952                 cmp     [ebx+_KPCR.PrcbData.DpcRoutineActive], 0
.text:00405959                 push    ecx             ; 保存OLD的异常链表
.text:0040595A                 jnz     loc_405AE2      ; 不为0就蓝屏
.text:00405960                 cmp     ds:_PPerfGlobalGroupMask, 0 ; 记录代码,通常情况不发生
.text:00405967                 jnz     loc_405AB9
.text:0040596D loc_40596D:
.text:0040596D                 mov     ebp, cr0        ; 读cr0
.text:00405970                 mov     edx, ebp
.text:00405972                 cmp     [edi+_KTHREAD.NpxState], 0 ; 检查浮点状态,浮点寄存器有没有用过
.text:00405976                 jz      loc_405A94      ; 如果为0就修改cr0
.text:0040597C loc_40597C:
.text:0040597C                 mov     cl, [esi+_KTHREAD.DebugActive] ; 新线程调试状态是否激活
.text:0040597F                 mov     [ebx+_KPCR.DebugActive], cl ; 将新线程的调试状态给处理器调试状态
.text:00405982                 cli
.text:00405983                 mov     [edi+_KTHREAD.KernelStack], esp ; 当前线程运行到最后一个地方的ESP,把老线程保存起来,老线程即将结束,新线程即将开始
.text:00405986                 mov     eax, [esi+_KTHREAD.InitialStack] ; 新线程的InitialStack
.text:00405989                 mov     ecx, [esi+_KTHREAD.StackLimit] ; 新线程的StackLimit
.text:0040598C                 sub     eax, 210h       ; 给浮点寄存器留空间
.text:00405991                 mov     [ebx+_KPCR.NtTib.StackLimit], ecx ; 设置为新的StackLimit
.text:00405994                 mov     [ebx+_KPCR.NtTib.StackBase], eax ; 设置为新的StackBase
.text:00405997                 xor     ecx, ecx
.text:00405999                 mov     cl, [esi+_KTHREAD.NpxState] ; 检查新线程的浮点状态
.text:0040599C                 and     edx, 0FFFFFFF1h ; EDX放的是原来cr0的值
.text:0040599F                 or      ecx, edx
.text:004059A1                 or      ecx, [eax+_FX_SAVE_AREA.Cr0NpxState] ; 检查浮点内容
.text:004059A7                 cmp     ebp, ecx
.text:004059A9                 jnz     loc_405A8C      ; 改变cr0,cr0中存有浮点状态
.text:004059AF                 lea     ecx, [ecx]

文章作者: Kevin。
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Kevin。 !
评论
 上一篇
Windows APC机制 Windows APC机制
Windows APC机制APC(Asynchronous Procedure Call),即异步过程调用,也称不确定调用。Windows的APC机制本质上是一种对于应用软件(线程)的“软件中断”机制。与DPC不同,APC是针对线程的,每个
2022-06-24
下一篇 
Windows进程和线程 Windows进程和线程
Windows进程和线程众所周知,进程是空间,线程是任务 进程结构体进程有两个结构体_kprocess和_eprocess,_eprocess继承了_kprocess 在Windbg中可以使用dt _kprocess [ADDR] 和dt
2022-05-14
  目录