• 九.Windows内核保护机制--TSS


    一.什么是TSS:

      TSS全称Task State Segment,中文名任务状态段,储存在内存中,大小104个字节,结构如下:(每个CPU,就是每个核,都有一个TSS,但是每个线程都有自己的ESP0Ktrap_frame 结构体)

      

     二.TSS原本的作用:

      TSS在任务(线程)切换时起着重要的作用,通过它保存CPU中各寄存器的值,实现任务的挂起和恢复。

      比如说,当CPU执行A进程的时间片用完,要切换到B进程时,CPU会先把当前寄存器里的值保存到A进程的TSS里(任务寄存器TR指向当前进程的TSS),比如CS,EIP,ESP,标志寄存器等等,然后挂起A进程。执行B进程。这样,在CPU下次执行A进程的时候,就可以从其TSS中取出,CPU就知道上一次A进程执行到了什么位置,执行状态等等,这样就恢复了上次A进程的执行现场。(但是Windows和Linux并没有使用TSS进行任务切换的工作,是使用的堆栈来实现的任务(也就是线程)的切换.但是在执行调用门操作的时候,ESPSS的值就是通过TSS来自动进行切换的.)

    三.CPU如何调用TSS:

      CPU中有一个TR段寄存器,存出一个段描述符,存在于GDT段描述符表中,属于系统段描述符的一种,base指向TSS表的地址,limit表示他的偏移范围.

    四.我们对于TSS的调用:

      1.申请内存空间,自己写一个TSS表(104字节),并为表中的寄存器赋值.

      2.修改GDT表中的段描述符,让其Base指向我们自己的TSS表

      3.CALL FAR 或者 JMP FAR,跳到段描述符,使用我们的TSS表.(会先自动改写TR寄存器,不需要LTR在改了.)

        1)也可以通过LTR指令:修改TR寄存器的段选择子,让TR寄存器指向GDT表中我们改写的TR段描述符.(LTR是系统指令,只有在R0层,才能使用)

            mov ax,4B(GDT中,自己写的段描述符)

            ltr ax

      *加载后TSS段描述符状态会更改(就是上图的B位),TYPE的值由1001变为1011.

      *如果要读TR寄存器的值,也就是段选择子,可以用STR指令.

      上述操作完成,可以一次性改写一堆寄存器,在指向TSS表的时候,我们可以使用CALL FAR 和JMP FAR指令来进行,需要注意的是二者的区别,  CALL FAR后NT位为1,返回时,EIP会取Previous Task Link的值,JMP FAR后NT位为0,返回时,EIP从堆栈中取值.

    五.Intel设计TSS的目的是为了任务切换(线程切换),但Windows与Linux , 并没有使用。而是采用堆栈来保存线程的各种寄存器。

      一个CPU只有一个TSS.但是线程很多,如何用一个TSS来保存所有线程的ESP0呢?

      下面来看看SwapContext代码分析:

    SwapContext     proc near               ; CODE XREF: KiUnlockDispatcherDatabase(x)+72p
                                            ; KiSwapContext(x)+29p ...
                    or      cl, cl
                    mov es:[esi+_ETHREAD.Tcb.State],2 ; _KTHREAD(+0x2d state)改为2
                    pushf                   ; 存储当前的EFLAGS寄存器
     
    loc_40492C:                             ; CODE XREF: KiIdleLoop()+5Aj
                    mov ecx,[ebx+KPCR+NtTib.ExceptionList] ; ebx存储KPCR的地址 此处是读出异常链表 3环的FS:[0]
                    cmp [ebx+KPCR.PrcbData.DpcRoutineActive],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+_ETHREAD.Tcb.KernelStack],esp ; 将当前的esp存储到原线程结构中
                    mov eax,[_ETHREAD.Tcb.InitialStack] ; 目标线程栈底
                    mov ecx,[esi+_ETHREAD.Tcb.StackLimt]
                    sub     eax, 210h       ; -210h 浮点寄存器
                    mov [ebx+KPCR.NtTib.StackLimit],ecx
                    mov [ebx+KPCR.NtTib.StackBase],eax
                    xor     ecx, ecx
                    mov cl,[esi+_ETHREAD.Tcb.NpxState] ; NpxState 浮点寄存器 运行浮点用这个 没运行就不用
                    and     edx, 0FFFFFFF1h ; 判断NpxState有没有浮点支持
                                            ; 如果上一个线程和要替换的线程对浮点支持是一样的那就不用换CP0 如果不一样
                    or      ecx, edx
                    or      ecx, [eax+20Ch]
                    cmp     ebp, ecx
                    jnz     loc_404A3F
                    lea     ecx, [ecx]
     
    loc_404983: 
                    test    dword ptr [eax-1Ch], 20000h
                    jnz     short loc_40498F ; 通过KPCR取出TSS
                    sub     eax, 10h        ; 再减去10h(虚拟8086模式下使用 TrapFrame结构)
     
    loc_40498F:
                    mov ecx,[ebx+KPCR.TSS]  ; 通过KPCR取出TSS
                    mov     [ecx+4], eax    ; 将修正后的栈底储存到TSS中
                    mov esp,[_ETHREAD.Tcb.KernelStatck] ; 将目标线程的ESP存储到ESP中
                    mov eax,[esi+_ETHREAD.Tcb.Teb] ; 当前线程有很多状态一份在ETHREAD里面
                                            ; 还有一个备份在FS中
                    mov ecx,[ebx+KPCR.TSS]  ; 通过KPCR取TSS
                    sti
                    mov eax,[edi+_ETHREAD.Tcb.ApcState.Process]
                    cmp eax,[esi+_ETHREAD.Tcb.ApcState.Process]
                    mov [edi+_ETHREAD.Tcb.IdleSwapBlock],0
                    jz      short loc_4049D7 ; 如果是一个进程内的线程切换 跳转
                    mov edi,[esi+_ETHREAD.Tcb.ApcState.Process] ; 如果不是一个进程 取出目标线程_KPROCESS
                    test [edi+_ETHREAD.pcb.LdtDescriptor.LimitLow],0FFFFh ; 判断LdtDescriptor是否为-1
                    jnz     short loc_404A11
                    xor     eax, eax
     
    loc_4049B8: 
                    lldt    ax
                    xor     eax, eax
                    mov     gs, eax         ; GS段寄存器清0 这个能解释清除 位什么在3环单步执行 GS会清0
                    assume gs:GAP
                    mov eax,[edi+_EPROCESS.Pcb.DirectoryTableBase] ; 得到目标线程CR3
                    mov ebp,[ebx+KPCR.TSS]  ; TSS寄存器
                    mov ecx,dword ptr[edi+_EPROCESS.Pcb.IopmOffset]
                    mov     [ebp+1Ch], eax  ; 将当前TSS中的CR3修改为目标进程的CR3
                    mov     cr3, eax        ; 切换CR3
                    mov     [ebp+66h], cx   ; 存储IO权限位图到TSS 当前线程的IO权限位图 Windows2000以后不用了
                    jmp     short loc_4049D7
    ; ---------------------------------------------------------------------------
                    db 8Dh, 49h, 0
    ; ---------------------------------------------------------------------------
     
    loc_4049D7: 
                    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
  • 相关阅读:
    开源框架/软件汇总
    如何查看Maven项目的jar包依赖
    我的前端技术栈(2018版)
    解决在Mac上用pyenv安装python3失败的问题
    学习jenv
    学习sbtenv
    解决MAC下修改系统文件没权限的问题
    学习Spring Boot
    学习音标
    C# 对List中的Object进行排序
  • 原文地址:https://www.cnblogs.com/jszyx/p/12431773.html
Copyright © 2020-2023  润新知