段间跳转之TSS段

TR寄存器,TSS描述符,TSS段

TR寄存器与普通的段寄存器一样都有可见部分和不可见部分。TR的可见部分为16位为其段选择子,不可见部分是32位的TSS基地址和16位的大小。

TSS描述符存在GDT表中,注意其G位为0,所以TSS段的大小Limit的单位为字节,TYPE位为10B1(B为忙碌标志)。cpu利用TSS描述符来填充TR寄存器不可见部分。

TSS段是一个104个字节的内存,是Inter用来提供实现任务切换的,但是windows和linux都没有使用。TR寄存器隐藏部分的基地址就是TSS段的基地址。TSS可以保存一堆寄存器实现一次替换所有寄存器。Previous Task Link用来保存旧的段选择子,iretd指令利用此字段返回。

读写TR寄存器

Ring 0

ldt指令是一个特权指令,其能够为TR寄存器的可见部分提供一个值。
sdt指令是一个不同指令,其能够从TR寄存器中读取可见部分的值。

Ring 3

在应用层只能通过jmp far和call far指令更改TR寄存器,读TR寄存器与在0环相同都是通过SDT指令。

利用jmp far更改TR寄存器

构造一个TSS段描述符,0000E95D`00000068,即TSS段的基地址为0x005D0000,长度为0x68(104)个字节。

我们构造TSS段,给各个字段赋值。其中我们让cs为8,cpl为0是为了提权。

TSS[0] = 0x00000000; // Previous Task Link
TSS[1] = 0x00000000; // ESP0
TSS[2] = 0x00000000; // SS0
TSS[3] = 0x00000000; // ESP1
TSS[4] = 0x00000000; // SS1
TSS[5] = 0x00000000; // ESP2
TSS[6] = 0x00000000; // SS2
TSS[7] = dwCr3;      // CR3
TSS[8] = (DWORD)TestPorc; // EIP
TSS[9] = 0x00000000; // EFLAGS
TSS[10] = 0x00000000; // EAX
TSS[11] = 0x00000000; // ECX
TSS[12] = 0x00000000; // EDX
TSS[13] = 0x00000000; // EBX
TSS[14] = (DWORD)esp; // ESP
TSS[15] = 0x00000000; // EBP
TSS[16] = 0x00000000; // ESI
TSS[17] = 0x00000000; // EDI
TSS[18] = 0x00000023; // ES
TSS[19] = 0x00000008; // CS 0x0000001B
TSS[20] = 0x00000010; // SS 0x00000023
TSS[21] = 0x00000023; // DS
TSS[22] = 0x00000030; // FS 0x0000003B
TSS[23] = 0x00000000; // GS
TSS[24] = 0x00000000; // LDT Segment Selector
TSS[25] = 0x20ac0000; // I/O Map Base Address

执行jmp far 0x48:0x00000000,执行后我们发现代码跳转到了TestPorc地址处。EFLAGS的NT位被置位0,所以jmp far的TSS切换不能利用iret指令返回,如果要返回应该利用指令jmp far旧的TSS段选择子返回。

而且jmp far不会将旧的TSS段选择子保存在TSS段的Previous Task Link中,如果我们需要返回应该在跳转前保存旧的TSS段选择子,然后在利用jmp far指令返回。

注意其CPU在切换任务时,会将现在的TSS段描述符的TYPE的B忙位置1。

利用call far更改TR寄存器

构造一个TSS段描述符,0000E93F`00000068,即TSS段的基地址为0x003F0000,长度为0x68(104)个字节。

我们构造和jmp far一样的TSS段,给各个字段赋值。执行jmp far 0x48:0x00000000,执行后我们发现代码跳转到了TestPorc地址处。EFLAGS的NT位被置为1,所以call far的TSS切换能利用iret指令返回,其返回利用保存在TSS段中的
Previous Task Link保存的旧的TSS段选择子。

我们查看其TSS段,发现Previous Task Link的值为0x28,所以旧的TSS段选择子为0x28。

我们查看堆栈,发现call far 更改TR寄存器并不会更改堆栈的内容。

同样其也会将现在的TSS段描述符的TYPE的忙位B置1。

疑问

当jmp far 和 call far改变TR寄存器时我们使用的段选择子的RPL都为0,当RPL为3时会出错。
当jmp far 和 call far改变TR寄存器时我们的TSS段的cs的CPL为3会出错。

posted @ 2021-03-02 12:47  怎么可以吃突突  阅读(586)  评论(0编辑  收藏  举报