6.windows線程切換_主動切換

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

看到這裏是不是感覺似曾相識,沒錯跟我們模擬的那個是類似的只不過有很多的細節沒有模擬。

總結:

  1. Windows中絕大部分API都調用了SwapContext函數也就是說,當線程只要調用了API,就是導致線程切換。
  2. 線程切換時會比較是否屬於同一個進程,如果不是,切換Cr3Cr3換了,進程也就切換了。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章