线程的被动切换——KiDispatchInterrupt & KiReadyThread&KiQuantumEnd逆向

介绍

  • 时钟中断在IDT中的中断号为0x30,他的IRQL是28
  • 如果想获取当前的时钟间隔值,可使用API GstSystemTimeAdjustment
  • 当一个线程的时限用完或者发生被抢占的情况下也会会发生线程切换,可以称之为被动切换,时钟中断的服务例程由HAL 提供,它调用了内核模块的KeUpdateSystemTime 函数。
  • 当时钟中断到来时,线程调度器获得控制权并不是直接在时钟中断处理函数中,而是在KiDispatchInterrupt 函数中。线程抢占和时限用完都发生在 KiDispatchInterrupt 函数中。在线程抢占的情形下,KiDispatchInterrupt 直接调用SwapContext 函数执行线程切换;而在时限用完的情形下,它将调用KiQuantumEnd 函数

KiDispatchInterrupt 逆向

.text:00404874                               public _KiDispatchInterrupt@0
.text:00404874                               _KiDispatchInterrupt@0 proc near        ; DATA XREF: .edata:off_5AC2A8↓o
.text:00404874 8B 1D 1C F0 DF FF             mov     ebx, ds:0FFDFF01Ch
.text:0040487A 8D 83 80 09 00 00             lea     eax, [ebx+_KPCR.PrcbData.DpcListHead] ; ebx = KPCR_SELFPCR
.text:0040487A                               _KiDispatchInterrupt@0 endp
.text:0040487A
.text:00404880 FA                            cli
.text:00404881 3B 00                         cmp     eax, [eax+_LIST_ENTRY.Flink]    ; 判断自己和链表下一个地址是否相同,也就是判断是否为空
.text:00404883 74 1D                         jz      short loc_4048A2                ; 如果为空
.text:00404883
.text:00404885 55                            push    ebp
.text:00404886 FF 33                         push    dword ptr [ebx]
.text:00404888 C7 03 FF FF FF FF             mov     [ebx+_KPCR.NtTib.ExceptionList], 0FFFFFFFFh
.text:0040488E 8B D4                         mov     edx, esp
.text:00404890 8B A3 88 09 00 00             mov     esp, [ebx+_KPCR.PrcbData.DpcStack]
.text:00404896 52                            push    edx
.text:00404897 8B E8                         mov     ebp, eax
.text:00404899 E8 F0 02 00 00                call    KiRetireDpcList                 ; 指定DPC处理列表

1.判断DPC链表是否为空,如果不为空则指定DPC处理列表

.text:004048A2 FB                            sti
.text:004048A3 83 BB AC 09 00 00 00          cmp     [ebx+_KPCR.PrcbData.QuantumEnd], 0 ; 判断QuantumEnd标志是否为空
.text:004048A3                                                                       ; 在系统时钟中断服务例程调用到
.text:004048A3                                                                       ; KeUpdateRunTime 函数时,若当前线
.text:004048A3                                                                       ; 程的时限已用完,则此标志被置上
.text:004048AA 75 56                         jnz     short loc_404902                ; 如果时间碎片未结束

.text:00404902 C7 83 AC 09 00 00 00 00 00 00 mov     dword ptr [ebx+9ACh], 0
.text:0040490C E8 35 BB 00 00                call    _KiQuantumEnd@0                 ; KiQuantumEnd()

2.判断时间碎片是否为空,如果不为空,则把QuantumEnd制空并通过KiQuantumEnd函数切换线程。

.text:004048BB                               loc_4048BB:                             ; CODE XREF: .text:00404913↓j
.text:004048BB 83 EC 0C                      sub     esp, 0Ch
.text:004048BE 89 74 24 08                   mov     [esp+8], esi
.text:004048C2 89 7C 24 04                   mov     [esp+4], edi
.text:004048C6 89 2C 24                      mov     [esp], ebp
.text:004048C9 8B F0                         mov     esi, eax
.text:004048CB 8B BB 24 01 00 00             mov     edi, [ebx+_KPCR.PrcbData.CurrentThread]
.text:004048D1 C7 83 28 01 00 00 00 00 00 00 mov     [ebx+_KPCR.PrcbData.NextThread], 0
.text:004048DB 89 B3 24 01 00 00             mov     [ebx+_KPCR.PrcbData.CurrentThread], esi ; 把下个线程放入当前线程
.text:004048E1 8B CF                         mov     ecx, edi
.text:004048E3 C6 47 50 01                   mov     [edi+_ETHREAD.Tcb.IdleSwapBlock], 1 ; 开启锁
.text:004048E7 E8 EE FD FF FF                call    @KiReadyThread@4                ; 把线程加入就绪列表中
.text:004048E7
.text:004048EC B1 01                         mov     cl, 1
.text:004048EE E8 31 00 00 00                call    SwapContext                     ; 进行线程环境交换
.text:004048EE
.text:004048F3 8B 2C 24                      mov     ebp, [esp]
.text:004048F6 8B 7C 24 04                   mov     edi, [esp+4]
.text:004048FA 8B 74 24 08                   mov     esi, [esp+8]
.text:004048FE 83 C4 0C                      add     esp, 0Ch
.text:004048FE
.text:00404901
.text:00404901                               locret_404901:                          ; CODE XREF: .text:004048B3↑j
.text:00404901 C3                            retn

3.然后判断KPCR是否选出下个进程,如果没有选出,则直接返回,如果选出则把选出的线程放入CurrentThread中,并通过KiReadyThread把线程放入就绪队列中,然后再通过SwapContext进行环境切换

KiReadyThread的逆向

.text:004046DA 8B FF                         mov     edi, edi
.text:004046DC 55                            push    ebp
.text:004046DD 8B EC                         mov     ebp, esp
.text:004046DF 51                            push    ecx
.text:004046E0 51                            push    ecx
.text:004046E1 8B C1                         mov     eax, ecx
.text:004046E3 8D 88 28 01 00 00             lea     ecx, [eax+_ETHREAD.Tcb.Preempted]
.text:004046E9 53                            push    ebx
.text:004046EA 8A 19                         mov     bl, [ecx]
.text:004046EC C6 01 00                      mov     byte ptr [ecx], 0               ; 设置抢占位为空
.text:004046EF 8B 15 00 B0 47 00             mov     edx, ds:_KeTickCount.LowPart    ; 获取当前时间
.text:004046F5 0F BE 48 33                   movsx   ecx, [eax+_ETHREAD.Tcb.Priority] ; 获取优先级
.text:004046F9 56                            push    esi
.text:004046FA 89 50 68                      mov     [eax+_ETHREAD.Tcb.WaitTime], edx ; 设置等待时间
.text:004046FD 8B 50 44                      mov     edx, [eax+_ETHREAD.Tcb.ApcState.Process]
.text:00404700 57                            push    edi
.text:00404700
.text:00404701
.text:00404701                               loc_404701:                             ; CODE XREF: KiReadyThread(x)-7↑j
.text:00404701 80 7A 65 00                   cmp     [edx+_EPROCESS.Pcb.State], ProcessInMemory ; 判断进程的状态是否处于内存中
.text:00404705 0F 85 18 19 03 00             jnz     loc_436023                      ; 如果被换出内存
.text:00404705
.text:0040470B 80 B8 2A 01 00 00 00          cmp     [eax+_ETHREAD.Tcb.KernelStackResident], 0 ; 判断线程是否驻留在内存中
.text:00404712 0F 84 1B CB 00 00             jz      loc_411233                      ; 如果被换出内存
.text:00404712
.text:00404718 C6 40 2D 03                   mov     [eax+_ETHREAD.Tcb.State], 3     ; 设置线程为备用状态
.text:0040471C 83 3D E4 AF 47 00 00          cmp     ds:_KiIdleSummary, 0            ; 判断KPCR是否活动状态
.text:00404723 8B 3D C0 30 48 00             mov     edi, ds:_KiProcessorBlock
.text:00404729 0F 85 4A A3 00 00             jnz     loc_40EA79
.text:00404729
.text:0040472F 8B 57 08                      mov     edx, [edi+_KPRCB.NextThread]
.text:00404732 85 D2                         test    edx, edx                        ; 判断下个线程是否为空
.text:00404734 0F 85 6A FF FF FF             jnz     loc_4046A4
.text:00404734
.text:0040473A 8B 57 04                      mov     edx, [edi+_KPRCB.CurrentThread]
.text:0040473D 0F BE 72 33                   movsx   esi, [edx+_ETHREAD.Tcb.Priority] ; 获取当前线程的优先级
.text:00404741 3B CE                         cmp     ecx, esi                        ; 比较优先级
.text:00404743 0F 8F 5C 8C 00 00             jg      loc_40D3A5
.text:00404743
.text:00404749
.text:00404749                               loc_404749:                             ; CODE XREF: KiReadyThread(x)-30↑j
.text:00404749 C6 40 2D 01                   mov     [eax+_ETHREAD.Tcb.State], 1
.text:0040474D 83 C0 60                      add     eax, 60h ; '`'
.text:00404750 84 DB                         test    bl, bl
.text:00404752 8D 14 CD A0 3A 48 00          lea     edx, _KiDispatcherReadyListHead[ecx*8] ; 找到线程优先级的调度链表
.text:00404759 0F 85 A6 D7 FF FF             jnz     loc_401F05
.text:00404759
.text:0040475F 8B 72 04                      mov     esi, [edx+4]
.text:00404762 89 10                         mov     [eax], edx
.text:00404764 89 70 04                      mov     [eax+4], esi
.text:00404767 89 06                         mov     [esi], eax
.text:00404769 89 42 04                      mov     [edx+4], eax                    ; 设置优先级
.text:00404769
.text:0040476C
.text:0040476C                               loc_40476C:                             ; CODE XREF: KiReadyThread(x)-27C9↑j
.text:0040476C 33 C0                         xor     eax, eax
.text:0040476E 40                            inc     eax
.text:0040476F D3 E0                         shl     eax, cl
.text:00404771 09 05 EC AF 47 00             or      ds:_KiReadySummary, eax
.text:00404771
.text:00404777
.text:00404777                               loc_404777:                             ; CODE XREF: KiReadyThread(x)-27DA↑j
.text:00404777                                                                       ; KiReadyThread(x)+CB8D↓j
.text:00404777                                                                       ; KiReadyThread(x)+3196B↓j
.text:00404777                                                                       ; .text:00446BFD↓j
.text:00404777 5F                            pop     edi
.text:00404778 5E                            pop     esi
.text:00404779 5B                            pop     ebx
.text:0040477A C9                            leave
.text:0040477B C3                            retn
.text:0040477B
.text:0040477B                               @KiReadyThread@4 endp

KiQuantumEnd 逆向

.text:00410446 8B FF                         mov     edi, edi
.text:00410448 55                            push    ebp
.text:00410449 8B EC                         mov     ebp, esp
.text:0041044B 51                            push    ecx
.text:0041044C 53                            push    ebx
.text:0041044D 56                            push    esi
.text:0041044E 57                            push    edi
.text:0041044F                               db      3Eh                             ; KPCR->Prcb
.text:0041044F 3E A1 20 F0 DF FF             mov     eax, ds:0FFDFF020h
.text:00410455 8B F8                         mov     edi, eax
.text:00410457 64 A1 24 01 00 00             mov     eax, large fs:_KPCR.PrcbData.CurrentThread ; 当前线程
.text:0041045D 8B F0                         mov     esi, eax
.text:0041045F FF 15 94 06 40 00             call    ds:__imp__KeRaiseIrqlToDpcLevel@0 ; 提升IRQL DISPATCH_LEVEL
.text:0041045F
.text:00410465 33 DB                         xor     ebx, ebx
.text:00410467 38 5E 6F                      cmp     [esi+_ETHREAD.Tcb.Quantum], bl
.text:0041046A 88 45 FF                      mov     [ebp+var_1], al
.text:0041046D 7F 40                         jg      short loc_4104AF                ; 如果时间碎片不为空

1.首先判断时间碎片是否为空,如果不为空则判断是否存在下个线程,如果存在则直接返回,不存在则执行KiUnlockDispatcherDatabase再返回

.text:0041046F 8B 46 44                      mov     eax, [esi+_ETHREAD.Tcb.ApcState.Process]
.text:00410472 38 58 69                      cmp     [eax+_EPROCESS.Pcb.DisableQuantum], bl
.text:00410475 0F 85 0B 66 03 00             jnz     loc_446A86                      ; 判断线程优先级

                                                                      ; .text:00446A99↓j
.text:004104AF 8B 77 08                      mov     esi, [edi+_KPRCB.NextThread]
.text:004104B2 3B F3                         cmp     esi, ebx                        ; 判断下一个线程是否为空
.text:004104B4 74 12                         jz      short loc_4104C8                ; 如果为空 
.text:004104B4
.text:004104B6
.text:004104B6                               loc_4104B6:                             ; CODE XREF: KiQuantumEnd()+8A↓j
.text:004104B6 5F                            pop     edi
.text:004104B7 8B C6                         mov     eax, esi
.text:004104B9 5E                            pop     esi
.text:004104BA 5B                            pop     ebx
.text:004104BB C9                            leave
.text:004104BC C3                            retn

2.然后判断线程时间碎片是否大于0,如果大于0则判断线程优先级是否0x10,如果大于0x10,设置线程时间碎片为0x7F,然后判断下个线程是否存在,如果不存在执行KiUnlockDispatcherDatabase结束

.text:0041047B                               loc_41047B:                             ; CODE XREF: KiQuantumEnd()+36644↓j
.text:0041047B 0F BE 56 33                   movsx   edx, [esi+_ETHREAD.Tcb.Priority]
.text:0041047F 83 FA 10                      cmp     edx, 10h
.text:00410482 8A 40 63                      mov     al, [eax+_EPROCESS.Pcb.ThreadQuantum]
.text:00410485 88 46 6F                      mov     [esi+_ETHREAD.Tcb.Quantum], al  ; 把时间碎片放入线程的时间碎片中
.text:00410488 8B C2                         mov     eax, edx
.text:0041048A 7D 14                         jge     short loc_4104A0                ; 如果优先级大于等于0x10
.text:0041048A
.text:0041048C 0F BE 4E 6E                   movsx   ecx, [esi+_ETHREAD.Tcb.PriorityDecrement] ; PriorityDecrement
.text:00410490 2B C1                         sub     eax, ecx                        ; 优先级-=动态优先级
.text:00410492 0F BE 4E 6C                   movsx   ecx, [esi+_ETHREAD.Tcb.BasePriority] ; 线程的静态优先级
.text:00410496 48                            dec     eax                             ; 优先级-1
.text:00410497 3B C1                         cmp     eax, ecx                        ; 比较优先级和动态优先级
.text:00410499 7D 02                         jge     short loc_41049D                ; 如果大于
.text:00410499
.text:0041049B 8B C1                         mov     eax, ecx                        ; 如果不大于则动态优先级覆盖优先级
.text:0041049B
.text:0041049D
.text:0041049D                               loc_41049D:                             ; CODE XREF: KiQuantumEnd()+53↑j
.text:0041049D 88 5E 6E                      mov     [esi+_ETHREAD.Tcb.PriorityDecrement], bl ; 置0动态优先级
.text:0041049D
.text:004104A0
.text:004104A0                               loc_4104A0:                             ; CODE XREF: KiQuantumEnd()+44↑j
.text:004104A0 3B D0                         cmp     edx, eax                        ; 判断eax==edx 此时是相等的
.text:004104A2 75 19                         jnz     short loc_4104BD
.text:004104A2
.text:004104A4 39 5F 08                      cmp     [edi+_KPRCB.NextThread], ebx    ; 判断是否存在下个线程
.text:004104A7 74 29                         jz      short loc_4104D2                ; 如果不存在则寻址一个就绪线程,然后结束
.text:004104A7
.text:004104A9 88 9E 28 01 00 00             mov     [esi+_ETHREAD.Tcb.Preempted], bl ; 设置此线程不被高优先级线程抢占
.text:004104A9
.text:004104AF
.text:004104AF                               loc_4104AF:                             ; CODE XREF: KiQuantumEnd()+27↑j
.text:004104AF                                                                       ; KiQuantumEnd()+80↓j
.text:004104AF                                                                       ; KiQuantumEnd()+9A↓j
.text:004104AF                                                                       ; KiQuantumEnd()+A3↓j
.text:004104AF                                                                       ; KiQuantumEnd()+3664E↓j
.text:004104AF                                                                       ; .text:00446A99↓j
.text:004104AF 8B 77 08                      mov     esi, [edi+_KPRCB.NextThread]
.text:004104B2 3B F3                         cmp     esi, ebx                        ; 判断下一个线程是否为空
.text:004104B4 74 12                         jz      short loc_4104C8                ; 如果为空 
.text:004104B4
.text:004104B6
.text:004104B6                               loc_4104B6:                             ; CODE XREF: KiQuantumEnd()+8A↓j
.text:004104B6 5F                            pop     edi
.text:004104B7 8B C6                         mov     eax, esi
.text:004104B9 5E                            pop     esi
.text:004104BA 5B                            pop     ebx
.text:004104BB C9                            leave
.text:004104BC C3                            retn

3.如果不大于0X10,则刷新线程的时间碎片,再判断优先级是否大于0x10,然后查看此时的线程动态优先级是否大于优先级,如果大于则覆盖,动态优先级清空,然后执行到不大于的步骤中,如果不大于则判断是否存在下个进程,如果不存在则寻址下个就绪线程,如果存在设置此线程不能被高优先级的线程抢占,然后结束,如果存在则执行KiUnlockDispatcherDatabase结束

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值