内核-分段

当我们用汇编读写某一个地址的时候:

Mov dword ptr ds:[0x123456],eax

真正写的地址是 ds.base+0x123456

ES CS SS DS FS GS LATR TR 8个

Base                               Limit                            atrribute                   select

内核-分段_第1张图片

  1. 段寄存器只能看到16位,如何证明又96位???

内核-分段_第2张图片

这个代码是没有任何问题的 因为ss可写ds也可写 eax完全可以赋值到var里面

 内核-分段_第3张图片

 改成cs就崩溃了 cs并没有可写属性

 内核-分段_第4张图片

 首先fs赋值gs 读取gs:[0]的位置 正常来说0的位置是不可写的 但是此时的gs是fs而fs的base并不是0 如上图 此时gs:[0]的位置是0x7ffde000

内核-分段_第5张图片

读取gs0x1000的地方也就相当于读取fs:0x1000的地方 但是 fs大小为0xfff随意程序崩溃

内核-分段_第6张图片

写段寄存器的时候,只给了16位,剩下80位给什么???16位的数可以随便写吗???

  1. GDT(全局描述符表) LDT(局部描述符表)

当我们执行类似mov ds,ax指令时,CPU会查表,根据AX的值来决定查找哪一个表,查找表的什么位置,查多少数据

Gdtr是48位 32位存储了GDT表在哪里16位存储了大小

 

 查看gdt表

 内核-分段_第7张图片

也就是说 gdt是一张表里面的元素叫段描述符 大小为64位8个字节

段描述符的结构

内核-分段_第8张图片

P位:0 - 无效段 、 1 - 有效段。(查看该段是否有效,最直接的就是查看该位)

G位:   G=0表示界限粒度(单位)为1字节,Limit最大值为0x000FFFFF(1MB)

G=1表示界限粒度(单位)为4K字节,Limit最大值为0xFFFFFFFF个4KB(4GB)

     注意,界限粒度只对段界限有效,对段基地址无效,段基地址总是以字节为单位。

S位:0 - 系统段、1 - 代码段或数据段。

S == 1 的时候 数据段或者代码段 type域 再通过11位去区分数据段还是代码段

数据段:E标志位=1,向下拓展,E标志位=0向上拓展.

向上拓展与向下拓展:

      向上拓展,可以访问的段范围是:Base到Base+Limit 之间. 现在操作系统都采用向上拓展

      向下拓展,可以访问的段范围是:小于Base 或 大于Base+Limit

 内核-分段_第9张图片

代码:

一致代码段 c==1: 可以从低特权级别的程序转移到高特权级别的程序执行代码 但是权限不变

一致代码段c==0:同级别访问 高就是高低就是低 低权限可通过门提升权限

内核-分段_第10张图片

D/B位

  该位对于数据段和代码段有着不同的含义,但大体都是与位数大小有关。比如,如果我们使用32位操作系统,一次操作32位,又如何切换到对16位的操作,根本上就是使用这个位。

1)代码段CS:在32位操作系统下,如果DB == 1,则采用32位寻址方式,如果操DB==0,则采用16位寻址方式.

   好比汇编代码加上了0x66前缀:

   机器码 :50   对应的汇编代码  push eax

   机器码 :66 50    对应的汇编代码  push ax

2)数据段:该段作用与不同的数据段其含义不同。

(1) 当特殊情况下,会把数据段ds的段描述符加载到ss段,这种情况下SS的描述符属性,实际上是DS的,属于数据段描述符,只是放在了ss段中.

mov ax,ds

mov ss,ax

此时,当使用 PUSH POP CALL RETN,类似这种能够改变堆栈指针esp值的代码:

SS段:  DB == 1 ,被修改的是 esp

DB == 0 ,被修改的是  sp

和段寄存器不可见部分的对应关系是

8到24字节对应atrribute          

三块base address对应base部分

两块Seg.Limit对应limit

段描述符只有64位如何填充80位的????

段限长20位 最大fffff

G为0的时候  但是要填充成32位就变成 000f ffff

G为1的时候  但是要填充成32位就变成 ffff ffff

根据TI决定查哪张表 在根据index找到表中的哪一项 在检查RPL<=DPL 满足则段描述符加载到段寄存器不可见部分

内核-分段_第11张图片

 更改段寄存器的其他指令

内核-分段_第12张图片

段权限检查

如何查看当前你的程序在哪一环???

看cs寄存器的最后两位 是几就在几环 ss寄存器最后两位一定是等于cs寄存器最后两位的

  1. RPL(Request Privilege Level) 请求特权级别,段选择子的后两位。

针对段选择子而言的每个段的选择子都有自己的RPL 我用什么权限去访问你

举例:

Mov ax,0008                   mov ax,000b                //段选择子

Mov ds,ax                        mov ds,ax                    //段描述

指向同一个段描述符 但是RPL是不一样的

(2)DPL(Descriptor Privilege Level)

DPL存储在段描述符中13位与14位中 规定了该段所需要的特权级别是什么

通俗的理解:

如果你想访问我,那你需要具备什么样的特权

举例:

如果AX指向的段DPL = 0 但当前CX的CPL=3 这行指令是不会成功的

  1. CPL(Current Privilege Level)当前特权级别,当前工作在CS\SS段的RPL,我们称之为CPL

数据段的权限检查

参考如下代码:

比如当前程序于0环 也就是说CPL=0

Mov ax,000b   // 1011 RPL= 3

Mov ds,ax      //ax指向的段描述符的DPL=0

数据段的权限检查 RPL拉低了CPL的权限

MAX(CPL,RPL)<=DPL

代码跨段跳转流程

内核-分段_第13张图片

内核-分段_第14张图片

1. 代码间的跳转 jmp 0x20:0x004183D7 cpu如何指向这行代码的哪???

(1)段选择子拆分

0x20 二进制 0000 0000 0010 0000

RPL = 00

TI = 0

INDEX = 4

  1. 查表得到段描述符

TL = 0所以查找GDT表

Index = 4 找到相应的段描述符

四种情况可以跳转:代码段,调用门,TSS任务段,任务门

  1. 权限检查

非一致代码段 要求 MAX(CPL,RPL)<=DPL

一致代码段 要求 CPL>=DPL

  1. 加载段描述符

通过上面的权限检查后,cpu会将段描述符加载到cs段寄存器中

  1. 代码执行

Cpu将cs.base+offset的值写入到EIP然后执行CS:EIP处的代码,段间跳转结束

内核-分段_第15张图片

内核-分段_第16张图片

你可能感兴趣的:(内核,windows)