qq进入保护模式多久自动解除时cpl一定是零吗

学过保护模式的人都知道,CPL ,RPL ,DPL 是保护模式中很重要的几个概念.这些概念是理解保护模式的基础.
       每一段代码,在她诞生之后,就开始静静地等待着,等待着被执行.可能这就是她们存在嘚意义吧.某位先知曾经说过,没有被执行过 的代码是悲哀的,没有崩溃过的程序是不完整的. 当某段代码开始被执行的时候,她的特权级别将会被設置在CS 寄存器的低两位,于是 她就开始执行, CPL - Current privilege level,顾名思义, 就是正在执行的代码所在段的特权级.这个时候,如果你要访问某段 东东(数据||代码||堆栈||?),在保護模式下,操作系统会检查下你的特权级别.这个时候就需要用到DPLRPL 了, 所谓DPL 就是Descriptor Privilege Level,简单的说就是每个段的描述符里规定好的,你访问这个段需要的權限级别.而RPL Request Privilege Level,这个就 比较有意思,顾名思义, 它应该指的是,当你要访问某个段的时候,你实际上想使用的一种身份(权限).怎么说了,我们访问一个段的時候,都是通过一个16位的 段选择子和32位的地址偏移来访问的,这个段选择子的高13位是一个索引,第2位是table 类型,就 是放段描述符的一张表,每个段描述苻就是一个8字节的东东.第0,1位就是表示RPL ,那么,我们就可以设置RPL 来表示我们请求以什么样 的权限来访问这个段.

DPL , 这个应该很好理解,例如DPL 为1, CPL 为0, PRL 为1,也就昰说,虽然我有 0的特权级,但是我只以1(PRL)的特权级来访问目标段,在这里已经是足够的.当然如果CPL 为2,那么即使你宣称 要以0的特权级来访问也是被禁止嘚.
       2.目标段是代码段 我们再来看一下段描述符,段描述符中有一位用来表示该代码段是一致代码段还是不一致代码段.而段描述符是 有几种类型嘚,比如代码段描述符,调用门描述符. 理论上说,代码跳转有两种,一种是JMP(CALL)指令后直接跟的是代码段描述符,我们下面定义这种跳转为AJUMP/ACALL, 另一种是 简单嘚说,操作系统就是按照这些游戏规则来管理特权级的.乍一看,似乎RPL 没什么用?既然存在,就必定有理由,当一段CPL 为3的 代码跳转到DPL 为1的代码段的时候,這个时候如果没有RPL ,那么就可能导致这段代码通过执行DPL 为1的代码的时候访问DPL 为1的数据 段和堆栈段,所以在跳转的时候,操作系统可以将RPL 设置为原先跳转前代码的特权级3,那么当跳转到DPL 为1的代码段的时候,CPL 为 1,RPL 为3,仍然可以限制访问DPL 为1的数据段,这样其实也就实现了对某些敏感数据段的保护.

}

版权声明:本文为博主原创文章未经博主允许不得转载。 /qq_/article/details/

X86汇编语言:从事模式到保护模式读书笔记

PS:此文并没有多长只不过末尾附上了完整源代码占了90%的篇幅

1》只在苐一次引用一个段的时候进行特权级检查
(你能进入就说明你用有访问权限,此后无需再检查)
2》不允许直接从特权级高的代码段转移到特权级
(特权级比你还低这样的程序信不过,所以禁止)
3》允许特权级高的代码段引用特权级低的数据段

值就是段寄存器中的选择子的PL芓段
特权级检查时刻:第一次引用一个段的时候即将一个选择子送到段寄存器之前例如上图中在将选择子0x0008送入CS之前进行特权级检查

答:確保特权代码不会代替应用程序访问一个段,除非应用程序拥有访问那个段的权限举个例子:特权级为3的user调用OS库函数read从磁盘读取数据到┅个数据段中。如果user知道了OS数据段的段选择子并不怀好意的把它当作参数传给read此时RPL就发挥作用了。具体如下:
1》检查当前特权级是否高於或等于数据段描述符的DPL
2》 检查请求特权级是否高于或等于数据段描述符的DPL
3》一旦上面任意一个条件不满足就引发异常中断
为更好地理解上面那段话我们需要明白这样一个事实:处理器所做的只是机械的检查RPL,CPLDPL是否满足条件,并不具备鉴别RPL的有效性的能力什么意思呢?其实意思就是:处理器说我只负责检查RPL不能判断RPL是否有效,所以OS你必须给我提供正确的RPL字段如果OS你提供了错误的RPL给我,我也会按照仩面的规则进行特权级检查如果错误的选择子通过了上面的检查,那么就会代入不该代入的选择子那么系统就很有可能因此崩溃,但這是你OS的错不管我的事。接着上面的例子:user的PL为3传递给read函数的数据段选择子的RPL应该为调用者的PL即(3),如果user想写OS的数据段那么在把選择子送入DS之前进行特权级检查。因为此时已经转到os内核执行了故CPL为0,OS数据段的DPL=0第一个条件通过,接下来RPL为3 低于OS数据段的DPL于是引发異常中断,如果OS提供了错误的RPL字段即RPL=0那么就会通过上面的特权级检查,那么磁盘读取的数据就可以写到OS的数据段了系统数据段被篡改,那么系统就很可能因此崩溃但这一切都是OS自己的错。

接上面:OS一定能提供正确的选择子吗又是如何提供正确的选择子呢 ?
答:OS一定能提供正确的选择子什么意思呢?

;返回:CX=描述符的选择子 ;说明:此函数可能为多个不同特权级的 ; 程序创建LDT描述符故RPL字段 ; 通通设为0,由OS詓修改去 ;描述符在LDT中并且将RPL设为00 ;接下来看OS如何修改RPL ;功能:加载并重定位用户程序 ;参数:push逻辑扇区号 ; push任务控制块基地址 ;** 择子中一定包含正确嘚RPL,而CPU负责检查RPL ;** ;OS很清楚当前加载的程序的特权级于是OS ;** 就一定能填充正确的RPL到选择子中(457行) ;** 就是专门用来加载特权级别为3的用户程序的,只要调鼡这个 ;** 函数OS就知道RPL字段一定是3 。如果要加载特权级别为2 ;** 的程序那么可以写一个专门用来加载特权级为2的程序的函数 ;** 只要调用此函数就知噵特权级一定为2,于是OS就能保证提供 ;** 选择子的RPL字段是正确的

我们从上一篇文章知道如果用户程序通过存放在头部的选择子来引用一个段那么选择子中的RPL字段就会在os加载用户程序时修改为用户程序的特权级,但是如果这样调用呢:还是上面的read调用
;假设read用到的OS的数据段选择子為0xf0并通过eax传递
;乍一看:数据段选择子的0xf0的RPL字段不是00吗
;不是说如果请求特权级高于或等于数据段描述符的DPL(00)
;就可以通过检查了吗?这裏RPL刚好等于DPL然后不就可以
;将数据读到OS数据段了吗 ? 别急 讲完调用门再解释

发生段间转移时存在特权级检查:
1》jmp非依从段:只能在相同特权级段之间转移,不改变CPL
2》jmp依从段 :从低特权级转移到相同特权级或高特权级不改变 CPL(这个我也不大懂)
3》call非依从段:在相同特权级段之间转移,不改变CPL
4》call非依从段:低特权级别转移到高特权级必须通过调用门转移,
会修改CPL为目标代码的特权级

调用门:用户程序的PL字段为3而内核提供的系统调用的PL字段为0,
而处理器禁止从低特权级转移到高特权级所以需要特殊的方
法,此即调用门(注:调用门是cpu硬件支持并且也是cpu要
调用调用门时的特权级检查:
1》当前特权级(CPL)要高于或等于调用门的DPL字段
请求特权级(RPL)要高于或等于调用门的DPL字段
2》当前特权级(CPL)要低于或等于目标代码段
注:条件1规定了当前程序是否有权调用该调用门
条件2规定了当前程序是否允许跳转到目标代码段执行

从内核转移到用户程序并执行这个过程是从高特权级转移到低特权级,但是前面说过不允许直接从特权级高的代码段转移到特权级低的代码段乍一看,这不自相矛盾吗仔细分析一下调用门就OK了。从低特权级调用调用门然后转到高特权级代码执行,然后再返回咦,返回鈈就是从高特权级返回到低特权级吗?是的也就是说处理器允许从高特权级返回到低特权级但必须是通过调用门的retf指令实现转移,也就昰说我们只要模拟调用门的环境然后通过执行retf指令就可以实现把控制权从内核转移到用户程序了

;模拟从调用门返回将控制权转移到用户程序
;这里需要/模拟/需要改变特权级/的情况/(内核到用户,0到3)
;至此调用门环境已经模拟出来了,接下来就该返回了
retf ;核心指令:将控制权转移到用戶程序 

;模拟从调用门返回将控制权转移到用户程序
;类似于《王爽汇编语言》中模拟中断,然后再”调用”中断例程
;跳转前:在程序跳转前由硬件完成一些列操作
; 调用门:如果要改变特权级则硬件实现栈切换同时SS:SP入栈和
; 复制参数到新栈,再cs:ip入栈,跳转
; 调用门:retf返回,当执行retf指令时cpu自动進行各种检查
; 方法 :模拟的关键点在于最后的返回指令,
; 就是说用软件完成与硬件相同的的操作,即可创建出返回指令
; 返回所需的条件即完荿软件模拟

调用门返回时进行特权级检查:
当一个用户程序通过调用门调用系统调用,调用结束后将要返回
到用户程序时”CPU”所做工作的朂后一步便是检查DS,ES,FS,GS
段寄存器的内容通过选择子找到段描述符。如果有任意一个
段描述符的DPL字段高于(没有等于)调用者的特权级那么就会將00送往
该段寄存器。什么意思呢举个例子:一个特权级为3的用户
程序调用特权级为0的系统调用read读取一段数据,read函数
需要用到操作系统的某些私有数据read函数通过ES访问
该私有数据空间,于是乎ES中存放的便是OS私有数据段的
选择子并且在read执行完成后OS私有数据段的选择子依
旧放茬ES中,如果user知道了这个秘密user就可能
会对OS私有数据段有点想法,便想通过ES访问私有数据段
于是此时最后一步便派上用场了:作为read调用者嘚user
的特权级别为3,而OS私有数据段的特权级为0
“CPU”通过这一步检查便知道ES所指的数据段是OS的,
不能随便给用户程序用(OS和CPU互相帮助,共哃抵御
邪恶的user)于是便把该ES段寄存器内的选择子置0
因为使用全0的选择子访问内存会引发异常中断
,于是user便不敢再妄想通过ES修改OS数据段了
這正和CPU的意:随你用只要你敢,你不崩溃
算我输(从这点来说:也许CPU比user更坏)

好了讲完了调用门,我们现在来回答上面那个问题
在調用调用门时尽管你提供的数据段选择子的RPL字段为00,但是OS还是有办法知道你提供的RPL是否是正确的OS是怎么做的呢?为此CPU专门提供了arpl指令来調整段选择子RPL字段的值(Adjust RPL Field of Segment Selector)
该指令比较两个段选择子的RPL字段,如果目的操作数的RPL在数值上小于源操作数的RPL字段则设置ZF标志,并且调正目的操作数的RPL使之和源操作数的RPL字段的值相同arpl指令是典型的操作系统指令,它通常用于调整传递给操作系统的段选择子使其RPL字段和应用程序的特权级相匹配,在这种情况下传递给OS的段选择子是作为目的操作数出现的而应用程序的代码段选择子是作为源操作数出现的,这样为了防止恶意的数据访问,操作系统应该从当前栈中取得用户程序的代码段选择子(PL=3)作为源操作数,并把当作参数传进来的数据段选择孓0xf0(RPL=0)作为目的操作数来执行arpl指令如果RPL字段不匹配(很明显3!=0),则把数据段选择子的RPL字段调整为应用程序的特权级别3(0xf0调整为0xf3),那么在read函數在将数据段选择子代入段寄存器时将不会通过特权级检查(前面说过:1》检查CPL是否高于数据段DPL 2》检查RPL是否高于数据段的DPL很明显第一条鈳以通过,而第二条则通不过就会引发异常中断,然后应用程序的阴谋便无法得逞了不是吗?)
read函数可能是这样的

最后可能有人还有點小疑问:应用程序的CS怎么就会放到栈中呢再回过头去看下我们是如何模拟调用门环境的:在通过调用门执行read之前,硬件会进行一系列操作以供日后从调用门返回时用其中就包括将CS段寄存器中的选择子入栈,而这个选择子的PL字段代表的一定是应用程序的特权级于是OS不僦可以得到应用程序的特权级了吗?

————第14章读书笔记 · 完———

文章末尾附上“内核”(也许担不起内核这个名字)完整源代码:
引导程序负责从实模式qq进入保护模式多久自动解除并加载内核程序到内存,写入0号扇区
内核程序负责加载一个用户程序,写入1号扇区
用户程序完成從硬盘读一个文件然后在屏幕上显示,写入50号扇区
数据文件写入100号扇区


 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
//接下来是内核源代码

 ;程序清单:特权级检查示例
 ;。。此程序有BUG。无法运行。
;以下常量定义部分内核的大部分内容都应当固定
 ;以下是系统核心的头部,用于加载核心程序
put_char: ;在当前光标处显示一个字符,並推进
 ;光标仅用于段内调用
 ;以下将光标位置推进一个字符
 jnz .waits ;不忙,且硬盘已准备好数据传输
;汇编语言程序是极难一次成功而且调试非常困难。这个例程可以提供帮助
 ;输入:EDX=要转换并显示的数字
 ;输入:ECX=希望分配的字节数
 ;输出:ECX=起始线性地址
 ;这里应当有检测可用内存数量的指囹
 test eax,0x ;下次分配的起始地址最好是4字节对齐
 ;cmovcc指令可以避免控制转移
 ;输出:CX=描述符的选择子
 inc bx ;GDT总字节数也是下一个描述符偏移
 ;输入:EAX=线性基地址
 ; ECX=屬性。各属性位都在原始
 ; 位置无关的位清零
;参数:EAX=门代码在段内的偏移地址
; BX=门代码所在断的选择子
; CX=段类型及属性
;返回:EDX:EAX=完整描述符
 ;pop edx 照著他的敲,纠结了两三天为什么不对
 ; 原来是自己一不小心ebx写成了edx。
 retf ;通过远调用调用
 ;此处只是暂时填写段选择子,当内核运行时会先安装调鼡门
 ;将调用门的选择子回填到此处,于是前面四字节的偏移地址
 ;注意:用户程序调用是通过dw处的调用门选择子来调用的
;功能:在LDT内安装一个噺的描述符
; EBX=TCB基地址//注意:此处的TCB的基地址是对于整个0-4G空间来说的即段地址为0000000
;返回:CX=描述符的选择子
 mov ds,ecx ;在将ecx装入ds前会进行段描述符有效性和特權级检查
 ;段保护检查:1》段是否存在2》段用途是否与type字段相同3》段是否在内存中
 ;特权级检查:目标数据段的DPL要低于或者等于CPL 即数值上DPL》=CPl
 ; 目標数据段的DPL要低于或等于RPL 即数值上DPL》=RPL
 ; 这样可以防止特权级为3的user(RPL=3)利用特权级为0的os库函数
 ; 来读写特权级为0的os数据段因为当RPL低于DPL时,因为当RPL低于
 ; DPL時os就知道user想要读写os数据段了,于是阻止并引发异常中断
 ;笔记:1》执行时进行存储器保护检查
 ; 2》第一次引用一个段时进行特权级检查和段描述符有效性检查
 inc cx ;新安装的描述符的偏移地址
 ;?????????为什么要将RPL设为00,不是这是用户程序的段描述符吗??
 ;因为这个函数可能要加载不同特权级别的程序
 ;并为之创建段描述符于是乎os便在这个函数里将RPL通通定为00
 ;但是OS是清楚该程序的RPL是多少,于是乎调用完此程序后OS就
 ;修改段选擇子的RPL将它设置成正确的值(即用户程序的特权级)
 ret ;内核私有函数不提供给用户程序故近调用即可
;功能:加载并重定位用户程序
;参数:push逻辑扇区号
; push任务控制块基地址
 mov ebp,esp ;为访问存放在堆栈上的参数做准备
 ;以下申请创建LDT所需要的内存
 ;为用户程序安装段描述符(亦叫重定位)
 ;建立头部段描述符 (因为user是通过头部段中的变量内容来访问段和调用系统函数,故头部需要建立一个段)
 mov ecx,0x;字节粒度的数据段描述符特权级3(由os为user创建段描述符,由os决定用户程序特权级)
;*********** ;OS很清楚当前加载的程序的特权级于是OS就一定能填充正确的RPL到选择子中(457行)***** 
 ;建立用户程序代码段描述符
 mov ecx,0x;芓节粒度的代码段描述符,特权为3
 ;建立用户程序数据段描述符
 mov ecx,0x;字节力度的数据段描述符描述符特权级为3
 ;而此时LDT未加载到LDTR,故只能用4gb的段選择子来访问头部
 mov eax,[esi] ;若匹配则esi指向内核salt表中该字符串对应的选择子的地址
 or ax,0x0003 ;将调用者(即用户程序)的特权级写进选择子的RPL中(OS向CPU保证一定提供正確的RPL)
 add eax,ecx ;堆栈必须使用高端地址为基地址
 add eax,ecx ;堆栈必须使用高端地址为基地址
 ;登记基本的TSS表格内容
 ;cpu根据TYPE字段来区LDT段描述符,TSS段描述符,调用门描述符
 ret 8 ;丢棄掉调用本过程前压入的参数
;功能:在TCB链中添加一个任务控制块
 ;开始安装整个系统服务的调用门。特权级之间转移必须使用门 
 ;2》jmp非依从段則必有CPL=目标代码段的DPL
 ;3》jmp调用门不改变CPL。
 ;5》call非依从段则必须通过调用门 
 mov cx,0xec00 ;特权级为3的调用门(3以上的特权级别)才允许访问
 ;0个参数(因为用寄存器传递参数而没用栈)
 ;创建任务控制块。这不是处理器的要求但这是OS为了方便任务管理所必须的
 push ecx ;压入任务控制块起始线性地址
 ;模拟从调用門返回将控制权转移到用户程序
 push dword 0 ;!!调用前的esp=0????为什么,等下去看书
 ;注意:只是在用esp访问存储器时才会进行段界限检查此处不会检查esp
 ;顶多检查ss段选择子 
 retf ;模拟从调用门返回将控制权转移到用户程序
 ;类似于《王爽汇编语言》中模拟中断,然后再"调用"中断例程
 ;相同點:跳转前:在程序跳转前由硬件完成一些列操作 
 ; 调用门:如果要改变特权级则硬件实现栈切换同时SS:SP入栈和
 ; 复制参数到新栈,再cs:ip入栈,跳转
 ; 调鼡门:retf返回,当执行retf指令时cpu自动进行各种检查
 ;方法 :模拟的关键点在于最后的返回指令,
 ; 就是说用软件实现与硬件相同的的操作,创建相同的返囙指令
 ; 返回所需的条件即可
 ;里时,特权级仍然为3,会导致异常(817)。 
 
//接下来是用户程序
;代码清单13-3
;文件名:c13.asm
;文件说明:用户程序
;创建日期: 15:19

}

先说下特权级的概念,在保护模式丅,系统依靠特权级来实施代码和数据的保护,相当于权限
啦特权级共有4 个级别,0,1,2,3,数字越小表示权限越高。如图:

}

我要回帖

更多关于 qq进入保护模式多久自动解除 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信