任务门
前言:任务门
上面的TR段寄存器 TSS段描述符 TSS任务段都学完了,练习也做完了,实现了通过JUMP / CALL 访问 TSS任务段 实现任务切换
这里继续来学习通过任务门来访问TSS任务段,那么问题来了,通过JUMP / CALL能访问TSS任务段,那为什么还需要学习通过任务门来访问TSS任务段呢?
自己的理解就是
任务门段描述符
之前学习过IDT表中存在三种类型的门描述符,分别是中断/陷阱/任务门描述符,这里的话就来学习任务门描述符,任务门描述符如下图所示

任务门执行过程:
因为都是IDT表中的,所以这些门触发都是从中断表中触发的,既然要IDT表中触发,那肯定少不了INT N,
-
触发
INT N,查IDT表,找到任务门描述符 -
通过任务门描述符,查GDT表,找到TSS段描述符
-
使用TSS段中的值修改TR寄存器
-
IRETD返回
构造一个任务门实现提权
- 触发
INT N,查IDT表,找到任务门描述符
这里选择一个IDT表中空的段描述符,如下图所示,地址为 0x8003f508 -> int 33

然后这个位置来填充一个任务门描述符,为0000E500 00000000
- 通过任务门描述符,查GDT表,找到TSS段描述符
当前的任务门描述符为0000E500 00000000,其中还少了TSS段描述符,TSS段描述符在GDT表中,所以这里还需要去GDT表中来构建TSS段描述符,我在GDT表中的如下位置来构建,如下图所示,位置在0x8003f048

到这里的话,就直到TSS段描述符的段选择子了,所以任务们的描述符为0000E500 00480000, eq 0x8003f508 0000E500 00480000(记得反引号)

GDT表中构建的TSS段描述符,根据如下所示的TSS段描述符,我这里构建的是XX0XE9XX XXXX0068,让它跳的TSS任务段的地址为,所以构造的TSS段描述符为XX00E9XX XXXX0068
这里查看TSS的地址,如下图所示,最终构建的TSS段描述符为0000E942 73180068

将TSS段描述符为0000E942 73180068写到GTR表中,eq 0x8003f048 0000E942 73180068(记得反引号)

以上其实总共执行了两条命令,如下所示
eq 0x8003f508 0000E500`00480000 // IDT表中构建任务门描述符
eq 0x8003f048 0000E942`73180068 // GDT表中构建TSS段描述符
最终测试代码如下:
#include<windows.h>
#include<stdio.h>
typedef struct TSS {
DWORD link; // 保存前一个 TSS 段选择子,使用 call 指令切换寄存器的时候由CPU填写。
// 这 6 个值是固定不变的,用于提权,CPU 切换栈的时候用
DWORD esp0; // 保存 0 环栈指针
DWORD ss0; // 保存 0 环栈段选择子
DWORD esp1; // 保存 1 环栈指针
DWORD ss1; // 保存 1 环栈段选择子
DWORD esp2; // 保存 2 环栈指针
DWORD ss2; // 保存 2 环栈段选择子
// 下面这些都是用来做切换寄存器值用的,切换寄存器的时候由CPU自动填写。
DWORD cr3;
DWORD eip;
DWORD eflags;
DWORD eax;
DWORD ecx;
DWORD edx;
DWORD ebx;
DWORD esp;
DWORD ebp;
DWORD esi;
DWORD edi;
DWORD es;
DWORD cs;
DWORD ss;
DWORD ds;
DWORD fs;
DWORD gs;
DWORD ldt;
// 这个暂时忽略
DWORD io_map;
} TSS;
DWORD dwHigh2GValue;
char stack[100]={0};
DWORD cr3;
DWORD testFunc;
TSS tss =
{
0x0,0x0,0x0,0x0,0x0,0x0,0x0,
0,
0,
0,0,0,0,0,
((DWORD)stack) - 100,
0,0,0,
0x23,
0x08,
0x10,
0x23,
0x30,
0,0,0x20ac0000
};
void __declspec(naked) test()
{
__asm
{
pushad;
pushfd;
mov eax, 0x8003f008;
mov ebx,[eax];
mov dwHigh2GValue, ebx;
popfd;
popad;
iretd;
}
}
int main()
{
printf("current tss addr: %X\n", &tss);
printf("current testFunc: %p\n", test);
printf("input testFunc: ");
scanf("%X",&tss.eip);
printf("input cr3: ");
scanf("%X", &tss.cr3);
__asm
{
int 33;
}
printf("dwHigh2GValue: %d\n", dwHigh2GValue);
printf("----ok----\n");
return 0;
}
可以看到,任务门构造成功了

模拟除0异常查找处理异常函数的地址

我模拟的除0异常的代码如下,就改了进0环之后的操作,让其div0,使其异常
void __declspec(naked) test()
{
__asm
{
pushad;
pushfd;
//mov eax, 0x8003f008;
//mov ebx,[eax];
//mov dwHigh2GValue, ebx;
//mov eax, dwHigh2GValue;
mov eax,0;
mov ebx,0;
div ebx;
popfd;
popad;
iretd;
}
}
报错信息如下所示,其中的参数8的实质意思是触发了INT 8,老师说这个是双重错误,我不理解
Use !analyze -v to get detailed debugging information.
BugCheck 7F, {8, 80042000, 0, 0}

双重异常

我的理解就是老师让我们分析INT 8的过程,所以这里直接找IDT表中索引为9的段描述符即可,如下图所示00008500 00501198

00008500 00501198,通过这个课的学习,这个可以知道是一个任务门描述符(DPL为0),并且当它触发了之后,它找的是GTR中段选择子为0050的TSS段描述符,这里跟过去看下,段描述符为80008955 27000068,一个系统段描述符,TYPE域为9

查看下相关系统段描述符的表,是一个TSS段描述符,我就只会分析到这里了

总结下INT8 就是走IDT表,然后通过任务门(这个任务段描述符是0环的,正常来说3环无法访问)进行相关的TSS任务段实现任务切换

浙公网安备 33010602011771号