Loading... # 保护模式 32位保护模式下存储的是段选择子,不再是段基址。真正的段基址在描述高速缓冲中。 16位保护模式。因为16位寄存器最大不能超过64KB。妨碍发展。所以被人淡忘。 | x86支持-3种模式 | | - | | 实模式:兼容16位CPU | | 保护模式:操作系统所在模式 | | 虚拟8086模式:可以模拟多个8086执行多个任务 | # 段寄存器 16位寄存器:DS(数据段) SS(堆栈段) ES(附加段) CS(代码段) 32位寄存器:FS(Flag segment标志段寄存器) GS(Global segment全局段寄存器) --- TI 为1-LDT:局部描述符。Windows没有使用LDT描述符。 TI 为0-GDT:全局描述符。 ![image.png](http://www.irohane.top/usr/uploads/2021/02/2615006639.png) ```cpp typedef struct _SELECTOR { unsigned short index: 13; // index 是存在于 GDT 或 LDT 中元素的索引 unsigned short ti: 1; // 为 0 表示 GDT 否则是 LDT,windows 始终各为 0 unsigned short rpl: 2; // 请求权限级别,表示使用什么样的权限访问 } ``` # 段描述符 通过Index寻找到段描述符: ![image.png](http://www.irohane.top/usr/uploads/2021/02/1399962478.png) ![20200525003046906.png](http://www.irohane.top/usr/uploads/2021/02/89603736.png) 段描述符是GDT、LDT的一种<span style="color:#FF0000">数据结构</span>,提供一个段位、大小、访问控制的状态信息、每个段的长度为8字节(图中就是一个段描述符的结构、上下各4字节)。 | 描述符号 | 作用 | 附加说明 | | - | - | - | | `P` | 1则段描述符有效,0则断描述符无效 | 系统首先会检测P位是是否有效性。 | | 粒度G位 | 为0,limit单位为字节。为1limit单位是4KB | | | Limit段长 | 处理器会把两个段限长字段合为一个20位的值,根据G来指定Limit的含义 | 若 G 为 1:假设 Limit 为 0xFFFFF,此时最终限长为 0xFFFFF × 0x1000 + 0xFFF -> 0xFFFFFFFF若 G 为 0:假设 Limit 为 0xFFFFF,此时最终限长为 0xFFFFF × 1 -> 0xFFFFF | | 基地址字段Base | 描述一个段的起始,由三个部分组成,一共32位,0~4GB范围内的任意地址 | 由 3 个部分组成,分别对应了 32 位基址的 0 ~ 15、16 ~ 23 以及 24 ~ 31 位,表示段基地址 | | S | 为1 代码/数据段 为0是系统段 | 需要配合TYPE食用 | | TYPE | 描述符字段的信息,一共4位,根据S的字段来表示不同意思 | 需要配合S食用 | | L | 64位标识,保留给64位使用 | 如果当前的处理哦其处于 64 位模式,就会提供 L 位进行标识,表示当前使用的是长模式 | | AVL | 软件可以使用的位,由操作系统使用,处理器不使用 | | | DPL | 存在于段描述符种,描述本段内存所需要的权限 | | | D\B | 默认使用单位 | 用于设置默认操作数的大小和默认地址的大小。对于栈来说,通常将这一位成为 B 位,当 B 位为1时,默认对 ESP 的操作是以 4 字节计算的,例如 push 1 实际执行了 sub esp, 4 的操作。对于其它情况,该位被称作 D 位,表示默认使用的是 4 字节还是 2 字节。通过 OPCODE 指令前缀可以修改操作数和地址大小。 | ```cpp typedef struct _DESCRIPTOR { unsigned int limit1: 16; // 段限长 [0~15] unsigned int base1: 16; // 段基址 [0~15] unsigned int base2: 8; // 段基址 [16~23] unsigned int type: 4; // 段的类型 unsigned int s: 1; // 当前是系统段还是用户段 unsigned int dpl: 2; // 访问当前段需要用到的权限 unsigned int p: 1; // 表示当前的段是否是有效的 unsigned int limit2: 4; // 段限长 [16~19] unsigned int avl: 1; // 保留给操作系统的 unsigned int L: 1; // 是否是长模式 unsigned int db: 1; // 默认使用的单位 unsigned int G: 1; // 表示 limit 的单位 unsigned int base3: 8; // 段基址 [24~31] } ``` # 用户段 当 S 位为 1 时,表示当前就是用户段,用户段又存在了两种状态,分别是代码段和数据段 * 如果 TYPE 位的最高位为 1,就表示当前是代码段,此时看到的 TYPE 整体会大于 7 * C: 表示当前是否是一致代码段。如果但其概念是一致代码段,就表示我们可以使用低权限访问高权限的内容。如果但其概念是非一致代码段,那么要求访问者个被访问者权限必须一致 。 * R: 当前的段是否是可读的 * A: 表示当前的段是否被访问了,如果被访问了就为 1 * 如果 TYPE 位的最高位为 0,就表示当前是数据段,此时看到的 TYPE 整体会小于 8 * E: 表示当前是向上扩展(extend-up)段还是向下扩展(extend-down)段 * W: 表示当前的段是可写的 * A: 表示当前的段是否被访问了,如果被访问了就为 1 ![image-20210201110642115.png](http://www.irohane.top/usr/uploads/2021/02/3660057756.png) [[windows内核]段描述符属性:S位_TYPE域](https://blog.csdn.net/r250414958/article/details/106324204) [GDT,LDT,GDTR,LDTR 详解,包你理解透彻](https://www.techbulo.com/708.html) # 权限检查 * 通过 lxs 和 mov xs, ax 可以切换段选择子 加载段选择符进入段寄存器的时候 * CS寄存器只能存放代码段的选择符 * 代码段选择符可以被加载到数据段寄存器,但是不可读的代码段选择符不能被加载进入数据段寄存器(因为数据段都是可读的) * 只有可读可写数据段选择符才能加载到SS寄存器(SS寄存器一定是可写的) * 当前接触到的三种权限: * CPL:特指 CS 段寄存器的最低两位,表示当前所拥有(当前执行代码)的权限 * 当前操作系统登录用户的权限 * RPL:指任何一个段选择子的最低两位,表示使用什么样的权限进行请求 * 当前是否使用了管理员方式打开目标程序 * DPL:想要切换到当前的段描述符需要什么样的权限 * 当前的应用程序最少需要使用什么样的权限 ![image-20210201110217342.png](http://www.irohane.top/usr/uploads/2021/02/2700137890.png) # 手动查看 ## 查看段选择子 WinDbug 双机环境 r 查看寄存器 ![image.png](http://www.irohane.top/usr/uploads/2021/02/3468789932.png) 高 | 段寄存器 | 操作数 | 二进制(只显示低16位可见部分) | 段选择子 | 描述符表索引:13 | TI:1 | RPL:2 | | - | - | - | - | - | - | - | | cs | 0008 | 0000 0000 0000 1000 | | 0000 1 - 1 | GDT | 00 | | ss | 0010 | 0000 0000 0001 0000 | | 0001 0 - 2 | GDT | 00 | | ds | 0023 | 0000 0000 0010 0011 | | 0010 0 - 4 | GDT | 11-3 | | es | 0023 | 0000 0000 0010 0011 | | 0010 0 - 4 | GDT | 11-3 | | fs | 0030 | 0000 0000 0011 0000 | | 0011 0 - 5 | GDT | 00 | | gs | 0000 | | | | | | ## 查看段描述符表 使用 WinDbug 查看描述表索引对应的。描述符表 CS = 1(INDEX) + 0(TI) + 00(RPL),通过 dq gdtr+(INDEX*8) 找到段描述符表 ![image.png](http://www.irohane.top/usr/uploads/2021/02/4071911323.png) | 段选择器 | 描述符表索引 | 描述符表 | | - | - | - | | cs | 1 | 00cf9b00`0000ffff | | ss | 2 | 00cf9300`0000ffff | | ds | 4 | 00cff300`0000ffff | | es | 4 | 00cff300`0000ffff | | fs | 5 | 80008b1e`600020ab | 由于太多不一 一举例 | 高4位 | | 基地址(31-24) | G(23) | D/B(22) | O(21) | AVL(20) | 段限长(19-16) | P(15) | DPL(14-13) | S(12) | TYPE(11-8) | 基地址(7-0) | | - | - | - | - | - | - | - | - | - | - | - | - | - | | 00cf9b00 | 0000 0000 1100 1111 1001 1011 0000<br />0000 | 0000<br />0000 | 1 | 1 | 0 | 0 | 1111 | 1 | 00 | 1 | 1011 | 0000 0000 | | 00cf9300 | 0000<br />0000<br />1100<br />1111<br />1001<br />0011<br />0000<br />0000 | 0000<br />0000 | 1 | 1 | 0 | 0 | 1111 | 1 | 00 | 1 | 0011 | 0000<br />0000 | 最后修改:2021 年 03 月 08 日 © 允许规范转载 赞 0 如果觉得我的文章对你有用,请随意赞赏