1.TSS的结构:
TSS不是寄存器,它是一个内存;(包含所有寄存器的值)
2.TSS的作用:
如果切换一个线程那么一定需要切换寄存器;
3.CPU怎么找到TSS内存块呢? 通过TaskRegister段寄存器
TaskRegister段寄存器 的值是CPU启动的时候通过GDT表中 TSS Descrptor (段描述符)加载出来的;
4.TSS Descriptor (TSS段描述符)
那么高字节BASE两个组合
+
低字节31-16位
0000e900~7b400068
0x68为结构体长度!104个字节
如果Type 为 1001 (9)的时候说明这个段描述符没有加载到TR寄存器中
如果Type 为 1011 (B)的时候说明这个段描述符加载到TR寄存器中
5.TR寄存器的读写:
6.修改TR寄存器:
测试实验:
7.实验思路
- 编写测试入口函数
- 构造TSS
- 设计TSS段描述符并安装
一、构造TSS:
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;
char st[10] = {0}; //定义一个堆栈切换的 TSS tss = {// tss的地址根据执行代码自己组合 0x00000000,//link (DWORD)st,//esp0 0x00000010,//ss0 0x00000000,//esp1 0x00000000,//ss1 0x00000000,//esp2 0x00000000,//ss2 0x00000000,//cr3 0x0040fad0,//eip 必填项,不然执行完后cpu不知道回来从哪开始执行 0x00000000,//eflags 0x00000000,//eax 0x00000000,//ecx 0x00000000,//edx 0x00000000,//ebx (DWORD)st,//esp 切换后堆栈在哪分配 0x00000000,//ebp 0x00000000,//esi 0x00000000,//edi 0x00000023,//es 0x00000008,//cs 0x00000010,//ss 0x00000023,//ds 0x00000030,//fs 0x00000000,//gs 0x00000000,//ldt 0x20ac0000 //IO权限位图 };
二、 准备TSS段描述符:
0040e900~7b400068 //加载的地址在你自己的VC6中看!
三、写入准备好的TSS段描述符到GDT空白位置
1: kd> r gdtr |
|
四.修改TR寄存器
CALL FAR或者JMP FAR
char buff[6]; *(DWORD*)&buff[0]= 0x12345678; *(DWORD*)&buff[4]= 0xC0; __asm { call fword ptd[buff] }