写在前面
此系列是本人一个字一个字码出来的,包括示例和实验截图。由于系统内核的复杂性,故可能有错误或者不全面的地方,如有错误,欢迎批评指正,本教程将会长期更新。 如有好的建议,欢迎反馈。码字不易,如果本篇文章有帮助你的,如有闲钱,可以打赏支持我的创作。如想转载,请把我的转载信息附在文章后面,并声明我的个人信息和本人博客地址即可,但必须事先通知我。
看此教程之前,问几个问题,
🔒 华丽的分割线 🔒
练习及参考
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`22000068 80008955`22680068
8003f060 00009302`2f40ffff 0000920b`80003fff
8003f070 ff0092ff`700003ff 80009a40`0000ffff
8003f080 80009240`0000ffff 00009200`00000000
1️⃣ 练习读取GDT表的位置和长度,并显示GDT表前48个段描述符。
2️⃣ 在给定的段描述符中,进行拆分练习(至少10个)。
3️⃣ 拆分如下段选择子。
002B 0023 0010 001B 003B
4️⃣ 快速辨别给定段描述符是否可用以及段基址、段长(至少10个)。
5️⃣ 从给定段描述符,请按照下面的要求进行练习(全部):
- 快速找出所有数据段,并分析该段属性:只读、已访问、可读可写、拓展方向
- 快速找出所有代码段,并分析该段属性:只执行、可读可执行、已访问、一致代码
- 快速找出所有系统段,并分析属性
6️⃣ 自行构造段选择子和段描述符,并用加载段描述符至段寄存器
中的代码模板和要求取得成功。如果有时间同样把LSS
、LDS
、LFS
、LGS
的实验也类比做了。
7️⃣ 如何在调试器中快速判断程序在几环权限。
8️⃣ 自学修改GDT表的相关知识,并思考如下问题。
r gdtr
dq 8003f090 00cffb00`0000ffff
r gdtr
8003f090
是GDT表中的一个段描述符的地址,更改后发现并没有更改,请思考为什么会这样。
CPL/RPL/DPL
- CPL:CPU当前的权限级别
- DPL:如果你想访问我,你应该具备什么样的权限(CPL)
- RPL:用什么权限去访问一个段
RPL存在的意义:
举个例子,我们本可以用读写
的权限去打开一个文件,但为了避免出错,有些时候我们使用只读
的权限去打开。
一致代码段与非一致代码段
对于一致代码段,也称为共享段:
- 特权级高的程序不允许访问特权级低的数据:核心态不允许访问用户态的数据
- 特权级低的程序可以访问到特权级高的数据,但特权级不会改变:用户态还是用户态
对于非一致代码段:
- 只允许同级访问
- 绝对禁止不同级别的访问:核心态不是用户态,用户态也不是核心态
数据段的权限检查
数值上,CPL
<=DPL
且RPL
<=DPL
。同时满足上述条件才能通过。
代码段的权限检查
下面的比较都是数值上的比较:
- 如果是非一致代码段,要求:
CPL
==DPL
且RPL
<=DPL
- 如果是一致代码段,要求:
CPL
>=DPL
代码跨段基础
代码跨段本质就是修改CS段寄存器。前面的教程介绍过段寄存器读写,除CS外,其他的段寄存器都可以通过MOV
/LES
/LSS
/LDS
/LFS
/LGS
指令进行修改。但是CS
为什么不可以直接修改呢?CS
的改变意味着EIP
的改变,改变CS
的同时必须修改EIP
,故我们无法使用上面的指令来进行修改,这个也是CPU不允许的。
代码间的段间跳转
段间跳转,有2种情况,即要跳转的段是一致代码段还是非一致代码段,它们不同做的权限检查就不同。
同时修改CS
与EIP
的指令如下:JMP FAR
/CALL FAR
/RETF
/INT
/IRETED
本篇只介绍段间跳转,故只使用JMP FAR
,即为长跳转。下面我举个示例来进行讲解:
CPU
如何执行这行代码JMP 0x20:0x004183D7
?
1️⃣ 段选择子拆分
0x20
对应二进制形式:0000 0000 0010 0000
- 解析结果:
- RPL = 0
- TI = 0
- Index = 4
2️⃣ 查表得到段描述符
TI=0
所以查GDT表,Index=4
找到对应的段描述符。注意四种情况可以跳转:代码段、调用门、TSS任务段、任务门。后面的几种将会在以后的教程详细讲解。
3️⃣ 权限检查
请参考本节的代码段的权限检查
4️⃣ 加载段描述符
通过上面的权限检查后,CPU会将段描述符加载到CS段寄存器中。
5️⃣ 代码执行
CPU
将CS.Base + Offset
的值写入EIP
然后跳转到将要执行的CS:EIP
处的代码,段间跳转结束。
本节练习
俗话说得好,光说不练假把式,如下是本节相关的练习。如果练习没做好,就不要看下一节教程了,越到后面,不做练习的话容易夹生了,开始还明白,后来就真的一点都不明白了。本节练习比只有很少,请保质保量的完成。
1️⃣ 记住代码段间跳转的执行流程。
2️⃣ 自己实现一致代码段的段间跳转。
3️⃣ 自己实现非一致代码段的段间跳转。
下一篇
保护模式篇——调用门、中断门、陷阱门