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\n",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\n",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\n",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\n",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\n",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\n",dwESP,dwCS); return 0; return 0; }
windbg 修改
其根据任务门属性来进行如下修改:
eq 8003f500 0000e500`00480000 (任务门,通过int 0x20触发,找到48选择子处)
eq 8003f048 0000e943`2c680068 (TSS内存地址构造TSS段描述符)
填写进程的CR3地址,之后就可以看见运行成功。
原文地址:https://www.cnblogs.com/onetrainee/p/12436412.html