[ 本帖最后由 woshikele 于 2021-10-6 18:40 编辑 ]\n\n章节介绍
- 参考体系段形貌符介绍,.
- TR段寄存器的结构,读写,切换时机.
- 任务段存储于GDT表中,TR段寄存器指向的任务段形貌符中的Base定位了TSS在内存中的起始地址.
- TSS的结构,大小,用途.
- 不同指令实行任务段的影响.(详情参考代码示例)
0.TR寄存器
intel白皮书解释如下:
The task register holds the 16-bit segment selector, base address (32 bits in protected mode; 64 bits in IA-32e mode), segment limit, and descriptor attributes for the TSS of the current task. The selector references the TSS descriptor in the GDT. The base address specifies the linear address of byte 0 of the TSS;
The LTR and STR instructions load and store the segment selector part of the task register, respectively. When the LTR instruction loads a segment selector in the task register, the base address, limit, and descriptor attributes from the TSS descriptor are automatically loaded into the task register. On power up or reset of the processor, the base address is set to the default value of 0 and the limit is set to 0FFFFH.
When a task switch occurs, the task register is automatically loaded with the segment selector and descriptor for the TSS for the new task. The contents of the task register are not automatically saved prior to writing the new TSS information into the register.
TR寄存器的读写:
//1.将TSS段形貌符加载到TR寄存器//指令:LTR//用LTR指令去装载的话 仅仅是改变TR寄存器的值(96位) 并没有真正改变TSS LTR指令只能在RING0使用 加载后TSS段形貌符会状态位会发生改变//2.读TR寄存器//指令:STR//说明:假如用STR去读的话,只读了TR的16位 也就是选择子#include #include int main(){ WORD wTR = 0; __asm { str wTR } printf("TR = %04x \n",wTR); system("Pause"); return 0;}1.任务段形貌符
在调用门,中断门,陷阱门中一旦出现权限切换,会有新的ESP SS,来自于任务段(TASK-STATE SEGMENT) TR寄存器指向当前TSS.
TSS.BASE指向TSS在内存中的基址
- 高4字节 31-24(BIT) BASE 31:24
- 高4字节 07-00(BIT) BASE 23:16
- 低4字节 31-16(BIT) BASE 15:00
TSS.LENGTH指向TSS在内存中的大小
- 高4字节 19-16(BIT) LIMIT 19:16
- 低4字节 15-00(BIT) LIMIT 15:00
- 高4字节 23(BIT) G == 0(BYTE) G == 1(PAGE)
TSS.ATTRIBUTE
- 高4字节 15-12(BIT) P == 1 DPL == 00/11 S == 0
- 高4字节 11-08(BIT) TYPE == 1001(空闲) 1011(占用)
2.TSS
TR寄存器指向的任务段形貌符的BASE为TSS的基址
TSS是一块内存,大小104字节.通过TSS可以同时更换“一堆”寄存器,包括通用寄存器和段寄存器等.
Windows只使用了TSS的SS0和ESP0,用于权限切换.
TSS这个东西是Intel设计出来做任务切换的,windows和linux都没有使用任务,而是本身实现了线程。在windows中,TSS唯一的作用就是权限切换时要用到SS0和ESP0,又或者这样理解,TSS就是用来一次性更换一堆寄存器的.
查看默认TR指向的数据:
3.任务段实行流程
1.通过TR寄存器段选择子去GDT表中查找TSS段形貌符
2.通过TSS段形貌符BASE定位TSS内存地址
3.切换任务通过TSS内存数据内寄存器一次性切换
- call far 实行会记载 PTL 且 NT标记位 = 1 返回时通过当前TSS表previous task link加载
- jmp far 实行不记载 PTL 且 NT标记位 = 0 返回时需提前备份TSS数据 通过 jmp far 返回
- NT位影响IRETD指令 NT == 1 通过切换任务返回 NT == 0 通过堆栈返回
PS:WIN7 X86 通过 CALLFAR JMPFAR TSS内存都均为保存CR3数据需要我们自行备份否则蓝屏或C05
4.任务段示例
4.1 CALL FAR实行任务段
#include #include //TSS结构体struct _KiIoAccessMap{ UCHAR DirectionMap[32]; //0x0 UCHAR IoMap[8196]; //0x20};typedef struct _KTSS{ USHORT Backlink; //0x0 USHORT Reserved0; //0x2 ULONG Esp0; //0x4 USHORT Ss0; //0x8 USHORT Reserved1; //0xa ULONG NotUsed1[4]; //0xc ULONG CR3; //0x1c ULONG Eip; //0x20 ULONG EFlags; //0x24 ULONG Eax; //0x28 ULONG Ecx; //0x2c ULONG Edx; //0x30 ULONG Ebx; //0x34 ULONG Esp; //0x38 ULONG Ebp; //0x3c ULONG Esi; //0x40 ULONG Edi; //0x44 USHORT Es; //0x48 USHORT Reserved2; //0x4a USHORT Cs; //0x4c USHORT Reserved3; //0x4e USHORT Ss; //0x50 USHORT Reserved4; //0x52 USHORT Ds; //0x54 USHORT Reserved5; //0x56 USHORT Fs; //0x58 USHORT Reserved6; //0x5a USHORT Gs; //0x5c USHORT Reserved7; //0x5e USHORT LDT; //0x60 USHORT Reserved8; //0x62 USHORT Flags; //0x64 USHORT IoMapBase; //0x66 struct _KiIoAccessMap IoMaps[1]; //0x68}TSS;TSS tss = {0};DWORD g_dwTR = 0;DWORD g_dwCr3 = 0;CHAR ESP0STACK[0x100] = {0};_declspec(naked) VOID CALLTASK(){ __asm { //提升堆栈 修复CR3 存储暂时数据提供空间 sub esp, 0x10 //获取GDT表数据 sgdt [esp] //获取GDT.Base mov eax, [esp + 0x2] //获取默认任务段形貌符 add eax, g_dwTR lea edx, [esp + 0x8] //获取默认任务段形貌符低4字节 mov ecx, [eax] //LO //获取默认任务段形貌符高4字节 mov eax, [eax + 0x4]//HI //获取默认TSS 31:24 mov ebx, eax shr ebx, 24 mov byte ptr [edx + 3], bl //获取默认TSS 23:16 mov ebx, eax and ebx, 0xFF mov byte ptr [edx + 2], bl //获取默认TSS 15:00 mov ebx, ecx shr ebx, 16 mov word ptr [edx], bx //修复CR3 mov eax, [esp + 0x8] mov ecx, [g_dwCr3] mov [eax + 0x1C], ecx add esp, 0x10 //call指令实行任务切换会使EFLAG.NT标记位置1(IRETD指令通过任务切换返回) iretd }}int main(){ //构建段形貌符XX00E9XX`XXXX0068 //G = 0 //P = 1 //DPL = 11 //S = 0 //TYPE = 1001 printf("%02x00e9%02x`%04x0068 \n",(DWORD)&tss >> 24,((DWORD)&tss >> 16) & 0xFF,LOWORD(&tss)); printf("TSSADDR [0x%08x] \n",&tss); system("Pause"); //Windbg 输入指令!process 0 0 获取自身进程CR3 printf("INPUT CR3: "); scanf("%x",&g_dwCr3); //构建ESP0 memset(ESP0STACK,0,0x100); //构建TSS tss.CR3 = g_dwCr3; tss.Eip = (ULONG)CALLTASK; tss.Esp = (ULONG)ESP0STACK + 0x100; tss.Es = 0x23; tss.Cs = 0x8; tss.Ss = 0x10; tss.Ds = 0x23; tss.Fs = 0x30; tss.IoMapBase = 0x20ac; //TR __asm { str [g_dwTR] } CHAR calldata[6] = {0,0,0,0,0x48,0}; __asm { call fword ptr [calldata] } system("Pause"); return 0;}实行任务切换前数据
进入切换任务时查看此时数据
4.2 JMP FAR实行任务段
#include #include //TSS结构体struct _KiIoAccessMap{ UCHAR DirectionMap[32]; //0x0 UCHAR IoMap[8196]; //0x20};typedef struct _KTSS{ USHORT Backlink; //0x0 USHORT Reserved0; //0x2 ULONG Esp0; //0x4 USHORT Ss0; //0x8 USHORT Reserved1; //0xa ULONG NotUsed1[4]; //0xc ULONG CR3; //0x1c ULONG Eip; //0x20 ULONG EFlags; //0x24 ULONG Eax; //0x28 ULONG Ecx; //0x2c ULONG Edx; //0x30 ULONG Ebx; //0x34 ULONG Esp; //0x38 ULONG Ebp; //0x3c ULONG Esi; //0x40 ULONG Edi; //0x44 USHORT Es; //0x48 USHORT Reserved2; //0x4a USHORT Cs; //0x4c USHORT Reserved3; //0x4e USHORT Ss; //0x50 USHORT Reserved4; //0x52 USHORT Ds; //0x54 USHORT Reserved5; //0x56 USHORT Fs; //0x58 USHORT Reserved6; //0x5a USHORT Gs; //0x5c USHORT Reserved7; //0x5e USHORT LDT; //0x60 USHORT Reserved8; //0x62 USHORT Flags; //0x64 USHORT IoMapBase; //0x66 struct _KiIoAccessMap IoMaps[1]; //0x68}TSS;TSS tss = {0};DWORD g_dwTR = 0;DWORD g_dwCr3 = 0;CHAR JMPDATA[6] = {0};CHAR ESP0STACK[0x100] = {0};_declspec(naked) VOID CALLTASK(){ __asm { //提升堆栈 修复CR3 存储暂时数据提供空间 sub esp, 0x10 //获取GDT表数据 sgdt [esp] //获取GDT.Base mov eax, [esp + 0x2] //获取默认任务段形貌符 add eax, g_dwTR lea edx, [esp + 0x8] //获取默认任务段形貌符低4字节 mov ecx, [eax] //LO //获取默认任务段形貌符高4字节 mov eax, [eax + 0x4]//HI //获取默认TSS 31:24 mov ebx, eax shr ebx, 24 mov byte ptr [edx + 3], bl //获取默认TSS 23:16 mov ebx, eax and ebx, 0xFF mov byte ptr [edx + 2], bl //获取默认TSS 15:00 mov ebx, ecx shr ebx, 16 mov word ptr [edx], bx //修复CR3 mov eax, [esp + 0x8] mov ecx, [g_dwCr3] mov [eax + 0x1C], ecx add esp, 0x10 //jmp far实行任务段NT标记位 = 0 不能使用iretd返回 jmp fword ptr [JMPDATA] }}int main(){ //构建段形貌符XX00E9XX`XXXX0068 //G = 0 //P = 1 //DPL = 11 //S = 0 //TYPE = 1001 printf("%02x00e9%02x`%04x0068 \n",(DWORD)&tss >> 24,((DWORD)&tss >> 16) & 0xFF,LOWORD(&tss)); printf("TSSADDR [0x%08x] \n",&tss); system("Pause"); //Windbg 输入指令!process 0 0 获取自身进程CR3 printf("INPUT CR3: "); scanf("%x",&g_dwCr3); //构建ESP0 memset(ESP0STACK,0,0x100); //构建TSS tss.CR3 = g_dwCr3; tss.Eip = (ULONG)CALLTASK; tss.Esp = (ULONG)ESP0STACK + 0x100; tss.Es = 0x23; tss.Cs = 0x8; tss.Ss = 0x10; tss.Ds = 0x23; tss.Fs = 0x30; tss.IoMapBase = 0x20ac; //TR __asm { str [g_dwTR] } *(LPWORD)&JMPDATA[4] = g_dwTR; CHAR calldata[6] = {0,0,0,0,0x48,0}; __asm { jmp fword ptr [calldata] } system("Pause"); return 0;}进入切换任务时查看此时数据
来源:http://www.12558.net
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |