保护模式

简介

x86cpu一共三种模式,实模式,保护模式,虚拟8086模式

特点

  • 段机制
  • 页机制

段寄存器

是什么

比如

mov dword ptr ds:[0x12345678],5

就是ds段寄存器作为base,偏移0x12345678的位置

一共有ES CS SS DS FS GS LDTR TR共8个

结构

image-20220823003209054

selecter是可见部分

attribute是属性部分,可读可写可执行

base是基址

limit是总长度多少

可以通过mov指令对段寄存器进行读写(除了LDTR,TR)

成员简介

image-20220823004349392

GDT和LDT

GDT是全局描述符表,LDT是局部描述符表

我们执行mov ds,ax等指令时,CPU会查表,根据AX的值决定查找GDT或者LDT

段描述符

image-20220823222115850

段选择子

image-20220823220151461

加载段描述符到段寄存器

image-20220823220417052

这里十分有意思,用到了fword,也就是6个字节,而这里用到的是les指令,所以这里高俩直接给es,低四个字节给dst的寄存器ecx。

段描述符成员介绍

p位

p=1代表段描述符有效,p=0代表段描述符无效

g位

当g位为零的时候,limit最大0xfffff,也就是20位。g位为1时最大0xffffffff,简便来说就是为0时limit的fffff前面添0,为1时后面添三个f

s位

s位为1的时候,代表当前段是代码段或者数据段,s位为0就是系统段,如果具体看是代码还是数据段,就看第六位的值,大于8就是代码段,小于8就是数据段

具体调试的时候看这里

image-20220912222317409

第五位也就是这里的9的位置,如果是9或者f就一定是数据段或者代码段,然后第六位如果是b对应的就是代码段

TYPE域

image-20220823225348273

数据段a位

type域中的第1位,也就是高四字节的第8位bit,代表是否已被访问

数据段w位

为1可写,为0不可写

数据段e位

拓展位,为0代表向上拓展,为1向下拓展

image-20220823230014040

左边图代表向上拓展,右边是向下拓展。左边意思是base到base+limit的那部分数据有效,右边是base到base+limit的其他的数据有效。

代码段a位

访问位,和上面的a位一样

代码段r位

可读位

代码段c位

c=1为一致代码段,c=0为非一致代码段

系统段描述符

image-20220823230423231

D/B位

d位干扰到的范围比较大

对CS的影响

D=1,用32位的寻址方式;D=0,用16位的寻址方式

前缀67改变寻址方式

对SS的影响

D=1,隐式堆栈访问指令(push,pop,call)使用32位堆栈指针寄存器ESP

D=0,使用16位堆栈指针寄存器SP

向下拓展的数据段

image-20220823232307901

段权限检查

CPU分级

就是0环3环

image-20220823233446678

确定0环或3环

cs的最低两位很特别,称为当前进程的特权级别,CPL。而3环和0环,就是对应的cs段寄存器的最低两位,也就是CPL,是3还是0.(牛逼啊)

CPL

CPL(Current Priviledge Level) :当前特权级

CS和SS中存储的段选择子后两位,这俩的后俩位一定一致

DPL

DPL(Descriptor Privilege Level):描述符特权级别

规定访问该段需要什么特权级

image-20220823235057260

RPL

RPL 请求特权级别

是针对段选择子而言的,每个段的选择子都有自己的RPL

数据段的权限检查

image-20220824000454601

总结

image-20220824000617225

代码跨段跳转

cs寄存器和eip必须一起改变,因为cs单独改变后eip就不准确了

代码间跳转

image-20220824204924532

假设代码如下

JMP 0x20:0x004183d7

cpu执行该代码的流程为

段选择字拆分

高位的两个字节对应的是段选择字,此处是0x20

对应二进制是0000 0000 0010 0000

RPL = 00 TI = 0 Index = 4

查表得到段描述符

TI=0 所以查GDT表

Index = 4 找到对应段描述符

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

权限检查

如果是非一致代码段,要求CPL==DPL,RPL<=DPL

如果是一致代码段,要求CPL>=DPL

一致代码段,随便用什么特权级都能访问,非一致的话就需要看特权级别

加载段描述符

如果上面的权限检查通过了,CPU就会将段描述符加载到CS段寄存器之中

代码执行

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

总结

image-20220824210735872

image-20220826162715425

代码跨段跳转实验

构造段描述符

image-20220826163336187

实验证明,非一致代码段低权限无法执行高权限的代码,改成一致代码段后就可以访问了

image-20220913095720215

长调用和短调用

短调用就是普通的call,不说了

长调用(跨段不提权)

image-20220913101250931

区别是会先压入cs再压入返回地址

长调用(跨段提权)

image-20220913101606340

提权会改变ss,所以压入。因为这里的跳转是从3环跳到0环,是两个完全不同的堆栈,所以我们需要存储esp来在返回的时候找到对应的3环栈顶的位置。

总结

image-20220913101821663

调用门

执行流程

image-20220913112213021

注意此处eip是完全没有用的

门描述符

image-20220913114125904

其中门描述符属于系统描述符的一种,12位和11位对应的type是写死的,代表这是个门描述符

上方的执行步骤的第二步所说的存储另一个代码段段的选择子,就是门描述符的这个Segment Selector。

所以真正要执行的代码段的位置,是这个Segment Selector对应的段作为偏移,然后加上这俩offset合起来的32位的offset作为偏移,找到对应的位置

其中上方的offset是高四位,下方的是第四位。

使用调用门

需要自己根据上方门描述符的结构构造调用门,因为windows没有使用,然后插入gdt表之中,然后可以通过长调用去到指定地址运行代码,且权限是0环,可以调用0环的数据和函数。

总结

image-20220913140135828

中断门

IDT

IDT就是中断描述符表,和GDT一样,IDT由一系列描述符组成,每个描述符占8个字节,但是第一个元素不是NULL

IDT表构成

  • 任务门描述符
  • 中断门描述符
  • 陷阱门描述符

中断门描述符

image-20220913141028479

和调用门差不多,但是没有地方传参数了。

陷阱门

陷阱门描述符

image-20220913144150333

陷阱门和中断门区别

中断门执行时,将IF位清零,但陷阱门不会,这是唯一的区别

如果为0,代表不再接受可屏蔽中断

可屏蔽中断就像运行程序时敲键盘,虽然程序没有运行完,但是我们敲键盘的操作还是会执行。

不可屏蔽中断就是,无论IF位为1或者0,CPU都会直接处理对应中断。

任务段

TSS段描述符

TSS是一段内存,大小104字节,通过TSS可以同时替换一堆寄存器,包括通用寄存器和段寄存器等。

TR段寄存器是用来让CPU找到TSS段描述符的。

CPU通过TR段寄存器找到TSS,我们如果想用自己的TSS段替换原来的寄存器,就要改TR寄存器,但是TR寄存器来自TSS段描述符,所以我们得构造一个TSS段描述符

修改TR寄存器

image-20220913202546916

LTR只改变TR寄存器,不改变其他寄存器。

保护模式十分复杂就在这里。jmp如果访问的是代码段,它只改变cs和eip俩寄存器。但是如果它访问的是任务段,他会把0x48对应的段描述符加载出来放到TR寄存器里,然后用TR寄存器的108个字节,全部拿出来赋值给TSS,把所有寄存器全部改变。

任务门

任务门描述符

image-20220913203749490

此处涉及到一个换表,因为任务门存储的位置是IDT,而TSS段选择子存储的位置是GDT,所以比较麻烦

任务门执行流程

image-20220913203931686

分页

物理地址

image-20220913205741468

image-20220913205850886

设置分页方式

image-20220913210155229

改了之后分页方式就是10-10-12,没改就是2-9-9-12(x32)

10-10-12分页

加起来刚好32位,就是将线性地址转为10 10 12位

假设用记事本存储一个字符串,字符串的线性地址是000aa8a0

分一下

0000 0000 00

00 1010 1010

8a0

10-10-12的形式

image-20220914010311215

注意寻址的时候,第二个10要乘4,因为一个成员是4个字节,不过第一个10和第三个12不需要乘

PDE和PTE

注意所有寄存器中,只有cr3存储的是物理地址,其他存储的都是线性地址

image-20220914011353083

PDT

对应上图的页目录表,也就是第一个10位寻址的对应的表。而PDE就是页目录表的元素

PTT

页表,第二个10位寻址的对应的表,PTE就是页表的元素

PTE特性

image-20220914012432240

10-10-12最后一位是12的原因是2的12次方是4096,也就是一页的大小,这样才可以让物理页每个部分都可以被访问到

向0地址读写数据

image-20220914013035933

0地址不能读写,会报错的原因是0对应的线性地址对应的物理页为空,没有物理页谈何读写存储数据呢,所以会报错。而如果我们在0线性地址对应的pte挂一个物理页上去,那么就可以正常的进行读写,十分的牛逼。

属性

image-20220914212623637

p位

image-20220915111826909

因为物理页的属性是PDE和PTE与的结果,所以p位必须两个都为1才能访问,不然挂了物理页也不能访问目标地址。

R/W位

image-20220915112108711

U/S位

image-20220915112859258

P/S位

image-20220915113001776

意思就是,本来10-10-12分页是PDE,PTE,然后是物理页,这里不需要PTE了,直接10的PDE后跟22位的物理页,也就是大页,一页4mb。

A位

是否被访问过,访问过置1,没访问过置0.只访问了一个字节也会置1

D位

是否被写过,写过置1

页目录表基址

直接访问的线性地址

C0300000作为线性地址可以直接访问页目录表基址,也就是cr3对应的物理内存

拆分C0300000

image-20220915120702482

页目录表基址(10-10-12)

image-20220915120757785

如下公式:0xC0300000+ N * 4

实际上没有PDT,有的是PTT,PDT是PTT里一个特殊的元素,指向其他PTE,然后其他PTE指向物理内存

c0000000线性地址对应的是第一个PTT

c0001000线性地址对应的是第二个PTT

总结

image-20220915140629261

有了0xc0300000和0xc0000000后

image-20220915140919481

PDI为页目录表索引,PTI为页表索引

2-9-9-12分页

又称PAE(物理地址扩展分页)

为什么是10-10-12

image-20220915143053348

为什么是2-9-9-12

image-20220915150858098

2-9-9-12分页结构(PAE,物理地址扩展)

image-20220915153106961

PDPTE结构

image-20220915153350657

PDE结构

image-20220915153740452

PTE结构

image-20220915165746802

XD标志位(NX,No Excetion)

image-20220915215653608

TLB

地址解析

image-20220915220928242

TLB结构

image-20220915222131466

一个CPU对应一个TLB

PDE中g位只有在PDE为大页的时候才去考虑,如果g位为1是全局页,就来给TLB来看的。

TLB种类

image-20220915222833845

实验

image-20220915223445327

TLB的存在,就是在a处挂一个物理页b,然后执行后把b换成c,然后继续访问a的物理页,会发现还是b,不是c,因为用了一次后存入TLB了,没有对新的物理页也就是c进行读写。

中断

是什么

image-20220915230026700

非可屏蔽中断处理

image-20220915230250676

可屏蔽中断处理

image-20220915230422169

image-20220915230805913

时钟中断

image-20220915230622844

异常

是什么

image-20220915231406675

异常处理

image-20220916141230530

不可屏蔽中断走IDT的2号门,也就是0x2

缺页异常

image-20220916141355435

控制寄存器

Cr0

image-20220916142307693

image-20220916142512108

Cr2

image-20220916144139422

Cr4

image-20220916144306725

PWT/PCD

CPU缓存

image-20220916144613710

PWT/PCD属性

image-20220916144824713