段权限检查,段保护机制
这节会从多个方面测试段会进行哪些权限检查,首先CPU可以在4个级别上运行ring 0,ring 1,ring 2,ring 3,运行的级别越低权限越高,我们常常挂在嘴边的内核,就是当CPU运行在Ring 0级别上运行的时候,CPU当前运行级别就是在执行当前指令的时候CS段寄存器或者或者SS段寄存器的选择子16位的低2位值就是当前CPU处理哪个级别,也称为了CPL。
CS寄存器存储的选择子任何时候和SS段寄存器存储的选择子低2为任何时候都是一样的,因为CPU运行在不同的级别,会使用不同的堆栈,所以操作系统准备了4个堆栈,当CPU运行与不同的级别会使用不同的堆栈,所以CS段寄存和SS段寄存器必须是配对的,指令运行的时候需要使用堆栈(函数调用参数等等局部变量的使用),cs寄存器或者ss寄存器的低2位值就是在那一时刻CPU运行的级别,称为cpl,我们平时说的应用程序就是3环程序cpl只能为3,内核ring0 cpl=0,这是本节需要提前知道的只是
本节会给大家验证段机制为了保护内存会进行哪些检查
数据段的段加载权限检查是RPL<=DPL(数据越小权限越大)同时CPL<=DPL请看下面证明
我们GDT表中构建了一个数据段的描述符, 段选择子0x93 RPL=3 段描述符的DPL=3 执行 mov ds,ax cs=0x1b CPl=3 ,此时 RPL=3=DPL=CPL段描述符加载成功
接下来段选择子位0x90 RPL=0 以最高请求权限请求加载这个段描述符,DPL=3,CPL=3 RPL<=RPL CPL<=DPL ok访问成
接下来把0x90选择子索引处的段描述符与修改DPL为2
此时 RPL=0 DPL=2 CPL=3 RPL<=DPL成功但是 CPL<=RPL不成功(段描述符加载失败)
因为在执行mov ds,ax CPL位3 过不了 CPL<=DPL的检查
验证数据段内存访问
构建一个数据段描述符 P=1 G=1 S=1 TYPE=3 DPL=3 TYPE=3 A=1 W=1 可读可写
Base=0x00000000
Limit=0xFFFFFFFF 可以看到 0-0xFFFFFFFF之间的内存可读可写 没有问题
构建一个数据段描述符 P=1 G=1 S=1 TYPE=1 DPL=3 TYPE=3 A=1 W=0 可写
Base=0x00000000
Limit=0xFFFFFFFF 可以看到 0-0xFFFFFFFF
此时RPL=0 DRPL=3 CPL=3 mov ds,0x90这条指令的段检查可以过
但是mov dword ptr ds:[taolaoda],0x666666; 这条指令访问了内存,此时ds段是不可写的,段的访问属性检查不过了
数据段E=0是向上扩展 访问段可访问区间是 Base~Base+Limit
构建一个数据段段描述符 G=0; Base=0000000 Limit=0xfffff DPL=3 选择子位0x90 ,RPL=0
执行mov ds,ax 时 RPL<=RPL CPL=3<=DPL可以段加载权限检查
W=1可读可写,可以过段内存访问检查,此时ds段可以访问的位0~0xFFFFF
taolaoda变量的地址是0x425A30不在0~0xFFFFF段越界了 直接挂,所以在访问内存的时候还会进行一个边界检查
为了使大家对数据段 E=0向上扩展的段的范围是Base~Base+Limit 看的更加直观,构造一个段描述符 数据段的属性位可读可写
VirtualAlloc函数在虚拟地址0x20000000开辟2个页的内存,权限为可读可写可执行
Base=0x00000000
Limit= 0x20000fff ds段能访问的地址是0x00000000-0x20000fff
在访问内存的时时候访问0x20000000虚拟地址的时候写入数据成功,在写入taolaoda全局变量的时候也成功,在访问0x20001000虚拟地址的时候挂了,段溢出了出了异常,所有可以推断,在访问内存的时候,每一条访问内存的指令,段保护机制都会检查,段有没有溢出,有没有访问权限,否则报异常,这就是对段对内存的保护机制
验证P位检查构建一个数据段描述符P=0,这个描述符没有意义的试试在ring3加载会怎么样(把这个放在最后是因为这个很容易被忽略)
总结数据段的检查有4种
1.加载段描述符的时候首先根据选择子的Index找到段描述符,在解析描述符P是否=1 如果为0直接失败 返回0xC0000005
2.如果加载数据段段描述符 段会检查 RPL<=DPL 和CPL<=DPL
3.在访问内存的时候段会检查,是否可写,如果W=0不可写,发送了写入操作段会制止你给一个异常0xC0000005访问异常
4.在访问内存的时候段会检查,是否在段范围内,如果也会制止你给一个异常
加载一个段描述符在CPU找到这个段描述符后,会进行检查P=1的检查如否则直接失败返回一个0xC0000005,然后检查
你有没有权限加载这个段 如果是数据段要求 RPL<=DPL&&CPL<=DPL(上述有证明) ,如果这两个检查过了就会把段描述符的中的Base,Limit Atrribute; 这80位加载到CPU内部的段寄存器缓冲中(你用哪个段寄存器操作的就加载到那个段寄存器),加载后对操作内存的指令在执行的时候都会检查这个段有没有写权限等等,有没有越界超出段的范围进行检查。