段寄存器位96位但是可见位数只有16位,剩下80位怎么填充?80位里每一位代表什么意思?
上面为段描述符的结构
这里学习一下怎么快捷使用gdt表和idt表,还有拆分段描述符
0: kd> r gdtr //常规访问gdt表 0: kd>dq 8003f000 0: kd> dq gdtr //当进一步缩写时 //如果我们要查看段描述符,需要对照查看 0: kd> dq 8003f008 8003f008 00cf9b00`0000ffff 0: kd> dq 8003f010 8003f010 00cf9300`0000ffff //当使用dg命令时: 0: kd> dg 08 P Si Gr Pr Lo Sel Base Limit Type l ze an es ng Flags ---- -------- -------- ---------- - -- -- -- -- -------- 0008 00000000 ffffffff Code RE Ac 0 Bg Pg P Nl 00000c9b // 0: kd> dg 10 P Si Gr Pr Lo Sel Base Limit Type l ze an es ng Flags ---- -------- -------- ---------- - -- -- -- -- -------- 0010 00000000 ffffffff Data RW Ac 0 Bg Pg P Nl 00000c93
P位(15):段描述符有效位
P=1 段描述符有效
P=0 段描述符无效
DPL位(13-14):访问该段的权限级别(Descriptor Privilege Level)
S位(12): 系统段描述符/用户段描述符
S=1 代码段或者数据段描述符
S=0 系统段描述符
P+DPL+S位联合拆解:
p位 DPL DPL S位 TYPE TYPE
TYPE TYPE 15
14 13 12 11 10 9 8 1 1/01/0 1/0 1/0 1/0 1/0 1/0
p位为1时段描述符才有效,DPL只能同时为1或者同时为0,S位为1时才是代码段或者数据段
当12位到15位
情况1:P位一定为1,DPL为3(11),S位为1,这个段描述符有效,且DPL为3,是系统段描述符
那么12到15位就是F
情况2: P位一定为1,DPL为0(00),S位为1, 这个段描述符有效,且DPL为0,是系统段描述符
那么12到15位就是9
00cffb00`0000ffff 00cf9b00`0000ffff
情况3: P位一定为1,DPL为0(00),S位为0,这个段描述符有效,且DPL为0,是用户段描述符
80008b04`200020ab
-------------------------------------------------------------------------------------------------------------------------------------------------------------- TYPE位(8-11):属性位,由S位来决定TYPE位的属性 --------------------------------------------------------------------------------------------------------------------------------------------------------------
当S位为1的时候,TYPE位里是数据段或者代码段
8到11位决定了是代码段描述符,还是数据段描述符
数据段描述符:
- 0-只读
- 1-只读,并且被访问过
- 2-可读,可写
- 3-可读,可写,并且被访问过
- 4-只读,向下扩展
- 5-只读,向下扩展,并且被访问过
- 6-可读,可写,向下扩展
- 7-可读,可写,向下扩展,并且被访问过
向下扩展属性位:
代码段描述符:
- 8-只可执行
- 9-只可执行,被执行过1次以上
- A-可执行,可读
- B-可执行,可读,被执行过1次以上
- C-只可执行,一致代码段
- D-只可执行,一致代码段,被执行过一次以上
- E-可执行,可读,一致代码段
- F-可执行,可读,一致代码段,被执行过一次以上
一致代码段:
简单理解,就是操作系统拿出来被共享的代码段,可以被低特权级的用户直接调用访问的代码
通常这些共享代码,是"不访问"受保护的资源和某些类型异常处理。比如一些数学计算函数库,为纯粹的数学运算计算
一致代码段的限制作用
特权级高的程序不允许访问特权级低的数据: Ring3不允许调用Ring0的数据
特权级低的程序可以访问到特权级高的数据 但是特权级不会改变: 权限不会发生切换,不会从Ring3进入Ring0
非一致代码段的限制作用
只允许同级间访问
绝对禁止不同级访问: 核心态不用用户态.用户态也不使用核心态
通常低特权代码必须通过"门"来实现对高特权代码的访问和调用
这里了解即可
拆分用户段TYPE位实战
这里有一个技巧
当TYPE为数据段描述符的时候,第11位一定为0
当TYPE为代码段描述符的时候,第11位一定为1
当TYPE位4个属性位组合成一个16进制数的时候,当这个数大于8则一定是代码段描述符,小于8则是数据段描述符,如果不懂建议去搬砖
-----3--`-------- //数据段描述符,可读,可写,被访问过 -----b--`-------- //代码段描述符,可执行,可读,并且被执行了1次以上 -----9--`-------- //代码段描述符,只可执行,并且被执行了1次以上 -----2--`-------- //数据段描述符,只读,并且被访问过
当S位为0的时候,TYPE位里是系统段描述符
- 0-保留
- 1-可获得的16位TSS
- 2-LDT
- 3-繁忙的16位TSS
- 4-16位调用门
- 5-任务门
- 6-16位中断门
- 7-16位陷阱门
- 8-保留
- 9-可获得的32位TSS
- A-保留
- B-繁忙的32位TSS
- C-32位调用门
- D-保留
- E-32位中断门
- F-32位陷阱门
实战拆解系统段描述符 -----3--`-------- //繁忙的16位TSS -----c--`-------- //32位调用门 -----7--`-------- //16位陷阱门 -----f--`-------- //32位陷阱门
TYPE位检查
当CPU使用段或者门的时候,其中的检查步骤之一就是检查GDT表中的的段描述符的TYPE位的属性,当
GDT表中存在中断门的时候,通过call或者jmp访问中断门的时候,CPU就会在硬件层面抛出一个异常--------------------------------------------------------------------------------------------------------------------------------------------------------
实战P位+DPL位+S位+TYPE位联合拆解,直接拆分GDT表的内容
00cf9b00`0000ffff //这个段描述符有效,DPL为3(11),S位为1,是用户段描述符,且是代码段描述符,只可执行,并且被执行了1次以上 00cf9300`0000ffff //这个段描述符有效,且DPL为0(00),S位为1,是用户段描述符,且是数据段描述符,可读,可写,并且被访问过 80008b04`200020ab //这个段描述符有效,且DPL为0(00),S位为0,是系统段描述符,且是繁忙的32位TSS 0000f200`0400ffff //这个段描述符有效,切DPL为3(00),且S位为1,是用户段描述符,且是数据段描述符,可读可写
--------------------------------------------------------------------------------------------------------------------------------------------------------
G位(23):粒度 字节/页
我们先看看段描述符的结构
Struct SegMent { WORD Select; //16位段选择子 WORD Attributes; //16位属性 DWORD Base; //32位基址 DWORD Limit; //32位段限长 }
除去16位段选择子,剩下16位属性,32位基址,32位段限长,16+32+32为80位
段基址位(0-8位+24-31位)[32位]+(16-31位)
段限长16-19位+0-15位,只有20位,剩下的12位怎么填充呢?由G位来决定
如果 G = 0,把段描述符中的LIMIT取出来,比如 0xfffff,然后在前面补 0 至32bit,即 limit = 0x000fffff 如果 G = 1,把段描述符中的LIMIT取出来,比如 0xfffff,然后在后面补 f 至32bit, 即 LIMIT = 0xffffffff
G位存在的意义除了填充属性位以外:兼容 优化
当系统使用TSS段的时候,每个TSS大小至少为104个字节
当前正在运行的CPU里的线程为2529,如果存在G位,每个线程的TSS加起来才使用了256KB
如果没有G位,内存分页为4K小页时。占用内存为10M,如果为大页,则会非常耗费空间,这里只做了解
如果没有 G 位,将会极大浪费内存空间
DB位(22):扩展属性位,争对不同的段描述符有不同的影响,通常由S位来决定DB位的作用
代码段 D:默认操作数大小-32位系统里加指令前缀当成16位来操作
数据段 B:扩展属性位
向上扩展:Base起始地址,Limit最大有效地址
向下扩展:Limit最低有效地址 最高地址由DB位中的B来决定
B=0:64K B=1:4G
情况一:对CS段的影响
情况一:对CS段的影响
D = 0 采用16位寻址方式
前缀67 改变寻址方式
67:8965 FF MOV DWORD PTR DS:[DI+FFFF],ESP //DI 16位
情况二:对SS段的影响
D = 1 隐式堆栈访问指令(如:PUSH POP CALL) 使用32位堆栈指针寄存器ESP
D = 0 隐式堆栈访问指令(如:PUSH POP CALL) 使用16位堆栈指针寄存器SP
隐式堆栈访问(比如PUSH EAX的时候,并没有动ESP寄存器,但是堆栈会自动变化)
情况三:向下拓展的数据段
D = 1 段上限为4GB
D = 0 段上限为64KB
AVL(20):可以获取,CPU与OS都没有使用
自由发挥