任务段

TSS(Task-state segment)

描述

TSS是一块内存
大小:104字节
TSS存储了一堆寄存器的值

TSS结构图

  • Previous Task Link:存放上一任务的 TSS 的段选择子, 以便在返回时确定切换任务前原来的 TSS 。
  • SS0-SS2,SEP0-ESP2:windows 系统在提权的时候切换时用的。降权时替换的栈寄存器在堆栈里面,权限不变时不用切换栈,因此都不需要查 TSS。另外一个提权时需要查 TSS 的寄存器是 FS 。
  • LDT Segment Selector:在任务切换时查找该任务的 LDT 段描述符并修改 ldtr 寄存器。

WinDbg 中使用 .tss + tss 段选择子 可以查看 TSS 信息。

kd> .tss 0x28
eax=00000001 ebx=7ffd7000 ecx=0042201e edx=00000000 esi=0012f7bc edi=0012ff80
eip=004011c9 esp=0012fe5c ebp=0012ff80 iopl=0         nv up ei pl nz na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000206
Unknown_Module_00400000+0x11c9:
001b:004011c9 33c0            xor     eax,eax

TSS的作用

  • Intel的设计思想
    通过使用TSS以达到任务(线程)的切换
  • 操作系统的设计思想
    与Intel设计思想不同的是,Windows并没有根据Intel的设计思想来做,甚至Linux也没有这样做。在 Windows 中,TSS 只在通过门提权时提供进入 0 环时环寄存器(SS,ESP等)的初始值。
  • 本质
    不要把TSS与“任务切换”联系到一起TSS的意义就在于可以同时换掉”一堆”寄存器

TR段寄存器

描述

TR寄存器的值是当操作系统启动时,从TSS段描述符中加载出来的,TSS段描述符在GDT表中

  • TR.Base = TSS起始地址
  • TR.Limit = TSS大小
  • CPU通过TR段寄存器寻找TSS

TR段寄存器的读写

  • 将TSS段描述符加载到TR寄存器

    • 指令:LTR
    • 说明:
      • 用LTR指令去装载的话 仅仅是改变TR寄存器的值(96位)并没有真正改变TSS
      • LTR指令只能在系统层使用
      • 加载后TSS段描述符会状态位会发生改变
  • 读TR寄存器
    • 指令:STR
    • 说明:如果用STR去读的话,只读了TR的16位 也就是选择子

TSS段描述符(TSS Descriptor)

描述

TSS段描述符是系统段描述符中的一种

结构图

  • 构造TSS段描述符:XX00E9XX`XXXX0068
  • Type = 二进制1001(9):说明该TSS段描述符未被加载到TR段寄存器中
  • Type = 二进制1011(B):说明该TSS段描述符已被加载到TR段寄存器中

WinDbg 查看 TSS

kd> r tr
tr=00000028
kd> dq gdtr
8003f000  00000000`00000000 00cf9b00`0000ffff
8003f010  00cf9300`0000ffff 00cffb00`0000ffff
8003f020  00cff300`0000ffff 80008b04`200020ab
8003f030  ffc093df`f0000001 0040f300`00000fff
8003f040  0000f200`0400ffff 00000000`00000000
8003f050  80008955`23800068 80008955`23e80068
8003f060  00009302`2f40ffff 0000920b`80003fff
8003f070  ff0092ff`700003ff 80009a40`0000ffff
kd> dg 28P Si Gr Pr Lo
Sel    Base     Limit     Type    l ze an es ng Flags
---- -------- -------- ---------- - -- -- -- -- --------
0028 80042000 000020ab TSS32 Busy 0 Nb By P  Nl 0000008b
kd> dd 80042000
80042000  0c458b24 80552170 8b080010 758b0855
80042010  eac14008 ffe68110 030000ff 00039000
80042020  e1750855 08458b5e 0310e8c1 c25d0845
80042030  ff8b000c 8bec8b55 c9330845 f7104d39
80042040  8b1f76d0 b60f0c55 d0331114 00ffe281
80042050  e8c10000 95043308 00433990 104d3b41
80042060  d0f70000 20ac0000 18000004 00000018
80042070  00000000 00000000 00000000 00000000

实验:加载自定义TSS

使用 call 命令加载 TSS 并返回

call 加载 TSS 的指令格式为 call 16位TSS段选择子:无效EIP,因此可以在 GDT 中构造一个段选择子然后指向自己构造的 TSS 然后 call 过去。
需要注意的是:

  • 利用 call 指令进行 TSS 加载时会将 EFLAGS 寄存器中的 NT 位置 1 ,表示中断嵌套,根据 NT 位是否为 1,iretd 返回时会选择根据 Previous Task Link 选择 TSS 还是根据堆栈返回。如果在切换任务函数中使用了 int 3 断点会将 NT 位置 0 导致返回时根据堆栈返回触发蓝屏。
  • 任务切换时会自动填充 Previous Task Link,因此在构造时不需要关心这个位置填什么值。
  • 提权时需要将 CS、SS、FS 寄存器都改成 0 环权限。
  • 为了确保稳定,I/O Map Base Address 属性改成和原来 TSS 一样。

运行如下代码:

#include <Windows.h>
#include <stdio.h>void __declspec(naked) test() {__asm {iretd}
}int main() {char stack[100] = {0};DWORD tss[0x68 / sizeof(DWORD)] = {0x00000000,           //Previous Task Link0x00000000,           //ESP00x00000000,           //SS00x00000000,           //ESP10x00000000,           //SS10x00000000,           //ESP20x00000000,           //SS20x00000000,           //Cr3(DWORD) test,         //EIP0x00000000,           //EFLAGS0x00000000,           //EAX0x00000000,           //ECX0x00000000,           //EDX0x00000000,           //EBX((DWORD) stack) + 100,//ESP0x00000000,           //EBP0x00000000,           //ESI0x00000000,           //EDI0x00000023,           //ES0x00000008,           //CS0x00000010,           //SS0x00000023,           //DS0x00000030,           //FS0x00000000,           //GS0x00000000,           //LDT Segment Selector0x20ac0000};          //I/O Map Base Addressunsigned char buf[6] = {0, 0, 0, 0, 0x48, 0};printf("tss: %X\n", tss);printf("cr3:");scanf("%X", &tss[7]);__asm {call fword ptr buf}return 0;
}

获取 tss 段的地址。

根据 tss 地址构造 TSS 段描述符:

kd> dq gdtr
8003f000  00000000`00000000 00cf9b00`0000ffff
8003f010  00cf9300`0000ffff 00cffb00`0000ffff
8003f020  00cff300`0000ffff 80008b04`200020ab
8003f030  ffc093df`f0000001 0040f300`00000fff
8003f040  0000f200`0400ffff 00000000`00000000
8003f050  80008955`23800068 80008955`23e80068
8003f060  00009302`2f40ffff 0000920b`80003fff
8003f070  ff0092ff`700003ff 80009a40`0000ffff
kd> eq  8003f048  0000e912`feb40068
kd> dq gdtr
8003f000  00000000`00000000 00cf9b00`0000ffff
8003f010  00cf9300`0000ffff 00cffb00`0000ffff
8003f020  00cff300`0000ffff 80008b04`200020ab
8003f030  ffc093df`f0000001 0040f300`00000fff
8003f040  0000f200`0400ffff 0000e912`feb40068
8003f050  80008955`23800068 80008955`23e80068
8003f060  00009302`2f40ffff 0000920b`80003fff
8003f070  ff0092ff`700003ff 80009a40`0000ffff

然后获取 CR3:b7040000

kd> !process 0 0
**** NT ACTIVE PROCESS DUMP ****
.
.
.
Failed to get VadRoot
PROCESS 89dc7be0  SessionId: 0  Cid: 0148    Peb: 7ffdc000  ParentCid: 0150DirBase: b7040000  ObjectTable: e34ebc40  HandleCount:  11.Image: test.exe

填入 CR3,代码成功运行完。

使用 jmp 命令加载 TSS 并返回

jmp 命令用法和 call 相同,但是 jmp 命令不会将上一任务的 TSS 段描述符保存在 Previous Task Link 中,因此返回时需要再使用 jmp 命令切换回来。由于 jmp 命令 不会将 NT 位置 1 ,因此可以在 test 函数中下断点。
代码如下:

#include <Windows.h>
#include <stdio.h>unsigned char trs[6];void __declspec(naked) test() {__asm {int 3jmp fword ptr trs}
}int main() {char stack[100] = {0};DWORD tss[0x68 / sizeof(DWORD)] = {0x00000000,           //Previous Task Link0x00000000,           //ESP00x00000000,           //SS00x00000000,           //ESP10x00000000,           //SS10x00000000,           //ESP20x00000000,           //SS20x00000000,           //Cr3(DWORD) test,         //EIP0x00000000,           //EFLAGS0x00000000,           //EAX0x00000000,           //ECX0x00000000,           //EDX0x00000000,           //EBX((DWORD) stack) + 100,//ESP0x00000000,           //EBP0x00000000,           //ESI0x00000000,           //EDI0x00000023,           //ES0x00000008,           //CS0x00000010,           //SS0x00000023,           //DS0x00000030,           //FS0x00000000,           //GS0x00000000,           //LDT Segment Selector0x20ac0000};          //I/O Map Base Addressunsigned char buf[6] = {0, 0, 0, 0, 0x48, 0};WORD rs;__asm {str rs}*(WORD *) &trs[4] = rs;printf("tss: %X\n", tss);printf("cr3:");scanf("%X", &tss[7]);__asm {jmp fword ptr buf}return 0;
}

运行效果如下:

kd> g
Break instruction exception - code 80000003 (first chance)
00401020 cc              int     3
kd> uf eip
Flow analysis was incomplete, some code may be missing
00401020 cc              int     3
00401021 ff2dc8574200    jmp     fword ptr ds:[4257C8h]
kd> r tr
tr=00000048
kd> r cs
cs=00000008
kd> r ss
ss=00000010
kd> r esp
esp=0012ff80
kd> r fs
fs=00000030
kd> p
00401021 ff2dc8574200    jmp     fword ptr ds:[4257C8h]
kd> dd 4257C8
004257c8  00000000 00000028 00000000 00000000
004257d8  00380650 00000000 00000001 00380650
004257e8  000003a8 00000000 00000000 00000000
004257f8  00000000 00000000 00000000 00000000
00425808  00000000 00000000 00000000 00000000
00425818  00000000 00000000 00000000 00000000
00425828  00000000 00000000 00000000 00000000
00425838  00000000 00000000 00000000 00000000
kd> p
001b:004011c9 33c0            xor     eax,eax
kd> uf eip
004011c9 33c0            xor     eax,eax
004011cb 5f              pop     edi
004011cc 5e              pop     esi
004011cd 5b              pop     ebx
004011ce 81c418010000    add     esp,118h
004011d4 3bec            cmp     ebp,esp
004011d6 e835010000      call    00401310
004011db 8be5            mov     esp,ebp
004011dd 5d              pop     ebp
004011de c3              ret
kd> r cs
cs=0000001b
kd> r ss
ss=00000023
kd> r esp
esp=0012fe5c
kd> r fs
fs=0000003b
kd> r tr
tr=00000028

任务门

描述

  • 任务门存在于IDT表
  • 任务门中包含TSS段选择子
  • 可以通过访问任务门达到切换TSS的目的

结构图

任务门执行过程

  • INT N(N为IDT表索引号)
  • 系统通过用户指定的索引查找IDT表,找到对应的门描述符
  • 门描述符若为任务门描述符,则根据任务门描述符中TSS段选择子查找GDT表,找到TSS段描述符
  • 将TSS段描述符中的内容加载到TR段寄存器
  • TR段寄存器通过Base和Limit找到TSS
  • 使用TSS中的值修改寄存器
  • IRETD返回

分析 int 8 中断

按照 IDT 第 9 项任务门→\rightarrow→ GDT 0x50 偏移的 TSS 段描述符 →\rightarrow→ TSS 基址 →\rightarrow→ TSS 中的 EIP 顺序定位到 int 8 的中断服务例程 。由于我的 WinDbg 版本原因,直接 uf 地址没有显示出函数名,但是通过查询 KiTrap08 函数地址可以确定是 int 8 的中断服务例程是 KiTrap08 。

kd> dq idtr
8003f400  804e8e00`00080360 804e8e00`000804db
8003f410  00008500`0058113e 804eee00`000808ad
8003f420  804eee00`00080a30 804e8e00`00080b91
8003f430  804e8e00`00080d12 804e8e00`0008137a
8003f440  00008500`00501198 804e8e00`0008179f
8003f450  804e8e00`000818bc 804e8e00`000819f9
8003f460  804e8e00`00081c52 804e8e00`00081f48
8003f470  804e8e00`0008267e 804e8e00`000828f3
kd> dq gdtr
8003f000  00000000`00000000 00cf9b00`0000ffff
8003f010  00cf9300`0000ffff 00cffb00`0000ffff
8003f020  00cff300`0000ffff 80008b04`200020ab
8003f030  ffc093df`f0000001 7f40f3fd`90000fff
8003f040  0000f200`0400ffff 0000e912`feb40068
8003f050  80008955`23800068 80008955`23e80068
8003f060  00009302`2f40ffff 0000920b`80003fff
8003f070  ff0092ff`700003ff 80009a40`0000ffff
kd> dg 50P Si Gr Pr Lo
Sel    Base     Limit     Type    l ze an es ng Flags
---- -------- -------- ---------- - -- -- -- -- --------
0050 80552380 00000068 TSS32 Avl  0 Nb By P  Nl 00000089
kd> dd 80552380
ReadVirtual: 80552380 not properly sign extended
80552380  00000000 8054f380 00000010 00000000
80552390  00000000 00000000 00000000 00039000
805523a0  804e16ad 00000000 00000000 00000000
805523b0  00000000 00000000 8054f380 00000000
805523c0  00000000 00000000 00000023 00000008
805523d0  00000010 00000023 00000030 00000000
805523e0  00000000 20ac0000 00000000 8054f380
805523f0  00000010 00000000 00000000 00000000
kd> uf 804e16ad
ReadVirtual: 804e16ad not properly sign extended
804e16ad fa              cli
804e16ae 8b0d3cf0dfff    mov     ecx,dword ptr ds:[0FFDFF03Ch]
804e16b4 8d4150          lea     eax,[ecx+50h]
804e16b7 c6400589        mov     byte ptr [eax+5],89h
804e16bb 9c              pushfd
804e16bc 812424ffbfffff  and     dword ptr [esp],0FFFFBFFFh
804e16c3 9d              popfd
804e16c4 a13cf0dfff      mov     eax,dword ptr ds:[FFDFF03Ch]
804e16c9 8a6857          mov     ch,byte ptr [eax+57h]
804e16cc 8a4854          mov     cl,byte ptr [eax+54h]
804e16cf c1e110          shl     ecx,10h
804e16d2 668b4852        mov     cx,word ptr [eax+52h]
804e16d6 a140f0dfff      mov     eax,dword ptr ds:[FFDFF040h]
804e16db 890d40f0dfff    mov     dword ptr ds:[0FFDFF040h],ecx
804e16e1 6a00            push    0
804e16e3 6a00            push    0
804e16e5 6a00            push    0
804e16e7 50              push    eax
804e16e8 6a08            push    8
804e16ea 6a7f            push    7Fh
804e16ec e809260500      call    nt!KeBugCheck2 (80533cfa)
804e16f1 ebee            jmp     nt!KiTrap08+0x34 (804e16e1)  Branch
kd> u KiTrap08
nt!KiTrap08:
804e16ad fa              cli
804e16ae 8b0d3cf0dfff    mov     ecx,dword ptr ds:[0FFDFF03Ch]
804e16b4 8d4150          lea     eax,[ecx+50h]
804e16b7 c6400589        mov     byte ptr [eax+5],89h
804e16bb 9c              pushfd
804e16bc 812424ffbfffff  and     dword ptr [esp],0FFFFBFFFh
804e16c3 9d              popfd
804e16c4 a13cf0dfff      mov     eax,dword ptr ds:[FFDFF03Ch]

IDA 中分析该函数:

.text:004096AD _KiTrap08       proc near               ; DATA XREF: KiSystemStartup(x)+CB↓o
.text:004096AD                                         ; INIT:005DE640↓o
.text:004096AD
.text:004096AD var_4           = dword ptr -4
.text:004096AD
.text:004096AD                 cli
.text:004096AE                 mov     ecx, ds:0FFDFF03Ch ; 获取 GDT 表基址
.text:004096B4                 lea     eax, [ecx+50h]  ; 获取 int 8 指向的 tss 段描述符的位置
.text:004096B7                 mov     byte ptr [eax+5], 89h ; 修改段描述符的状态(DPL = 0, Type = TSS)
.text:004096BB                 pushf                   ; 将 EFLAGS 寄存器压栈
.text:004096BC                 and     [esp], 0FFFFBFFFh ; 将 NT 位置 0
.text:004096C3                 popf                    ; 将修改保存到 EFLAGS 中
.text:004096C4                 mov     eax, ds:0FFDFF03Ch ; 再次获取 GDT 表基址
.text:004096C9                 mov     ch, [eax+57h]
.text:004096CC                 mov     cl, [eax+54h]
.text:004096CF                 shl     ecx, 10h
.text:004096D2                 mov     cx, [eax+52h]   ; 获取 tss 段描述符中的 base 属性
.text:004096D6                 mov     eax, ds:0FFDFF040h ; 获取 _KPCR 中保存的 TSS 段基址
.text:004096DB                 mov     ds:0FFDFF040h, ecx ; 将 int 8 中断对应的 TSS 段基址保存到 KPCR 中
.text:004096E1
.text:004096E1 loc_4096E1:                             ; CODE XREF: .text:004096F1↓j
.text:004096E1                 push    0
.text:004096E3                 push    0
.text:004096E5                 push    0
.text:004096E7                 push    eax
.text:004096E8                 push    8
.text:004096EA                 push    7Fh
.text:004096EC                 call    _KeBugCheck2@24 ; KeBugCheck2(x,x,x,x,x,x)
.text:004096EC _KiTrap08       endp

可以确定该函数的大致执行流程是将 int 8 对应的 TSS 保存在 KPCR 结构中,然后将之前的 TSS 作为参数传到 KeBugCheck2 函数中。因为 int 8 本身是任务门,这里可以理解为维护 KPCR 中的 TSS 与当前状态对应。

实验:通过任务门加载 TSS

介前面 TSS 段实验构造的 TSS 段描述符,代码如下:

#include <Windows.h>
#include <stdio.h>void __declspec(naked) test() {__asm {iretd}
}int main() {char stack[100] = {0};DWORD tss[0x68 / sizeof(DWORD)] = {0x00000000,           //Previous Task Link0x00000000,           //ESP00x00000000,           //SS00x00000000,           //ESP10x00000000,           //SS10x00000000,           //ESP20x00000000,           //SS20x00000000,           //Cr3(DWORD) test,         //EIP0x00000000,           //EFLAGS0x00000000,           //EAX0x00000000,           //ECX0x00000000,           //EDX0x00000000,           //EBX((DWORD) stack) + 100,//ESP0x00000000,           //EBP0x00000000,           //ESI0x00000000,           //EDI0x00000023,           //ES0x00000008,           //CS0x00000010,           //SS0x00000023,           //DS0x00000030,           //FS0x00000000,           //GS0x00000000,           //LDT Segment Selector0x20ac0000};          //I/O Map Base Addressprintf("tss: %X\n", tss);printf("cr3:");scanf("%X", &tss[7]);__asm {int 0x20}return 0;
}

在 IDT 表的第 0x20 项构造任务门

kd> dq idtr l30
8003f400  804e8e00`00080360 804e8e00`000804db
8003f410  00008500`0058113e 804eee00`000808ad
8003f420  804eee00`00080a30 804e8e00`00080b91
8003f430  804e8e00`00080d12 804e8e00`0008137a
8003f440  00008500`00501198 804e8e00`0008179f
8003f450  804e8e00`000818bc 804e8e00`000819f9
8003f460  804e8e00`00081c52 804e8e00`00081f48
8003f470  804e8e00`0008267e 804e8e00`000828f3
8003f480  804e8e00`00082a10 804e8e00`00082b46
8003f490  804e8500`00a028f3 804e8e00`00082cac
8003f4a0  804e8e00`000828f3 804e8e00`000828f3
8003f4b0  804e8e00`000828f3 804e8e00`000828f3
8003f4c0  804e8e00`000828f3 804e8e00`000828f3
8003f4d0  804e8e00`000828f3 804e8e00`000828f3
8003f4e0  804e8e00`000828f3 804e8e00`000828f3
8003f4f0  804e8e00`000828f3 806f8e00`00081fd0
8003f500  00000000`00080000 00000000`00080000
8003f510  00000000`00080000 00000000`00080000
8003f520  00000000`00080000 00000000`00080000
8003f530  00000000`00080000 00000000`00080000
8003f540  00000000`00080000 00000000`00080000
8003f550  804dee00`0008fba2 804dee00`0008fca5
8003f560  804dee00`0008fe44 804eee00`0008078c
8003f570  804dee00`0008f631 804e8e00`000828f3
kd> eq 8003f500 0000e500`00480000
kd> dq idtr l30
8003f400  804e8e00`00080360 804e8e00`000804db
8003f410  00008500`0058113e 804eee00`000808ad
8003f420  804eee00`00080a30 804e8e00`00080b91
8003f430  804e8e00`00080d12 804e8e00`0008137a
8003f440  00008500`00501198 804e8e00`0008179f
8003f450  804e8e00`000818bc 804e8e00`000819f9
8003f460  804e8e00`00081c52 804e8e00`00081f48
8003f470  804e8e00`0008267e 804e8e00`000828f3
8003f480  804e8e00`00082a10 804e8e00`00082b46
8003f490  804e8500`00a028f3 804e8e00`00082cac
8003f4a0  804e8e00`000828f3 804e8e00`000828f3
8003f4b0  804e8e00`000828f3 804e8e00`000828f3
8003f4c0  804e8e00`000828f3 804e8e00`000828f3
8003f4d0  804e8e00`000828f3 804e8e00`000828f3
8003f4e0  804e8e00`000828f3 804e8e00`000828f3
8003f4f0  804e8e00`000828f3 806f8e00`00081fd0
8003f500  0000e500`00480000 00000000`00080000
8003f510  00000000`00080000 00000000`00080000
8003f520  00000000`00080000 00000000`00080000
8003f530  00000000`00080000 00000000`00080000
8003f540  00000000`00080000 00000000`00080000
8003f550  804dee00`0008fba2 804dee00`0008fca5
8003f560  804dee00`0008fe44 804eee00`0008078c
8003f570  804dee00`0008f631 804e8e00`000828f3

写入 CR3 后程序可以正常执行并退出。

实验:提权至 1 环

在 GDT 的 0xb0,0xb8,0xc0 偏移处分别构造 DPL = 1 的 CS,SS,FS 段寄存器。

kd> dq gdtr l30
8003f000  00000000`00000000 00cf9b00`0000ffff
8003f010  00cf9300`0000ffff 00cffb00`0000ffff
8003f020  00cff300`0000ffff 80008b04`200020ab
8003f030  ffc093df`f0000001 0040f300`00000fff
8003f040  0000f200`0400ffff 00000000`00000000
8003f050  80008955`23800068 80008955`23e80068
8003f060  00009302`2f40ffff 0000920b`80003fff
8003f070  ff0092ff`700003ff 80009a40`0000ffff
8003f080  80009240`0000ffff 00009200`00000000
8003f090  0000e242`55ec03ff 00000000`00000000
8003f0a0  8a008919`f2400068 00000000`00000000
8003f0b0  00000000`00000000 00000000`00000000
8003f0c0  00000000`00000000 00000000`00000000
8003f0d0  00000000`00000000 00000000`00000000
8003f0e0  f7009f66`7000ffff 00009200`0000ffff
8003f0f0  8003984d`9b287ca7 00009200`0000ffff
8003f100  ba40936f`f400ffff ba40936f`f400ffff
8003f110  ba40936f`f400ffff 00000000`8003f120
8003f120  00000000`8003f128 00000000`8003f130
8003f130  00000000`8003f138 00000000`8003f140
8003f140  00000000`8003f148 00000000`8003f150
8003f150  00000000`8003f158 00000000`8003f160
8003f160  00000000`8003f168 00000000`8003f170
8003f170  00000000`8003f178 00000000`8003f180
kd> eq 8003f0b0 00cfbb00`0000ffff
kd> eq 8003f0b8 00cfb300`0000ffff
kd> eq 8003f0c0 ffc0b3df`f0000001

运行如下代码,代码中的 tss 的寄存器已填充号前面构造的 1 环段的段选择子。

#include <Windows.h>
#include <stdio.h>unsigned short tcs, tss, tfs;void __declspec(naked) test() {__asm {mov tcs,csmov tss,ssmov tfs,fsiretd}
}int main() {char stack[100] = {0};DWORD Tss[0x68 / sizeof(DWORD)] = {0x00000000,           //Previous Task Link0x00000000,           //ESP00x00000000,           //SS00x00000000,           //ESP10x00000000,           //SS10x00000000,           //ESP20x00000000,           //SS20x00000000,           //Cr3(DWORD) test,         //EIP0x00000000,           //EFLAGS0x00000000,           //EAX0x00000000,           //ECX0x00000000,           //EDX0x00000000,           //EBX((DWORD) stack) + 100,//ESP0x00000000,           //EBP0x00000000,           //ESI0x00000000,           //EDI0x00000023,           //ES0x000000b1,           //CS0x000000b9,           //SS0x00000023,           //DS0x000000c1,           //FS0x00000000,           //GS0x00000000,           //LDT Segment Selector0x20ac0000};          //I/O Map Base Addressunsigned char buf[6] = {0, 0, 0, 0, 0x48, 0};printf("tss: %X\n", Tss);printf("cr3:");scanf("%X", &Tss[7]);__asm {call fword ptr buf}printf("cs: %X\nss: %X\nfs: %X\n", tcs, tss, tfs);return 0;
}

根据代码输出的 tss 地址构造 tss 段描述符:

kd> eq 8003f048 0000e912`feb40068

继续运行代码发现成功提权至 1 环。

目前用 call 总能成功,jmp 会蓝屏,原因未知

Windows保护模式(五)任务段任务门相关推荐

  1. Windows保护模式学习笔记(五)—— 任务段任务门

    Windows保护模式学习笔记(五)-- 任务段&任务门 要点回顾 任务段 TSS (Task-state segment ) TR段寄存器 TR段寄存器的读写 TSS段描述符 实验:加载自定 ...

  2. 2020-11-24(Windows保护模式学习笔记(1)—— 段寄存器与段权限检查)

    X86 CPU的三个模式:实模式.保护模式和虚拟8086模式 0x01 段寄存器 通常情况下,我们认为有8个段寄存器,他们分别是 ES CS SS DS FS GS LDTR TR 其中,后四个寄存器 ...

  3. Windows保护模式学习笔记(三)—— 长调用/短调用/调用门

    Windows保护模式学习笔记(三)-- 长调用/短调用/调用门 要点回顾 长调用与短调用 一.短调用 二.长调用(跨段不提权) 三.长调用(跨段并提权) 长调用执行时: 执行返回(RETF)时: 总 ...

  4. Windows保护模式学习笔记(二)—— 代码跨段跳转

    Windows保护模式学习笔记(二)-- 代码跨段跳转 要点回顾 代码跨段跳转 执行流程 1)段选择子拆分 2)查表得到段描述符 3)权限检查 4)加载段描述符 5)代码执行 6)总结 一致代码段(共 ...

  5. Windows保护模式学习笔记(四)—— 中断门陷阱门

    Windows保护模式学习笔记(四)-- 中断门&陷阱门 要点回顾 中断描述符表(IDT) 一.中断门 实验:构造一个中断门 第一步:初步构造参数 第二步:确定 Offset in Segme ...

  6. Windows保护模式学习笔记(一)—— 段寄存器GDT表

    Windows保护模式学习笔记(一)-- 段寄存器&GDT表 保护模式 参考书籍: 一.段寄存器 段寄存器的结构 段寄存器的读写 段寄存器的属性 1)探测Attribute: 2)探测Base ...

  7. Windows保护模式学习笔记(十二)—— 控制寄存器

    Windows保护模式学习笔记(十二)-- 控制寄存器 控制寄存器 Cr0寄存器 Cr2寄存器 Cr4寄存器 控制寄存器 描述: 控制寄存器有五个,分别是:Cr0 Cr1 Cr2 Cr3 Cr4 Cr ...

  8. Windows保护模式学习笔记(九)—— 2-9-9-12分页

    Windows保护模式学习笔记(九)-- 2-9-9-12分页 要点回顾 10-10-12分页 原理 环境配置 2-9-9-12分页 原理 PDPTE PDE PTE XD/NX标志位 环境配置 实验 ...

  9. Windows保护模式学习笔记(六)—— 10-10-12分页

    Windows保护模式学习笔记(六)-- 10-10-12分页 基本概念 4GB内存空间 有效地址-线性地址-物理地址 有效地址与线性地址 物理地址 控制寄存器:Cr3 10-10-12分页 实验:通 ...

  10. x86保护模式 任务状态段和控制门

    x86保护模式    任务状态段和控制门 每个任务都有一个任务状态段TSS     用于保存任务的有关信息     在任务内权变和任务切换时  需要用到这些信息    任务内权变的转移和任务切换  一 ...

最新文章

  1. 《Kotlin项目实战开发》第1章 Kotlin是什么
  2. Ubuntu 安装 Qt 开发环境 简单实现
  3. 基于RBAC模型的通用权限管理系统的设计(数据模型)的扩展
  4. 6升小米6——算法解题
  5. 常见的虚拟机需要配置的服务
  6. 【OS学习笔记】三十一 保护模式九:页目录、页表和页三者的关系详解
  7. 保存 laravel model 而不更新 timestamps 的方法
  8. qt 窗口自绘、鼠标响应拖动窗口
  9. 算法--生成1~n的排列
  10. 广告创意还是侮辱女性?全棉时代卸妆巾广告被骂上热搜......
  11. coreboot学习6:ramstage阶段之芯片初始化流程
  12. 等响度曲线_等响曲线是如何绘制的?响度级
  13. Java设计模式之工厂方法模式与抽象工厂模式
  14. Apache Solr Java 企业级搜索引擎
  15. 【一周头条盘点】中国软件网(2018.9.10~2018.9.14)
  16. SqlServer 多服务器管理(MSSQL分布式作业管理)
  17. 计算机型号或配置,新手必看电脑配置及型号含义速成!
  18. 线性方程组求解——基于MTALAB/Octave,Numpy,Sympy和Maxima
  19. 普通软件加入开机启动项
  20. 逆转ISP,港科大陈启峰团队提出了可逆ISP

热门文章

  1. 产品经理的修炼:如何把梳子卖给和尚
  2. C++利用opencv调用pytorch训练好的分类模型
  3. 漂流幻境服务器文件,飘流幻境 飘流幻境常用合成资料汇总
  4. 用Java实现简单的语音朗读
  5. dbcp连接池不合理的锁导致连接耗尽
  6. OPPO PUSH 配额
  7. [@vue/compiler-sfc] defineProps is a compiler macro and no longer needs to be imported
  8. python统计列表中重复_查找统计python列表中的重复元素
  9. linux控制pwm输出个数,树莓派精确控制pwm输出,控制步进电机
  10. char字符对应的ASCII码值