您的位置:首页 > 其它

调用门实战(2)----调用门特权级转移理论篇

2010-11-20 19:26 239 查看
假设我们想由代码段A转移到代码段B,运用一个调用门G,调用门G中的目标选择子指向代码B的段。这里有几个要素:CPL、RPL、代码B得DPL(DPL_B)、调用门G的DPL(DPL_G)。A访问调用门G是,要求CPL和RPL都小于等于DPL_G。即CPL和RPL需要在更高的特权级上。

除了上面一步符合要求之外,系统还将比较CPL和DPL_B。如果一致代码段的话,要求DPL_B<=CPL;如果非一致代码段的话,call指令和jmp指令有所不同。call指令要求DPL_B<=CPL;在用jmp指令时,只能是DPL_B=CPL.

综上所述,调用门特权规则如下图:



通过调用门call指令,可以实现从低特权级到高特权级的转移,无论目标代码段是一致的还是非一致的。

在有特权级转移时,堆栈也会随之变化,见下图



每个任务最多可能在4个特权级间转移,所以每个任务实际需要4个堆栈。可是我们只有一个ss和esp,在发生堆栈切换时,从哪里获得其余堆栈ss和esp呢?从TSS(Task-State Stack)。32位TSS如下图所示:



TSS包含多个字段,这里只需要关注偏移4到偏移27的3个ss和3个esp。当发生堆栈切换时,内存的ss和esp就是从这里取得的。比如我们当前所在的ring3,当转移至ring1时,堆栈将被自动切换到由ss1和esp1指定的位置。由于只是外层到内层(低特权级到高特权级),切换时新堆栈会从TSS中取得,所以TSS中没有位于最外层的ring3的堆栈信息。

了解了堆栈问题,就可以屡清特权级转移了。

调用门从外层到内层的转移过程:

1、根据目标代码段的DPL(新的CPL)从TSS中选择应该切换到哪个ss和esp

2、从TSS中读取新的ss和esp。在这过程中如果发现ss、esp或者TSS界限错误都会导致TSS异常(#TS)

3、对ss描述符进行检查,如果发生错误,同样产生#TS异常

4、暂时性保存当前ss和esp值

5、加载新的ss和esp

6、将刚刚保存起来的ss和esp的值压入新栈

7、从调用者堆栈中奖参数复制到被调用者堆栈(新堆栈)中,复制参数的数目由调用门中Param Count一项来决定。如果Param Count是零的话,将不会复制参数。

8、将当前的cs和eip压栈

9、加载调用门中指定的新的cs和eip,开始执行被调用过程。

第7步中,ParamCount只有5位,最多只能复制31个参数。如果参数多于31,可以让其中某个参数变成指向一个数据结构的指针。

ret指令返回的步骤:

1、检查保存的cs中的RPL以判断返回时是否要变换特权级。

2、加载被调用者堆栈上的cs和eip(此时会进行代码段描述符和选择子类型和特权级检验)

3、如果ret指令含有参数,则增加esp的值以跳过参数,然后esp将指向被保存过的调用者ss和esp。注意,ret的参数必须对应调用门中的Param Count的值。

4、加载ss和esp,切换到调用者堆栈,被调用者的ss和esp被丢弃,这里将会进行ss描述符、esp以及ss段描述符的检验。

5、如果ret指令含有参数,增加esp的值以跳过参数(此时已经在调用者堆栈中)

6、检查ds、es、fs、gs的值,如果其中哪一个寄存器指向的段的DPL小于CPL(此规则不适用于一致代码段),那么一个空描述符会被加载到该寄存器。

下图是返回的步骤:



综上所述,使用调用门的过程实际分为两个部分,一部分是从低特权级到高特权级,通过调用门call指令来实现;另一部分是从高特权级到低特权级,通过ret指令来实现。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐