简介
在 Windows
内核中,线程的切换是通过底层内核 API
函数 KiSwapContex/SwapContex
实现的。
KiSwapContex
KiSwapContex
的逆向分析如下:
.text:00404828 ; =============== S U B R O U T I N E =======================================
.text:00404828
.text:00404828
.text:00404828 ; __fastcall KiSwapContext(x)
.text:00404828 @KiSwapContext@4 proc near ; CODE XREF: KiSwapThread()+33↓p
.text:00404828
.text:00404828 var_10 = dword ptr -10h
.text:00404828 var_C = dword ptr -0Ch
.text:00404828 var_8 = dword ptr -8
.text:00404828 var_4 = dword ptr -4
.text:00404828
.text:00404828 sub esp, 10h
.text:0040482B mov [esp+10h+var_4], ebx ; 保存当前寄存器的现场
.text:0040482F mov [esp+10h+var_8], esi
.text:00404833 mov [esp+10h+var_C], edi
.text:00404837 mov [esp+10h+var_10], ebp
.text:0040483A mov ebx, ds:0FFDFF01Ch ; SelfPcr, 即fs[0x1c], 指向_KPCR的指针
.text:00404840 mov esi, ecx ; ESI中存储的是要切换线程的_KTHREAD
.text:00404842 mov edi, [ebx+_KPCR.PrcbData.CurrentThread] ; 取出当前线程的_KTHREAD
.text:00404848 mov [ebx+_KPCR.PrcbData.CurrentThread], esi ; 更新CPU的_KTHREAD
.text:0040484E mov cl, [edi+58h]
.text:00404851 call SwapContext ; 切换线程上下文
.text:00404851 ; ESI指向要切换线程的_KTHREAD
.text:00404851 ; EDI指向当前线程的_KTHREAD
.text:00404851 ; EBX中存储的是SelfPcr, 指向_KPCR的指针
.text:00404856 mov ebp, [esp+10h+var_10] ; 恢复寄存器现场
.text:00404859 mov edi, [esp+10h+var_C]
.text:0040485D mov esi, [esp+10h+var_8]
.text:00404861 mov ebx, [esp+10h+var_4]
.text:00404865 add esp, 10h
.text:00404868 retn
.text:00404868 @KiSwapContext@4 endp
SwapContex
SwapContex
的逆向分析如下:
.text:00404924 ; =============== S U B R O U T I N E =======================================
.text:00404924
.text:00404924 ; ESI指向要切换线程的_KTHREAD
.text:00404924 ; EDI指向当前线程的_KTHREAD
.text:00404924 ; EBX中存储的是SelfPcr, 指向_KPCR的指针
.text:00404924
.text:00404924 SwapContext proc near ; CODE XREF: KiUnlockDispatcherDatabase(x)+72↑p
.text:00404924 ; KiSwapContext(x)+29↑p ...
.text:00404924 or cl, cl
.text:00404926 mov byte ptr es:[esi+_KTHREAD.State], 2 ; es寄存器是附加段寄存器, 更新当前线程的状态
.text:0040492B pushf ; 即 pushfd
.text:0040492C
.text:0040492C loc_40492C: ; CODE XREF: KiIdleLoop()+5A↓j
.text:0040492C mov ecx, [ebx+_KPCR.Nt_Tib.ExceptionList]
.text:0040492E cmp dword ptr [ebx+994h], 0
.text:00404935 push ecx ; 备份指向ExceptionList异常链表的指针
.text:00404936 jnz loc_404A70
.text:0040493C cmp ds:_PPerfGlobalGroupMask, 0
.text:00404943 jnz loc_404A47
.text:00404949
.text:00404949 loc_404949: ; CODE XREF: SwapContext+12B↓j
.text:00404949 ; SwapContext+13C↓j ...
.text:00404949 mov ebp, cr0
.text:0040494C mov edx, ebp
.text:0040494E mov cl, [esi+2Ch]
.text:00404951 mov [ebx+_KPCR.DebugActive], cl
.text:00404954 cli ; 屏蔽中断, 不被I/O事件, 时钟干扰
.text:00404955 mov [edi+_KTHREAD.KernelStack], esp ; 保存原线程的ESP
.text:00404958 mov eax, [esi+_KTHREAD.InitialStack]
.text:0040495B mov ecx, [esi+_KTHREAD.StackLimit]
.text:0040495E sub eax, 210h ; 将上边的浮点寄存器去掉,指向真正的栈顶
.text:00404963 mov [ebx+_KPCR.StackLimit], ecx ; 将新线程的堆栈属性写入_KPCR中
.text:00404966 mov [ebx+_KPCR.StackBase], eax
.text:00404969 xor ecx, ecx
.text:0040496B mov cl, [esi+_KPCR.Tcb.NpxState] ; NpxState浮点寄存器
.text:0040496E and edx, 0FFFFFFF1h ; 判断NpxState有没有浮点支持
.text:00404971 or ecx, edx
.text:00404973 or ecx, [eax+20Ch]
.text:00404979 cmp ebp, ecx
.text:0040497B jnz loc_404A3F
.text:00404981 lea ecx, [ecx]
.text:00404983
.text:00404983 loc_404983: ; CODE XREF: SwapContext+11E↓j
.text:00404983 test dword ptr [eax-1Ch], 20000h
.text:0040498A jnz short loc_40498F ; 判断是否是虚拟8086模式
.text:0040498C sub eax, 10h
.text:0040498F
.text:0040498F loc_40498F: ; CODE XREF: SwapContext+66↑j
.text:0040498F mov ecx, [ebx+_KPCR.TSS] ; 此时EAX指向0环栈顶,即EAX = ESP
.text:00404992 mov [ecx+_KTSS.ESP0], eax ; 将ESP0写入TSS
.text:00404995 mov esp, [esi+_KTHREAD.KernelStack] ; 将新线程的KernelStack写入ESP, 完成堆栈切换
.text:00404998 mov eax, [esi+_KTHREAD.Teb]
.text:0040499B mov [ebx+_KPCR.NtTib.Self], eax ; 更新_KPCR.NtTib.Self指向新线程的0环Teb
.text:0040499E sti ; 允许中断发生
.text:0040499F mov eax, [edi+_KTHREAD.ApcState.Process] ; 获取旧线程所属的资源进程的_KPROCESS结构体指针
.text:004049A2 cmp eax, [esi+_KTHREAD.ApcState.Process] ; 将旧线程所属资源进程_KPROCESS指针与新线程的指针相比较
.text:004049A2 ; 如果发生了跨进程切换线程则更换Cr3,否则不更换Cr3
.text:004049A5 mov byte ptr [edi+_KTHREAD.IdleSwapBlock], 0
.text:004049A9 jz short loc_4049D7 ; EAX将指向_KPCR
.text:004049AB mov edi, [esi+_KTHREAD.ApcState.Process] ; 发生了跨进程线程切换
.text:004049AB ; 更新EDI, 指向新线程的资源提供进程的_KPROCESS
.text:004049AE test word ptr [edi+_KTHREAD.Teb], 0FFFFh ; ExceptionList链表的地址的高位是否为0xffff
.text:004049B4 jnz short loc_404A11
.text:004049B6 xor eax, eax
.text:004049B8
.text:004049B8 loc_4049B8: ; CODE XREF: SwapContext+116↓j
.text:004049B8 lldt ax
.text:004049BB xor eax, eax
.text:004049BD mov gs, eax ; 将GS寄存器置为0,Windows并未使用GS寄存器
.text:004049BF assume gs:GAP
.text:004049BF mov eax, [edi+_KPROCESS.DirectoryTableBase] ; 获取新线程的Cr3
.text:004049C2 mov ebp, [ebx+_KPCR.TSS] ; 获取TSS
.text:004049C5 mov ecx, [edi+_KPROCESS.IOpmOffset]
.text:004049C8 mov [ebp+TSS.Cr3], eax ; 更新TSS中的Cr3
.text:004049CB mov cr3, eax ; 切换Cr3
.text:004049CE mov [ebp+I/O_Map_base_Address], cx
.text:004049D2 jmp short loc_4049D7 ; EAX将指向_KPCR
.text:004049D2 ; ---------------------------------------------------------------------------
.text:004049D4 db 8Dh, 49h, 0
.text:004049D7 ; ---------------------------------------------------------------------------
.text:004049D7
.text:004049D7 loc_4049D7: ; CODE XREF: SwapContext+85↑j
.text:004049D7 ; SwapContext+AE↑j
.text:004049D7 mov eax, [ebx+_KPCR.SelfPcr] ; EAX将指向_KPCR
.text:004049DA mov ecx, [ebx+_KPCR.GDT] ; ECX将指向GDT表
.text:004049DD mov [ecx+3Ah], ax ; 更新GDT表中的0x38处的段描述符的Base
.text:004049E1 shr eax, 10h ; 取EAX的高2字节
.text:004049E4 mov [ecx+3Ch], al ; 更新Base
.text:004049E7 mov [ecx+3Fh], ah ; 更新Base
.text:004049E7 ; 此时fs寄存器可以通过段选择子0x3B找到当前的段描述符
.text:004049EA inc dword ptr [esi+_KTHREAD.ContextSwitches]
.text:004049ED inc dword ptr [ebx+61Ch]
.text:004049F3 pop ecx ; ECX将指向_KPCR.Nt_Tib
.text:004049F4 mov [ebx], ecx ; 恢复新线程异常链表的地址
.text:004049F6 cmp byte ptr [esi+_KTHREAD.ApcState.KernelApcPending], 0
.text:004049FA jnz short loc_404A00
.text:004049FC popf
.text:004049FD xor eax, eax
.text:004049FF retn
.text:00404A00 ; ---------------------------------------------------------------------------
.text:00404A00
.text:00404A00 loc_404A00: ; CODE XREF: SwapContext+D6↑j
.text:00404A00 popf
.text:00404A01 jnz short loc_404A06
.text:00404A03 mov al, 1
.text:00404A05 retn
.text:00404A06 ; ---------------------------------------------------------------------------
.text:00404A06
.text:00404A06 loc_404A06: ; CODE XREF: SwapContext+DD↑j
.text:00404A06 mov cl, 1
.text:00404A08 call ds:__imp_@HalRequestSoftwareInterrupt@4 ; HalRequestSoftwareInterrupt(x)
.text:00404A0E xor eax, eax
.text:00404A10 retn
.text:00404A11 ; ---------------------------------------------------------------------------
.text:00404A11
.text:00404A11 loc_404A11: ; CODE XREF: SwapContext+90↑j
.text:00404A11 mov ebp, [ebx+_KPCR.GDT]
.text:00404A14 mov eax, [edi+20h]
.text:00404A17 mov [ebp+48h], eax
.text:00404A1A mov eax, [edi+24h]
.text:00404A1D mov [ebp+4Ch], eax
.text:00404A20 mov eax, 48h
.text:00404A25 mov ebp, [ebx+38h]
.text:00404A28 mov ecx, [edi+28h]
.text:00404A2B mov [ebp+108h], ecx
.text:00404A31 mov ecx, [edi+2Ch]
.text:00404A34 mov [ebp+10Ch], ecx
.text:00404A3A jmp loc_4049B8
.text:00404A3F ; ---------------------------------------------------------------------------
.text:00404A3F
.text:00404A3F loc_404A3F: ; CODE XREF: SwapContext+57↑j
.text:00404A3F mov cr0, ecx
.text:00404A42 jmp loc_404983
.text:00404A47 ; ---------------------------------------------------------------------------
.text:00404A47
.text:00404A47 loc_404A47: ; CODE XREF: SwapContext+1F↑j
.text:00404A47 mov eax, ds:_PPerfGlobalGroupMask
.text:00404A4C cmp eax, 0
.text:00404A4F jz loc_404949
.text:00404A55 mov edx, esi
.text:00404A57 mov ecx, edi
.text:00404A59 test dword ptr [eax+4], 4
.text:00404A60 jz loc_404949
.text:00404A66 call @WmiTraceContextSwap@8 ; WmiTraceContextSwap(x,x)
.text:00404A6B jmp loc_404949
.text:00404A70 ; ---------------------------------------------------------------------------
.text:00404A70
.text:00404A70 loc_404A70: ; CODE XREF: SwapContext+12↑j
.text:00404A70 push 0B8h ; BugCheckCode
.text:00404A75 call _KeBugCheck@4 ; KeBugCheck(x)
.text:00404A75 SwapContext endp
.text:00404A75