什么是内核态,什么是用户态,谁定义的?从段页层面解析用户态和内核态

        应该学习过一段时间的人,都能唱出来,低2GB是用户空间,高2GB是内核空间,我们如果在用户空间访问内核空间数据,直接给你一个0xC0000005异常,告诉你你没有权限访问,

       今天就给大家完全的解析什么是内核空间,什么是用户空间

CPU有4个运行级别,如下图,我们所说的内核就是Ring0当CPU运行ring0态的时候就是内核态(也就是CPL=0),此时拥有最           高的权限

而在用户态的时候就是CPL=3此时CPU处于用户态

    再次提出几个问题解决了这几个问题就解决了

1.我在用户态访问高2GB内存会失败是因为我不是内核态所有访问失败的嘛?

2.内核态真的只是高2GB的时候才能处于内核态嘛

 

首先我使用用户态访问一个高2GB内存

void  _declspec(naked) taolaoda(){
    __asm{
        pushad
        pushfd
        mov eax,0x8003f008
        mov ecx,[eax]
        mov edx,[eax+4]
        mov Vluae,ecx
        mov Vluae1,edx
        popfd
        popad
        retf
    }
}
int main(int argc, char* argv[])
{
    char buf[6];
    char buf2[6];
    *((WORD*)&buf[4])=0x1b;                                                      //这个就是本来cs的选择子 没有改变  直接调用taolaoda函数也    是一样我用长调用的方式调用,是为了后面构造段描述符方便少该代码
    *((DWORD*)&buf[0])=(int)taolaoda;
    __asm{
        call buf;
    }
    printf("Vluae=%p  Vluae\n",Vluae,Vluae1);
    getchar();
    return 0;
}

结果是访问访问高2GB的   0xC0000005访问异常,这是谁不让我们访问?

答案是页机制(没有学过页的不要紧后面我们会有一篇帖子专门介绍页),

 

  我通过Windug修改0x8003f000这个物理页的访问权看看,首先通过Windug输入 !process 0 0遍历所有进程,获得自己正在运行的Cr3,然后找到0x8003f000对应的物理页

这我自己写的一个2-9-9-12地址拆分器

看到下面红框起来的,可以看到找到了0x8003f000对应的物理页,数据吻合

修改自己进程 0x8003f000对应的物理页PTE的属性 的第2位和第8位

第2位是U/S  U/S位=1的时候  允许用户态访问CPL=3,(CPU允许CPL=0,1,2访问用户态)

                     U/S位=0的时候  允许内核态访问,此时只有CPL=0的时候访问这个页地址的时候才能通过

第7位是G位  G=0给刷新一下CPU内部的TLB表,后面会将这章的重点是让我们明白 段和页的限制以及内核态用户态的是

根据什么来定的

修改PDE的属性    修改U/S=1

这是接着上面0xC0000005运行的那个进程接着运行的没有重新运行

这就是为什么高2GB用户态无法访问了,所有进程高2GB都是内核是共享的,操作系统通过页机制,

把0x80000000-0xFFFFFFFF这些地址对应的物理页PTE,PDE的U/S设置0位只允许内核态访问呢就是CPL=0时候

mov  eax,[0x8003f008]这条执行才能执行,或者把0x8003f000这个物理页的对应的PTE和PDE的 全都设置为U/S=1

此时这条指令mov  eax,[0x8003f008],在CPL=0,1,2,3的时候都能访问。

        所以可以说是页机制将高2GB和第2GB数据分格开,由于操作系统将高2GB的内存的物理页PTE全都设置成了U/S=0只允许CPL=0的时候访问,所以高2GB又被一些人称为内核(因为此时候CPL=0才被称为内核的),http://www.javashuo.com/article/p-bobthpzl-sk.html 这是我们写一的一篇段权限检查,里面描述了段机制做了什么,

保护模式保护的是内存(和一些特权指令),段机制对保护内存做的不多,对内存的保护是页做的,能够将高2GB和第2GB分开,其实很多人对内核的理解都是有误的,本意应该是当CPU执行某条指令的时候 CPL的值,如果此时CPL=3就是用户态,CPL=0就是内核态,这说明的是CPU的状态,很多人却将其与内存对应起来,说高2GB是内核,(再次是申明一下内核态是CPU的状态,与内存无关),高2GB的内存别操作系统设置过物理页的属性,只允许CPL=0(内核态访问),而低2GBCPU运行与任何状态都可以访问,这就是页机制做的内存保护

我们也谈一谈段对内存的保护,也有但是远远无法和页做的相比,段对内存就做就比如数据段(好你可以访问0x00000000-0xFFFFFFFF这4GB空间,以可读,或者可读可写的权限(段把内存看成一个整体,这个整体权限完全相同)),页是在段的基础上将分割成一个一个页(每个小页0x1024字节),每个一页都有它自己的属性,有的页只允许CPL=0的指令访问,有些页只读,有些页可读可写,所有说对内存的保护主要是页机制做的,因为段主要做的是加载段描述符,具有提权功能(会进行权限检查),

我们构造一个系统段,调用们提权

通过调用们提权后可以看到直接直接读高2GB内存的数据

可以看到通过调用们提权后发现 调试的时候是WIndug内核调试器接受的调试信息,此时CPL=0就是内核态了,也就是说也可以访问高2GB内存了,结合所有应该能够明白了,权限说的是CPU的概念,访问不同内存需要的权限不同,所以CPL在不同级能够访问的数据不同,也有一写特权指令执行在内核态才能执行成功,段就是提升CPU权限的手段,当然也能降低。

当段机制和页机制同时配合起来的时候,就有了高2GB是内核空间(只允许内核态访问 页限制),低2GB是用户空间(允许所有权限访问),用户空间中有些区域是只读区,有些可读可,这有是页机制的杰作

上面的测试可以看到地址0x401050  处的指令也是在内核态,在很多正向人眼里这是用户空间,这说明他根本不知道什么是应用空间,内核空间,到这里大家应该能了解到那些是段机制做的了,那些事页机制做的。