不妨先来做个实验。打开 OD,双击第一行,把代码改成 mov ax, 0x20; mov ds, ax,然后按两下 F8 键(单步),发现很正常。如果你把代码改成 mov ax, 0x10; mov ds, ax,按两下 F8 后,代码跳转到了一个地址以 7 开头的地方去了。
图1 这两行可以正常执行 图2 第二行不能正常执行 图3 图2中的代码执行异常会跳到这里为了搞清这个原因,我们需要看段描述符 DPL。
分析段选择子 0x10 和 0x20,这两个描述符分别是 00cf9300-0000ffff和00cff300-0000ffff,可以发现这两个描述符唯一的不同就在于 DPL 不同,第一个描述符的 DPL = 0,而第二个描述符的 DPL = 3.
原因就在这里。
DPL = 0 的数据段,只允许当前特权级为 0 的程序访问,而 DPL= 3 的数据段,允许当前特权级为 0,1,2,3的程序访问。在 OD 中,当前特权级为 3.
分析:3环只能加载DPL为3的数据段。
数据段有: 00cf9300`0000ffff DPL = 0 00cff300`0000ffff DPL = 3 --> 可以加载 ffc093df`f0000001 DPL = 0 0040f300`00000fff DPL = 3 --> 可以加载 0000f200`0400ffff DPL = 3 --> 可以加载 00009302`2f30ffff DPL = 0 0000920b`80003fff DPL = 0 ff0092ff`700003ff DPL = 0 80009240`0000ffff DPL = 0 00009200`00000000 DPL = 0 00009200`0000ffff DPL = 0 f8409337`9400ffff DPL = 0 f8409337`9400ffff DPL = 0 f8409337`9400ffff DPL = 0分析:0环可以加载DPL=0,1,2,3 的数据段,以下数据段均可以加载
数据段有: 00cf9300`0000ffff DPL = 0 00cff300`0000ffff DPL = 3 ffc093df`f0000001 DPL = 0 0040f300`00000fff DPL = 3 0000f200`0400ffff DPL = 3 00009302`2f30ffff DPL = 0 0000920b`80003fff DPL = 0 ff0092ff`700003ff DPL = 0 80009240`0000ffff DPL = 0 00009200`00000000 DPL = 0 00009200`0000ffff DPL = 0 f8409337`9400ffff DPL = 0 f8409337`9400ffff DPL = 0 f8409337`9400ffff DPL = 0数据段权限检查,本质上就是检查能不能把段选择子代入到段寄存器。如果代入成功,表明权限检查通过。如果代入不成功,说明权限不够(CPL在数值上太大了)。
大家注意没有,本篇的标题是——数据段权限检查。为什么不是段权限检查?
因为数据段权限检查简单。这确实是一个无懈可击的理由:)
相比于数据段的权限检查,代码段权限检查要更加严格。后文会给出详细的答案。