线程的切换分为主动切换和被动切换两种方式
主动切换主要是通过KiSwapThread进行的。
KiSwapThread逆向
.text:004050BF 8B FF mov edi, edi
.text:004050C1 56 push esi
.text:004050C2 57 push edi
.text:004050C3 db 3Eh ; eax=prcb
.text:004050C3 3E A1 20 F0 DF FF mov eax, ds:0FFDFF020h
.text:004050C9 8B F0 mov esi, eax
.text:004050CB 8B 46 08 mov eax, [esi+_KPRCB.NextThread]
.text:004050CE 85 C0 test eax, eax ; 判断是否为空
.text:004050D0 8B 7E 04 mov edi, [esi+_KPRCB.CurrentThread]
.text:004050D3 0F 85 D6 B8 00 00 jnz loc_4109AF
1.首先判断下个线程是否为空
.text:004050D9 53 push ebx
.text:004050DA 0F BE 5E 10 movsx ebx, [esi+_KPRCB.Number] ; 判断kpcr在哪个核上
.text:004050DE 33 D2 xor edx, edx
.text:004050E0 8B CB mov ecx, ebx
.text:004050E2 E8 6B FF FF FF call @KiFindReadyThread@8 ; 寻找一个可以执行在当前核上的线程
.text:004050E2
.text:004050E7 85 C0 test eax, eax ; 判断是否找到
.text:004050E9 0F 84 96 99 00 00 jz loc_40EA85 ; 空闲线程
2.寻找到一个可以运行在当前核上的线程,通过KiFindReadyThread在就绪态的线程中寻找,如果找不到则在空闲线程中寻址。无论通过哪种方式eax等于下个线程的位置
.text:004050EF 5B pop ebx
.text:004050EF
.text:004050F0
.text:004050F0 loc_4050F0: ; CODE XREF: KiSwapThread()+B8F4↓j
.text:004050F0 8B C8 mov ecx, eax ; 下一个线程
.text:004050F2 E8 31 F7 FF FF call @KiSwapContext@4 ; KiSwapContext(x)
3.然后调用KiSwapContext进行上下文的交换,最后再进行一些寄存器值的交换,到这里线程切换结束。
KiSwapContext逆向
.text:00404828 83 EC 10 sub esp, 10h
.text:0040482B 89 5C 24 0C mov [esp+10h+var_4], ebx
.text:0040482F 89 74 24 08 mov [esp+10h+var_8], esi ; ecx 下一个线程
.text:00404833 89 7C 24 04 mov [esp+10h+var_C], edi
.text:00404837 89 2C 24 mov [esp+10h+var_10], ebp
.text:0040483A 8B 1D 1C F0 DF FF mov ebx, ds:0FFDFF01Ch ; kpcr.selfpcr
.text:00404840 8B F1 mov esi, ecx
.text:00404842 8B BB 24 01 00 00 mov edi, [ebx+_KPCR.PrcbData.CurrentThread]
.text:00404848 89 B3 24 01 00 00 mov [ebx+_KPCR.PrcbData.CurrentThread], esi ; 把当前线程设为下个线程
.text:0040484E 8A 4F 58 mov cl, [edi+_ETHREAD.Tcb.WaitIrql] ; 等待Irpl
.text:00404851 E8 CE 00 00 00 call SwapContext
.text:00404851
.text:00404856 8B 2C 24 mov ebp, [esp+10h+var_10]
.text:00404859 8B 7C 24 04 mov edi, [esp+10h+var_C]
.text:0040485D 8B 74 24 08 mov esi, [esp+10h+var_8]
.text:00404861 8B 5C 24 0C mov ebx, [esp+10h+var_4]
.text:00404865 83 C4 10 add esp, 10h
.text:00404868 C3 retn
4.KiSwapContext首先把KPCR结构中的CurrentThread设置为寻找到的新线程,然后调用SwapContext
SwapContext
.text:00404924 0A C9 or cl, cl
.text:00404926 26 C6 46 2D 02 mov es:[esi+_ETHREAD.Tcb.State], 2 ; 修改线程的状态
.text:00404926 ; esi等于下个线程
.text:0040492B 9C pushf
.text:0040492B
.text:0040492C
.text:0040492C loc_40492C: ; CODE XREF: KiIdleLoop()+5A↓j
.text:0040492C 8B 0B mov ecx, [ebx+_KPCR.NtTib.ExceptionList]
.text:0040492E 83 BB 94 09 00 00 00 cmp [ebx+_KPCR.PrcbData.DpcRoutineActive], 0 ; 判断当前cpu是否正在执行dpc
.text:00404935 51 push ecx ; 异常链压栈
.text:00404936 0F 85 34 01 00 00 jnz loc_404A70 ; 如果dpc执行,则kebugcheck蓝屏
.text:00404936
.text:0040493C 83 3D 0C B1 48 00 00 cmp ds:_PPerfGlobalGroupMask, 0
.text:00404943 0F 85 FE 00 00 00 jnz loc_404A47
5.SwapContext首先修改线程的状态,然后判断DpcRoutineActive和PPerfGlobalGroupMask。
.text:00404949 0F 20 C5 mov ebp, cr0
.text:0040494C 8B D5 mov edx, ebp
.text:0040494E 8A 4E 2C mov cl, [esi+_ETHREAD.Tcb.DebugActive]
.text:00404951 88 4B 50 mov [ebx+_KPCR.DebugActive], cl ; 设置KPCR的DebugActive
.text:00404954 FA cli ; 关中断
.text:00404955 89 67 28 mov [edi+_ETHREAD.Tcb.KernelStack], esp ; 保存之前的esp
.text:00404955 ; edi交换之前的线程
.text:00404958 8B 46 18 mov eax, [esi+_ETHREAD.Tcb.InitialStack]
.text:0040495B 8B 4E 1C mov ecx, [esi+_ETHREAD.Tcb.StackLimit]
.text:0040495E 2D 10 02 00 00 sub eax, 210h ; init陷阱桢大小
.text:00404963 89 4B 08 mov [ebx+_KPCR.NtTib.StackLimit], ecx
.text:00404966 89 43 04 mov [ebx+_KPCR.NtTib.StackBase], eax ; 初始化栈
.text:00404969 33 C9 xor ecx, ecx
.text:0040496B 8A 4E 31 mov cl, [esi+_ETHREAD.Tcb.NpxState] ; 浮点寄存器状态
.text:0040496E 83 E2 F1 and edx, 0FFFFFFF1h ; 关闭CR0的一些位
.text:00404971 0B CA or ecx, edx
.text:00404973 0B 88 0C 02 00 00 or ecx, [eax+_FX_SAVE_AREA.Cr0NpxState]
.text:00404979 3B E9 cmp ebp, ecx ; 判断Cr0NpxState和cr0de值是否相等
.text:0040497B 0F 85 BE 00 00 00 jnz loc_404A3F ; 不相等则赋值给cr0
.text:0040497B
.text:00404981 8D 09 lea ecx, [ecx]
6.设置DebugActive,并对CR0进行一些列操作
.text:00404983 loc_404983: ; CODE XREF: SwapContext+11E↓j
.text:00404983 F7 40 E4 00 00 02 00 test dword ptr [eax-1Ch], 20000h ; 陷阱桢-1c == EFLAGS
.text:0040498A 75 03 jnz short loc_40498F ; 判断是否虚拟模式
.text:0040498A
.text:0040498C 83 E8 10 sub eax, 10h ; eax = HardwareSegSs
.text:0040498C
.text:0040498F
.text:0040498F loc_40498F: ; CODE XREF: SwapContext+66↑j
.text:0040498F 8B 4B 40 mov ecx, [ebx+_KPCR.TSS]
.text:00404992 89 41 04 mov [ecx+_KTSS.Esp0], eax ; esp0 = HardwareSegSs
.text:00404995 8B 66 28 mov esp, [esi+_ETHREAD.Tcb.KernelStack]
.text:00404998 8B 46 20 mov eax, [esi+_ETHREAD.Tcb.Teb]
.text:0040499B 89 43 18 mov [ebx+_KPCR.NtTib.Self], eax ; teb放入 nttib
.text:0040499E FB sti
7.进行堆栈初始化以及堆栈修改操作
.text:0040499F 8B 47 44 mov eax, [edi+_ETHREAD.Tcb.ApcState.Process]
.text:004049A2 3B 46 44 cmp eax, [esi+_ETHREAD.Tcb.ApcState.Process] ; 判断新线程和旧线程是否处于同一个进程中
.text:004049A5 C6 47 50 00 mov [edi+_ETHREAD.Tcb.IdleSwapBlock], 0 ; 设置锁
.text:004049A9 74 2C jz short loc_4049D7
.text:004049AB 8B 7E 44 mov edi, [esi+_ETHREAD.Tcb.ApcState.Process]
.text:004049AE 66 F7 47 20 FF FF test [edi+_EPROCESS.Pcb.LdtDescriptor.LimitLow], 0FFFFh
.text:004049B4 75 5B jnz short loc_404A11 ; 判断是否dos系统
.text:004049B4
.text:004049B6 33 C0 xor eax, eax
.text:004049B6
.text:004049B8
.text:004049B8 loc_4049B8: ; CODE XREF: SwapContext+116↓j
.text:004049B8 0F 00 D0 lldt ax ; 加载LDTR段描述符 0
.text:004049BB 33 C0 xor eax, eax
.text:004049BD 8E E8 mov gs, eax
.text:004049BF assume gs:GAP
.text:004049BF 8B 47 18 mov eax, [edi+_EPROCESS.Pcb.DirectoryTableBase] ; 活动新线程的活动进程的cr3
.text:004049C2 8B 6B 40 mov ebp, [ebx+_KPCR.TSS]
.text:004049C5 8B 4F 30 mov ecx, dword ptr [edi+_EPROCESS.Pcb.IopmOffset] ; IOPM位置(I/O权限表)
.text:004049C8 89 45 1C mov [ebp+_KTSS.CR3], eax ; 修改CR3
.text:004049CB 0F 22 D8 mov cr3, eax
.text:004049CE 66 89 4D 66 mov [ebp+_KTSS.IoMapBase], cx ; 填入I/O权限表
.text:004049D2 EB 03 jmp short loc_4049D7
.text:004049D7 loc_4049D7: ; CODE XREF: SwapContext+85↑j
.text:004049D7 ; SwapContext+AE↑j
.text:004049D7 8B 43 18 mov eax, [ebx+_KPCR.NtTib.Self]
.text:004049DA 8B 4B 3C mov ecx, [ebx+_KPCR.GDT]
.text:004049DD 66 89 41 3A mov [ecx+3Ah], ax
.text:004049E1 C1 E8 10 shr eax, 10h
.text:004049E4 88 41 3C mov [ecx+3Ch], al
.text:004049E7 88 61 3F mov [ecx+3Fh], ah ; 修改fs
.text:004049EA FF 46 4C inc [esi+_ETHREAD.Tcb.ContextSwitches] ; 环境切换次数加1
.text:004049ED FF 83 1C 06 00 00 inc [ebx+_KPCR.PrcbData.KeContextSwitches] ; KPCR记录的切换次数+1
.text:004049F3 59 pop ecx
.text:004049F4 89 0B mov [ebx+_KPCR.NtTib.ExceptionList], ecx ; 修改异常链
.text:004049F6 80 7E 49 00 cmp [esi+_ETHREAD.Tcb.ApcState.KernelApcPending], 0 ; 判断有内核模式APC 对象正在等待交付
.text:004049FA 75 04 jnz short loc_404A00
.text:004049FA
.text:004049FC 9D popf
.text:004049FD 33 C0 xor eax, eax
.text:004049FF C3 retn
8.判断新线程和旧线程是否在一个进程内,如果在一个进程内,修改FS设置一些值返回。如果不在一个进程内,则修改CR3并在tss中填入IOPM位置