欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  科技

保护模式_1_段寄存器_段描述符_段选择子

程序员文章站 2022-06-02 21:44:16
1 段寄存器 1 1 段寄存器的结构 图示: 结构体表示: 1 2 段寄存器的属性探测 可以通过MOV指令进行读写(LDTR和TR除外) 段寄存器成员简介 探测Attribute是否存在 探测Base是否存在 探测Limit是否存在 1 3 段描述符与段选择子 段寄存器的值是通过段描述符填充的。 1 ......

1 段寄存器

1-1 段寄存器的结构

图示:
保护模式_1_段寄存器_段描述符_段选择子
结构体表示:

struct segment
{
    word selector;
    word attribute;
    dword base;
    dword limit;
}

1-2 段寄存器的属性探测

可以通过mov指令进行读写(ldtr和tr除外)

段寄存器成员简介

保护模式_1_段寄存器_段描述符_段选择子

探测attribute是否存在

int var=0;
int main()
{
    __asm
    {
        mov ax, ss  //cs不行 cs是可读 可执行 但不可写
        mov ds, ax
        mov dword ptr ds:[var], eax
    }
}

探测base是否存在

int var=0;
int main()
{
    __asm
    {
        mov ax, fs
        mov gs, ax
        mov eax, gs:[0]  //不要用ds否则编译不过去  //fs.base+0是真正访问的
        //相当于
        //mov edx, dword ptr ds:[0x7ffde000]  //这个地址是可以访问的
        mov dword ptr ds:[var], eax

    }
}

探测limit是否存在

int var=0;
int main()
{
    __asm
    {
        mov ax, fs
        mov gs, ax
        mov eax, gs:[0x1000]   //0x7ffdf000+0x1000,1000超过了0xfff
        //访问的地址相当于下面的 但ds的limit是0xffffffff
        mov edx, dword ptr ds:[0x7ffdf000+0x1000]
        mov dword ptr ds:[var], eax
    }
}

1-3 段描述符与段选择子

段寄存器的值是通过段描述符填充的。

1-3-1 gdt(全局描述符表) ldt(局部描述符表)

当我们执行类似mov ds, ax指令时,cpu会查表,根据ax的值来决定查找gdt还是ldt,查找表的什么位置,查出多少数据
保护模式_1_段寄存器_段描述符_段选择子

1-3-2 段选择子

段选择子是一个16位的段描述符,该描述符指向了定义该段的段描述符.
保护模式_1_段寄存器_段描述符_段选择子

1-3-3 加载段描述符至段寄存器

除了mov指令,我们还可以使用les、lss、lds、lfs、lgs指令修改寄存器.

cs不能通过上述的指令进行修改,cs为代码段,cs的改变会导致eip的改变,要改cs,必须要保证cs与eip一起改,后面会讲

char buffer[6];
__asm
{
    les ecx, fword ptr ds:[buffer]  //高2字节给es,低四字节给ecx
}

注意:rpl<=dpl(在数值上)

1-4 段描述符属性_p位_g位_s位_type域

1-4-1 p位

p = 1 段描述符有效
p = 0 段描述符无效

1-4-2 段描述符与段寄存器的对应关系

1-4-3 g位

重点在于limit结构。
当g = 0 时,limit是0x000xxxxx
当g = 1 时,limit是0xfffxxxxx -- 这里存疑

1-4-4 s位

小结:先判断p位,再判断s位是0/1(确定是数据段/代码段或者是系统段的)
dpl只能出现两种情况,或0或1

1-4-5 type域

s = 1 代码段或数据段的描述符
保护模式_1_段寄存器_段描述符_段选择子
s = 0 系统段的描述符
保护模式_1_段寄存器_段描述符_段选择子
** 数据段说明:
a 访问位,表示该位最后一次被操作系统清理后,该段是否被访问过,每当处理器将该段选择符置入某个段寄存器时,就将该位置1.
w 是否可写
e 扩展方向
代码段说明:**
a 访问位
r 可读位
c 一致位 { c = 1 一致代码段; c = 0 非一致代码段}

1-4-6 db位

情况一:对cs段的影响
d = 1采用32位寻址方式
d = 0采用16位寻址方式
前缀67 改变寻址方式

情况二:对ss段的影响
d = 1 隐式堆栈访问指令(如:push pop call)使用32位堆栈指令寄存器esp
d = 0 隐式堆栈访问指令(如:push pop call)使用16位堆栈指令寄存器sp

情况三:向下扩展的数据段
d = 1 段上线为4gb
d = 0 段上线为64kb
保护模式_1_段寄存器_段描述符_段选择子

1-5 段权限检查

1-5-1 cpu分级

保护模式_1_段寄存器_段描述符_段选择子

1-5-2 如何查看程序处于第几环?

cs寄存器的段选择子(共16bit)的后两个bit,表示的是cpl(current privilege level):cpu当前特权等级
cs和ss中存储的段选择子后2个bit

1-5-3 dpl(descriptor privilege level) 描述符特权等级

dpl存储在段描述符中,规定了访问该段所需要的特权级别是什么
举例说明:
如果ax指向的段dpl = 0 但当前程序的cpl = 3 这行指令是不会成功的

1-5-4 rpl(request privilege level) 请求特权等级

举例说明:
mov ax, 0008 与 mov ax, 000b //段选择子
mov ds, ax //将段描述指向的是同一个段描述符,但rpl是不一样的

1-5-5 数据段的权限检查

参考如下代码:
比如当前程序处于0环, 也就是说cpl=0
mov ax, 000b //1011 rpl=3
mov ds, ax //ax指向的段描述符的dpl=0

数据段的权限检查:
cpl <= dpl 并且 rpl <= dpl(数值上的比较)

注意:
代码段和系统段描述符中的检查方式并不一样,具体参见后面内容...

1-5-6 总结:

cpl cpu当前的权限级别
dpl 如果你想访问我,你应该具备什么样的权限
rpl 用什么权限去访问一个段

为啥要有rpl?
我们本可以用“读、写”的权限去打开一个文件,但为了避免出错,有些时候我们使用“只读”的权限去打开。