ida 分析KiSwapThread
sub esp, 10h
mov [esp+10h+var_4], ebx ;保存当前线程寄存器现场
mov [esp+10h+var_8], esi
mov [esp+10h+var_C], edi
mov [esp+10h+var_10], ebp
mov ebx, ds:0FFDFF01Ch
mov esi, ecx ;ESI中存储的是要切换线程的_KTHREAD(ecx是别的地方传过来的)
mov edi, [ebx+KPCR.PrcbData.CurrentThread];取出运行当前代码的线程的_KTHREAD
mov [ebx+KPCR.PrcbData.CurrentThread], esi
mov cl, [edi+58h]
call SwapContext ;真正的线程切换函数
mov ebp, [esp+10h+var_10];恢复新线程各种寄存器
mov edi, [esp+10h+var_C]
mov esi, [esp+10h+var_8]
mov ebx, [esp+10h+var_4]
add esp, 10h
retn
查看有多少处调用,选中函数->view->Open subviews->cross refer…
只要调用这里面的api都会导致线程切换,windows的api绝大多数都会调用这里面的api
ecx来源
@KiSwapThread@0 proc near
mov edi, edi
push esi
push edi
db 3Eh
mov eax, ds:0FFDFF020h
mov esi, eax
mov eax, [esi+8]
test eax, eax
mov edi, [esi+4]
jnz loc_4109AF
push ebx
movsx ebx, byte ptr [esi+10h]
xor edx, edx
mov ecx, ebx
call @KiFindReadyThread@8 ;该函数返回一个_KTHREAD eax来源
test eax, eax
jz loc_40EA85
pop ebx
mov ecx, eax ;eac来源,eax来源上面的call
call @KiSwapContext@4 ; 寄存器传参 参数是KiFindReadyThread找到的结构体
test al, al
mov cl, [edi+58h] ; NewIrql
mov edi, [edi+54h]
mov esi, ds:__imp_@KfLowerIrql@4 ; KfLowerIrql(x)
jnz loc_415ADB
call esi ;
mov eax, edi
pop edi
pop esi
retn
call SwapContext ;真正的线程切换函数
SwapContext proc near ; CODE XREF: KiUnlockDispatcherDatabase(x)+72p
; KiSwapContext(x)+29p ...
or cl, cl
mov byte ptr es:[esi+2Dh], 2 ; 1就绪 2运行 5等待
pushf ; 保持EFLAGS寄存器
loc_40492C: ; CODE XREF: KiIdleLoop()+5Aj
mov ecx, [ebx] ; 保存本线程切换时的内核SEH链表
cmp dword ptr [ebx+994h], 0 ; 是否有DPC有就蓝屏
push ecx
jnz loc_404A70
cmp ds:_PPerfGlobalGroupMask, 0 ; log用的windows自己调试用的别的地方没用
jnz loc_404A47
loc_404949: ; CODE XREF: SwapContext+12Bj
; SwapContext+13Cj ...
mov ebp, cr0 ; CR0中的保存控制位
mov edx, ebp
mov cl, [esi+2Ch]
mov [ebx+50h], cl
cli
mov [edi+28h], esp ; 当前的ESP存储到原线程结构中
mov eax, [esi+18h] ; 目标线程栈顶
mov ecx, [esi+1Ch]
sub eax, 210h
mov [ebx+8], ecx
mov [ebx+4], eax
xor ecx, ecx
mov cl, [esi+31h]
and edx, 0FFFFFFF1h
or ecx, edx
or ecx, [eax+20Ch]
cmp ebp, ecx
jnz loc_404A3F
lea ecx, [ecx]
loc_404983: ; CODE XREF: SwapContext+11Ej
test dword ptr [eax-1Ch], 20000h
jnz short loc_40498F ; 取出TSS(tss就是从3环向0环切的时候去TSS中取ESP0和SS0别的没用)
sub eax, 10h
loc_40498F: ; CODE XREF: SwapContext+66j
mov ecx, [ebx+40h] ; 取出TSS(tss就是从3环向0环切的时候去TSS中取ESP0和SS0别的没用)
mov [ecx+4], eax ; 将修正后的栈顶存储到tss中
mov esp, [esi+28h] ; 将目标线程的ESP存储到ESP中
mov eax, [esi+20h] ; 当前线程有很多状态一份在ETHREAD里面还有一个备份在FS中
; 这样做的好处就是可以在3环通过FS获取当前线程信息
mov [ebx+18h], eax ; 临时存储目标的TEB
sti
mov eax, [edi+44h] ; 40h =_ETHREAD.Tcb.ApcState.Process
cmp eax, [esi+44h] ; 40h=_ETHREAD.Tcb.ApcState.Process
mov byte ptr [edi+50h], 0
jz short loc_4049D7
mov edi, [esi+44h]
test word ptr [edi+20h], 0FFFFh
jnz short loc_404A11
xor eax, eax
loc_4049B8: ; CODE XREF: SwapContext+116j
lldt ax
xor eax, eax
mov gs, eax
assume gs:GAP
mov eax, [edi+18h]
mov ebp, [ebx+40h]
mov ecx, [edi+30h]
mov [ebp+1Ch], eax
mov cr3, eax
mov [ebp+66h], cx
jmp short loc_4049D7
; ---------------------------------------------------------------------------
db 8Dh, 49h, 0
; ---------------------------------------------------------------------------
loc_4049D7: ; CODE XREF: SwapContext+85j
; SwapContext+AEj
mov eax, [ebx+18h]
mov ecx, [ebx+3Ch]
mov [ecx+3Ah], ax
shr eax, 10h
mov [ecx+3Ch], al
mov [ecx+3Fh], ah
inc dword ptr [esi+4Ch]
inc dword ptr [ebx+61Ch]
pop ecx
mov [ebx], ecx
cmp byte ptr [esi+49h], 0
jnz short loc_404A00
popf
xor eax, eax
retn
看到这里是不是感觉似曾相识,没错跟我们模拟的那个是类似的只不过有很多的细节没有模拟。
总结: