段描述符

CPU分级

用户程序 -> 3环
内核程序 -> 0环

o_2109200928364-8

选择子

结构图

o_2109200226344-2

选择子大小 2字节(WORD)

RDL(Requested Privilege Level)请求特权级别

当前段寄存器的请求级别,越小,级别越高,高权限可以访问同级别和比当前级别低的段描述符

TI

判断是查GDT表还是LDT表
TI = 1 查GDT表
TI = 0 查LDT表

Index

段描述符的索引值

选择子 0x2B
0000 0000 0010 1011
RPL: 0x11b -> 3
TI: 1 ->查GDT表
Index: 0000 0000 0010 1 -> 5 也就是GDT表第6个 8字节 (下表从0开始)

段描述符

段描述符结构

o_2109191244474-1

P位

判断当前段描述符是否有效
P = 1 有效
P = 0 无效

Base

大小为 4字节(DWORD)
由三部分组成 高四字节的 高8位 和 低8位 加上 低四字节的 高16位 组成完整的Base

Limit

大小为 4字节 (DWORD)
根据段描述符的结构图,我们可以拼出 19~0位
高四字节的 19~16位 + 低四字节的 15~0位
完整的Limit还需要G位来补充
如下

G位

G位的不同会导致 Limit 大小的变化
G = 0 在现有的Limit高位 补12位0
现在Limit = 0x12345
补全Limit = 0x00012345

G = 1 在现有的Limit地位 补12位1 也就是3个F
现在Limit = 0x12345
补全Limit = 0x12345FFF

S位

判断段描述符为 数据或者代码段描述符 还是 系统段描述符
S = 1 数据或者代码段描述符
S = 0 系统段描述符

TYPE域

根据 S位的不同 有不一样的含义

S = 1

此时段描述符具体是数据段还是代码段,可以通过TYPE的最高位是否为 1 做判断
o_2109200324584--4

A: 访问位(被访问过)
E: 向下扩展位
R: 可读
W: 可写
C: 一致位

E = 1 向下扩展
E = 0 向上扩展
o_2109200327104-5

左边为向上扩展
右边为向下扩展
向上扩展:段寄存器的访问区间为 Base ~ Base + Limit
向下扩展:段寄存器的访问区间为除了 Base ~ Base + Limit 的其他区域

S = 0

此时段描述符表示的是系统段
TYPE域对应系统段不同的含义
o_2109200325124-6

D/B位

对CS段的影响

D = 1采用32位寻址方式
D = 0采用16位寻址方式

对SS段的影响

D = 1 隐式堆栈访问指令(如:PUSH POP CALL)使用32位堆栈指针寄存器ESP
D = 0 隐式堆栈访问指令(如:PUSH POP CALL)使用16位堆栈指针寄存器SP

向下扩展的数据段

如果说向下向上扩展决定了访问区间
那么D/B位就是决定数据段加载的边界
D = 1段上限为4GB 0 ~ 0xFFFFFFFF
D = 0段上限为64KB 0 ~ 0xFFFF

o_2109200412524-7

边界 和 Limit 是两个独立的概念 不要搞混

DPL

DPL(Descriptor Privilege Level),描述符特权级别,规定了访问该段所需要的特权级别是什么。

段寄存器 根据选择子 中的 RPL 根据Index 加载段描述符
此时权限级别必须满足 RPL <= DPL

### 练习

从windbg 获取 GDT表

kd> r gdtr
gdtr=8003f000
kd> dq 0x8003f000 
ReadVirtual: 8003f000 not properly sign extended
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  80008954`af000068 80008954`af680068
8003f060  00009302`2f40ffff 0000920b`80003fff
8003f070  ff0092ff`700003ff 80009a40`0000ffff
  1. 练习读取GDT表的位置和长度,并显示GDT表前48个段描述符。
    PixPin_2026-07-22_15-43-06

2.在给定的段描述符中,进行拆分练习
00cf9b00 0000ffff
P = 1 有效
G = 1 Limit = 0xffffffff
Base = 0x00000000
D/B = 1
AVL = 0
DPL = 00b
S = 1 代码或者数据段
Type = b = 1011

80008b04 200020ab
P = 1 有效
G = 0 Limit = 0x000020ab
Base = 0x80042000
D/B = 0
AVL = 0
DPL = 00b = 0
S = 0 系统段
Type = b = 1011

3.拆分如下段选择子。

002B   0023   0010   001B   003B

002B = 0000 0000 0010 1011 = 0000 0000 0010 1(Index) 0(TI) 11(RPL)
0023 = 0000 0000 0010 0011 = 0000 0000 0010 0(Index) 0(TI) 11(RPL)
0010 = 0000 0000 0001 0000 = 0000 0000 0000 1(Index) 0(TI) 00(RPL)
001B = 0000 0000 0001 1011 = 0000 0000 0001 1(Index) 0(TI) 11(RPL)
003B = 0000 0000 0011 1011 = 0000 0000 0011 1(Index) 0(TI) 11(RPL)

4.快速辨别给定段描述符是否可用以及段基址、段长

5.如何判断系统段描述符还是数据或代码段描述符
根据S位
S = 1 数据或代码段描述符
S = 0 系统段描述符
00cf9300 0000ffff S位于前四个字节的第12位
所以我们只需要判断 9 (1001) 这里的在低位就是四字节里面的第12位
简单来说,我们只需要判断前四字节里面 15~12 位中,第12位是否为 1 或者 0 即可判断是系统段描述符还是数据或代码段描述符

00cffb00 0000ffff 15~12位 = f(1111) 数据或代码段描述符
00009302 2f40ffff 15~12位 = 9(1001) 数据或代码段描述符
80008954 af000068 15~12位 = 8(1000) 系统段描述符

6.判断那些是代码描述符还是数据描述符
根据S位,我们可以判断系统段描述符还是数据或代码段描述符
S = 1, 此时TYPE域 用来具体的分辨段描述符为数据或代码段描述符

根据前四字节的 11~8位 ,第11位 是否为 1 或者 0 即可判断是数据段描述符还是代码段描述符

00cffb00 0000ffff 15~12位 = f(1111) type 11~8位 = b(1011) 代码段描述符
00009302 2f40ffff 15~12位 = 9(1001) type 11~8位 = 3(0011) 数据段描述符

7.查分几个数据段: E W A
E:向下扩展位
W:可写
A:访问过
00009302 2f40ffff 15~12位 = 9(1001) type 11~8位 = 3(0011) 数据段描述符 R/W + A

8.查分几个代码段: C R A
C:一致位
R:可读
A:访问过
此处的E = Execute
00cffb00 0000ffff 15~12位 = f(1111) type 11~8位 = b(1011) 代码段描述符 E/R + A
f8009f71 a000ffff 15~12位 = 9(1001) type 11~8位 = f(1111) 代码段描述符 E/R + C + A

9.查分几个系统段
S = 0
80008954 af000068 15~12位 = 8(1000) type 11~8位 = 9(1001) 系统段描述符 32-bit TSS(Available)
`80008b04`200020ab` 15~12位 = 8(1000) type 11~8位 = b(1011) 系统段描述符 32-bit TSS(Busy)

10.如何在调试器中快速判断程序在几环权限
EIP(CPU)运行到哪,可以根据段寄存器,判断当前CPU执行在哪个环
根据段寄存器csss 可以判断 CPL(Current Privilega Level)当前特权级别 = 11 = 3 --> 3环
PixPin_2026-07-22_16-11-49

当我们使用windbg 调试winXP
查看寄存器可以发现,cs = 8 = 1000 ->后两位为00 -> 0 环
PixPin_2026-07-22_20-09-13

11.在 3环 能加载的数据段有那些?
判断DPL(描述符权限级别)
描述符权限级别 根据高四字节 15~12位 之间的 13和14位
00cffb00 0000ffff f = 1111 -> DPL = 11 = 3 能够加载在 3环
00cff300 0000ffff f = 1111 -> DPL = 11 = 3 能够加载在 3环

12.在 0环 能加载的数据段有那些?
判断DPL(描述符权限级别)
00cf9b00 0000ffff 9 = 1001 -> DPL = 00 = 0 能够加载在 0环
00cf9300 0000ffff 9 = 1001 -> DPL = 00 = 0 能够加载在 0环
80008954 af000068 8 = 1000 -> DPL = 00 = 0 能够加载在 0环
80008954 af680068 8 = 1000 -> DPL = 00 = 0 能够加载在 0环

13.详细描述这下面代码的执行过程:

mov ax, 0x23
mov ds, ax

把0x23(0010 0011)存放到 ax
然后把ax(0x23) 写入段寄存器ds
根据段寄存器的结构,我们可以知道我们看不见的80位,是根据选择子的前13位 -> 0000 0000 0010 0 = 4 ->根据我们GDT表,可以知道
此处的段描述符是 第5个 00cff300 0000ffff

posted @ 2026-07-22 21:59  书与兔子  阅读(3)  评论(0)    收藏  举报