任务段与任务门

Posted onetrainee

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了任务段与任务门相关的知识,希望对你有一定的参考价值。

Windows内核分析索引目录:https://www.cnblogs.com/onetrainee/p/11675224.html

任务段与任务门

索引:

1.任务段

2.如何加载一个段寄存器和取出段寄存器

3.TSS的作用(在Windows操作系统上)

4.如何查看TSS段内容

5.构造TSS门并进行提权

6.使用int3指令断下观察esp的实验(出现一个elfags标志位的坑)

7.int3断下时,如果不回复eflags寄存器,其就会卡死

8.任务门的作用(在Windows操作系统上)

9.任务门实验

 

解答:

1.  任务段

   任务段是系统段的一种,Windows操作系统只运行一个(启动时就已经确定)
    技术图片

    查看对应的任务段的属性,当切换进执行程序时,其会将任务段属性改为繁忙,
    可以看出下表红色的位置。
    技术图片

    tr 寄存器表示当前的任务段,我们可以使用windbg 的 dg指令解析该段

  技术图片

 

2. 如何加载一个段寄存器和取出段寄存器
    加载段寄存器 load (零环)
    mov ax,0x28
    ltr ax
    取出段寄存器 store (三环)
    str dword ds:[0x12345678]
    获取gdt:  sgdt (三环)  加载gdt: lgdt (零环)
 获取idt: sidt ……………

 3. TSS的作用(在Windows操作系统上)
    线程切换时,一次保存多个寄存器。
    注意:是线程切换,不是进程切换,进程切换还要替换整个环境远不止寄存器那么多!!


4. 如何查看TSS段内的内容
    TSS的地址就是TSS段描述符描述的基地址,因此我们通过 dg tr 查看其Base为 80042000。
    对于查看TSS段,有一个单独的指令。
    dt _KTSS base_address
    效果如下图(此时没用到,之后线程切换会有新的效果)

   技术图片

 

 5. 构造tss门并进行提权
  1)实验代码

    
        // test.cpp : Defines the entry point for the console application.
        //
        
        #include "stdafx.h"
        #include "windows.h"
        
        DWORD iTSS[26];
        DWORD ESP0[0x1000];
        DWORD ESP3[0x1000];
        
        DWORD dwESP;
        DWORD dwCS;
        DWORD dwCR3;
        
        _declspec(naked) void Call(){
            _asm{
            
                mov dwESP,ESP;
                mov ax,cs;
                mov dwCS,eax;
        
                iretd;
            }
        }
        int main(int argc, char* argv[])
        {
            memset(iTSS,0,sizeof(iTSS));
            memset(ESP0,0,sizeof(ESP0));
            memset(ESP3,0,sizeof(ESP3));
        
            dwESP = 0;
            dwCS = 0;
            dwCR3 = 0;
        
            iTSS[1] = (DWORD)(ESP0+0x900);    // ESP
            iTSS[2] = 0x10;                    // SS0
            iTSS[8] = (DWORD)Call;            // EIP
            iTSS[14] = (DWORD)(ESP3+0x900); // ESP3
            iTSS[18] = 0x23;    // ES
            iTSS[19] = 0x08;    // CS
            iTSS[20] = 0x10;    // SS
            iTSS[21] = 0x23;    // DS
            iTSS[22] = 0x30;    // FS
        
            printf("iTSS:%x ESP3:%x ESP0:%x
",iTSS,(ESP3+0x900),(ESP0+0x900));
            printf("input cr3:");
            scanf("%x",&dwCR3);
            iTSS[7] = dwCR3;        // cr3
        
            char buf[6] = {0,0,0,0,0x48,0};
            _asm{
                call fword ptr buf;
            }
            printf("ESP:%x CS:%x
",dwESP,dwCS);
            return 0;
            return 0;
}

  2)查看TSS的内存地址,然后来修改任务门的偏移量(注意之前为函数地址,但任务门是一次性替换全部寄存器,因此函数地址在tss的eip中)。

    技术图片

     0x48偏移处构造,windbg指令 eq 8003f048 0000e943`2c680068

  3)使用 !process 0 0 找到对应的CR3(物理页处),然后输入进去。

    技术图片

   4)可以看到其直接使用了三环的esp(虽然我们权限是零环,但它并没有使用零环esp,而是直接替换目录中的esp)。

    技术图片

 

 6. 使用int3指令断下观察esp的实验(出现一个eflags标志位的坑)

    //
    
    #include "stdafx.h"
    #include "windows.h"
    
    DWORD iTSS[26];
    DWORD ESP0[0x1000];
    DWORD ESP3[0x1000];
    
    DWORD dwESP;
    DWORD dwCS;
    DWORD dwCR3;
    
    _declspec(naked) void Call(){
        _asm{
            int 3;
    
            mov dwESP,ESP;
            mov ax,cs;
            mov dwCS,eax;
    
            // reset the NT flag in eflags register
            pushfd;
            pop eax;
            or eax,0x4000;
            push eax;
            popfd;
    
            iretd;
        }
    }
    int main(int argc, char* argv[])
    {
        memset(iTSS,0,sizeof(iTSS));
        memset(ESP0,0,sizeof(ESP0));
        memset(ESP3,0,sizeof(ESP3));
        VirtualLock(iTSS),0x2000);
        VirtualLock(ESP0),0x2000);
        VirtualLock(ESP3),0x2000);
        dwESP = 0;
        dwCS = 0;
        dwCR3 = 0;
    
        iTSS[1] = (DWORD)(ESP0+0x900);    // ESP
        iTSS[2] = 0x10;                    // SS0
        iTSS[8] = (DWORD)Call;            // EIP
        iTSS[14] = (DWORD)(ESP3+0x900); // ESP3
        iTSS[18] = 0x23;    // ES
        iTSS[19] = 0x08;    // CS
        iTSS[20] = 0x10;    // SS
        iTSS[21] = 0x23;    // DS
        iTSS[22] = 0x30;    // FS
    
        printf("iTSS:%x ESP3:%x ESP0:%x
",iTSS,(ESP3+0x900),(ESP0+0x900));
        printf("input cr3:");
        scanf("%x",&dwCR3);
        iTSS[7] = dwCR3;        // cr3
    
        char buf[6] = {0,0,0,0,0x48,0};
        _asm{
            call fword ptr buf;
        }
        printf("ESP:%x CS:%x
",dwESP,dwCS);
        return 0;
        return 0;
    }

  技术图片

 

7. int 3 断下时,如果不恢复eflags寄存器,其就会卡死。
    因为当进行TSS跳转时,其会将老的TSS保存在新的TSS头部(上面我们看到),当我们使用iretd返回时,其不是像中断那样根据返回地址,而是根据TSS段选择子找旧的TSS段内存,然后将里面的寄存器全部加载进去。
    而INT 3 会清空 VM、NT、IF、TF四个位,其中NT表示嵌套任务段(nested task),如果清空,其就认为不存在任务段嵌套,直接像常规那样,根据返回地址返回,此时就会出错。
    因此就会存在下面一段代码来修改elfags寄存器中的NT位。
    // reset the NT flag in eflags register
    pushfd;
    pop eax;
    or eax,0x4000;
    push eax;
 popfd;

 

8. 任务门的作用
    技术图片

  当CPU出现双重错误,其就会通过任务门,调到08到中断去。

  任务门在IDT表中,触发同样适用 int 0x20;

 

9. 任务门实验

    //
    
    #include "stdafx.h"
    #include <stdlib.h>
    #include <windows.h>
    #include <memory.h>
    DWORD iTSS[26];
    DWORD ESP0[0x1000];
    DWORD ESP3[0x1000];
    
    DWORD dwESP;
    DWORD dwCS;
    DWORD dwCR3;
    
    _declspec(naked) void Call(){
        _asm{
            //int 3;
    
            mov dwESP,ESP;
            mov ax,cs;
            mov dwCS,eax;
    
            // reset the NT flag in eflags register
            /*
            pushfd;
            pop eax;
            or eax,0x4000;
            push eax;
            popfd;
            */
            iretd;
        }
    }
    int main(int argc, char* argv[])
    {
        memset(iTSS,0,sizeof(iTSS));
        memset(ESP0,0,sizeof(ESP0));
        memset(ESP3,0,sizeof(ESP3));
        VirtualLock(iTSS,28);
        VirtualLock(ESP0,0x1000);
        VirtualLock(ESP3,0x1000);
        dwESP = 0;
        dwCS = 0;
        dwCR3 = 0;
    
        iTSS[1] = (DWORD)(ESP0+0x900);    // ESP
        iTSS[2] = 0x10;                    // SS0
        iTSS[8] = (DWORD)Call;            // EIP
        iTSS[14] = (DWORD)(ESP3+0x900); // ESP3
        iTSS[18] = 0x23;    // ES
        iTSS[19] = 0x08;    // CS
        iTSS[20] = 0x10;    // SS
        iTSS[21] = 0x23;    // DS
        iTSS[22] = 0x30;    // FS
    
        printf("iTSS:%x ESP3:%x ESP0:%x
",iTSS,(ESP3+0x900),(ESP0+0x900));
        printf("input cr3:");
        scanf("%x",&dwCR3);
        iTSS[7] = dwCR3;        // cr3
    
        char buf[6] = {0,0,0,0,0x48,0};
        _asm{
            int 0x20;
        }
        printf("ESP:%x CS:%x
",dwESP,dwCS);
        return 0;
        return 0;
    }

    windbg 修改
    其根据任务门属性来进行如下修改:
    eq 8003f500  0000e500`00480000 (任务门,通过int 0x20触发,找到48选择子处)
    eq 8003f048 0000e943`2c680068 (TSS内存地址构造TSS段描述符)
 填写进程的CR3地址,之后就可以看见运行成功。

 

以上是关于任务段与任务门的主要内容,如果未能解决你的问题,请参考以下文章

Android 片段生命周期

VS2015 代码片段整理

任务切换

异步任务片段背景数据

从片段中调用分离的异步任务类

屏幕方向期间片段内的异步任务