Windows保护模式(五)任务段任务门
任务段
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保护模式(五)任务段任务门相关推荐
- Windows保护模式学习笔记(五)—— 任务段任务门
Windows保护模式学习笔记(五)-- 任务段&任务门 要点回顾 任务段 TSS (Task-state segment ) TR段寄存器 TR段寄存器的读写 TSS段描述符 实验:加载自定 ...
- 2020-11-24(Windows保护模式学习笔记(1)—— 段寄存器与段权限检查)
X86 CPU的三个模式:实模式.保护模式和虚拟8086模式 0x01 段寄存器 通常情况下,我们认为有8个段寄存器,他们分别是 ES CS SS DS FS GS LDTR TR 其中,后四个寄存器 ...
- Windows保护模式学习笔记(三)—— 长调用/短调用/调用门
Windows保护模式学习笔记(三)-- 长调用/短调用/调用门 要点回顾 长调用与短调用 一.短调用 二.长调用(跨段不提权) 三.长调用(跨段并提权) 长调用执行时: 执行返回(RETF)时: 总 ...
- Windows保护模式学习笔记(二)—— 代码跨段跳转
Windows保护模式学习笔记(二)-- 代码跨段跳转 要点回顾 代码跨段跳转 执行流程 1)段选择子拆分 2)查表得到段描述符 3)权限检查 4)加载段描述符 5)代码执行 6)总结 一致代码段(共 ...
- Windows保护模式学习笔记(四)—— 中断门陷阱门
Windows保护模式学习笔记(四)-- 中断门&陷阱门 要点回顾 中断描述符表(IDT) 一.中断门 实验:构造一个中断门 第一步:初步构造参数 第二步:确定 Offset in Segme ...
- Windows保护模式学习笔记(一)—— 段寄存器GDT表
Windows保护模式学习笔记(一)-- 段寄存器&GDT表 保护模式 参考书籍: 一.段寄存器 段寄存器的结构 段寄存器的读写 段寄存器的属性 1)探测Attribute: 2)探测Base ...
- Windows保护模式学习笔记(十二)—— 控制寄存器
Windows保护模式学习笔记(十二)-- 控制寄存器 控制寄存器 Cr0寄存器 Cr2寄存器 Cr4寄存器 控制寄存器 描述: 控制寄存器有五个,分别是:Cr0 Cr1 Cr2 Cr3 Cr4 Cr ...
- Windows保护模式学习笔记(九)—— 2-9-9-12分页
Windows保护模式学习笔记(九)-- 2-9-9-12分页 要点回顾 10-10-12分页 原理 环境配置 2-9-9-12分页 原理 PDPTE PDE PTE XD/NX标志位 环境配置 实验 ...
- Windows保护模式学习笔记(六)—— 10-10-12分页
Windows保护模式学习笔记(六)-- 10-10-12分页 基本概念 4GB内存空间 有效地址-线性地址-物理地址 有效地址与线性地址 物理地址 控制寄存器:Cr3 10-10-12分页 实验:通 ...
- x86保护模式 任务状态段和控制门
x86保护模式 任务状态段和控制门 每个任务都有一个任务状态段TSS 用于保存任务的有关信息 在任务内权变和任务切换时 需要用到这些信息 任务内权变的转移和任务切换 一 ...
最新文章
- 《Kotlin项目实战开发》第1章 Kotlin是什么
- Ubuntu 安装 Qt 开发环境 简单实现
- 基于RBAC模型的通用权限管理系统的设计(数据模型)的扩展
- 6升小米6——算法解题
- 常见的虚拟机需要配置的服务
- 【OS学习笔记】三十一 保护模式九:页目录、页表和页三者的关系详解
- 保存 laravel model 而不更新 timestamps 的方法
- qt 窗口自绘、鼠标响应拖动窗口
- 算法--生成1~n的排列
- 广告创意还是侮辱女性?全棉时代卸妆巾广告被骂上热搜......
- coreboot学习6:ramstage阶段之芯片初始化流程
- 等响度曲线_等响曲线是如何绘制的?响度级
- Java设计模式之工厂方法模式与抽象工厂模式
- Apache Solr Java 企业级搜索引擎
- 【一周头条盘点】中国软件网(2018.9.10~2018.9.14)
- SqlServer 多服务器管理(MSSQL分布式作业管理)
- 计算机型号或配置,新手必看电脑配置及型号含义速成!
- 线性方程组求解——基于MTALAB/Octave,Numpy,Sympy和Maxima
- 普通软件加入开机启动项
- 逆转ISP,港科大陈启峰团队提出了可逆ISP
热门文章
- 产品经理的修炼:如何把梳子卖给和尚
- C++利用opencv调用pytorch训练好的分类模型
- 漂流幻境服务器文件,飘流幻境 飘流幻境常用合成资料汇总
- 用Java实现简单的语音朗读
- dbcp连接池不合理的锁导致连接耗尽
- OPPO PUSH 配额
- [@vue/compiler-sfc] defineProps is a compiler macro and no longer needs to be imported
- python统计列表中重复_查找统计python列表中的重复元素
- linux控制pwm输出个数,树莓派精确控制pwm输出,控制步进电机
- char字符对应的ASCII码值