任务门

前言:任务门

上面的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 00480000eq 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任务段实现任务切换

posted @ 2022-02-08 13:27  zpchcbd  阅读(301)  评论(0)    收藏  举报