保护模式-滴水逆向观看笔记
保护模式
简介
x86cpu一共三种模式,实模式,保护模式,虚拟8086模式
特点
- 段机制
- 页机制
段寄存器
是什么
比如
mov dword ptr ds:[0x12345678],5
就是ds段寄存器作为base,偏移0x12345678的位置
一共有ES CS SS DS FS GS LDTR TR共8个
结构
selecter是可见部分
attribute是属性部分,可读可写可执行
base是基址
limit是总长度多少
可以通过mov指令对段寄存器进行读写(除了LDTR,TR)
成员简介
GDT和LDT
GDT是全局描述符表,LDT是局部描述符表
我们执行mov ds,ax等指令时,CPU会查表,根据AX的值决定查找GDT或者LDT
段描述符
段选择子
加载段描述符到段寄存器
这里十分有意思,用到了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就是数据段
具体调试的时候看这里
第五位也就是这里的9的位置,如果是9或者f就一定是数据段或者代码段,然后第六位如果是b对应的就是代码段
TYPE域
数据段a位
type域中的第1位,也就是高四字节的第8位bit,代表是否已被访问
数据段w位
为1可写,为0不可写
数据段e位
拓展位,为0代表向上拓展,为1向下拓展
左边图代表向上拓展,右边是向下拓展。左边意思是base到base+limit的那部分数据有效,右边是base到base+limit的其他的数据有效。
代码段a位
访问位,和上面的a位一样
代码段r位
可读位
代码段c位
c=1为一致代码段,c=0为非一致代码段
系统段描述符
D/B位
d位干扰到的范围比较大
对CS的影响
D=1,用32位的寻址方式;D=0,用16位的寻址方式
前缀67改变寻址方式
对SS的影响
D=1,隐式堆栈访问指令(push,pop,call)使用32位堆栈指针寄存器ESP
D=0,使用16位堆栈指针寄存器SP
向下拓展的数据段
段权限检查
CPU分级
就是0环3环
确定0环或3环
cs的最低两位很特别,称为当前进程的特权级别,CPL。而3环和0环,就是对应的cs段寄存器的最低两位,也就是CPL,是3还是0.(牛逼啊)
CPL
CPL(Current Priviledge Level) :当前特权级
CS和SS中存储的段选择子后两位,这俩的后俩位一定一致
DPL
DPL(Descriptor Privilege Level):描述符特权级别
规定访问该段需要什么特权级
RPL
RPL 请求特权级别
是针对段选择子而言的,每个段的选择子都有自己的RPL
数据段的权限检查
总结
代码跨段跳转
cs寄存器和eip必须一起改变,因为cs单独改变后eip就不准确了
代码间跳转
假设代码如下
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处的代码,段间跳转结束。
总结
代码跨段跳转实验
构造段描述符
实验证明,非一致代码段低权限无法执行高权限的代码,改成一致代码段后就可以访问了
长调用和短调用
短调用就是普通的call,不说了
长调用(跨段不提权)
区别是会先压入cs再压入返回地址
长调用(跨段提权)
提权会改变ss,所以压入。因为这里的跳转是从3环跳到0环,是两个完全不同的堆栈,所以我们需要存储esp来在返回的时候找到对应的3环栈顶的位置。
总结
调用门
执行流程
注意此处eip是完全没有用的
门描述符
其中门描述符属于系统描述符的一种,12位和11位对应的type是写死的,代表这是个门描述符
上方的执行步骤的第二步所说的存储另一个代码段段的选择子,就是门描述符的这个Segment Selector。
所以真正要执行的代码段的位置,是这个Segment Selector对应的段作为偏移,然后加上这俩offset合起来的32位的offset作为偏移,找到对应的位置
其中上方的offset是高四位,下方的是第四位。
使用调用门
需要自己根据上方门描述符的结构构造调用门,因为windows没有使用,然后插入gdt表之中,然后可以通过长调用去到指定地址运行代码,且权限是0环,可以调用0环的数据和函数。
总结
中断门
IDT
IDT就是中断描述符表,和GDT一样,IDT由一系列描述符组成,每个描述符占8个字节,但是第一个元素不是NULL
IDT表构成
- 任务门描述符
- 中断门描述符
- 陷阱门描述符
中断门描述符
和调用门差不多,但是没有地方传参数了。
陷阱门
陷阱门描述符
陷阱门和中断门区别
中断门执行时,将IF位清零,但陷阱门不会,这是唯一的区别
如果为0,代表不再接受可屏蔽中断
可屏蔽中断就像运行程序时敲键盘,虽然程序没有运行完,但是我们敲键盘的操作还是会执行。
不可屏蔽中断就是,无论IF位为1或者0,CPU都会直接处理对应中断。
任务段
TSS段描述符
TSS是一段内存,大小104字节,通过TSS可以同时替换一堆寄存器,包括通用寄存器和段寄存器等。
TR段寄存器是用来让CPU找到TSS段描述符的。
CPU通过TR段寄存器找到TSS,我们如果想用自己的TSS段替换原来的寄存器,就要改TR寄存器,但是TR寄存器来自TSS段描述符,所以我们得构造一个TSS段描述符
修改TR寄存器
LTR只改变TR寄存器,不改变其他寄存器。
保护模式十分复杂就在这里。jmp如果访问的是代码段,它只改变cs和eip俩寄存器。但是如果它访问的是任务段,他会把0x48对应的段描述符加载出来放到TR寄存器里,然后用TR寄存器的108个字节,全部拿出来赋值给TSS,把所有寄存器全部改变。
任务门
任务门描述符
此处涉及到一个换表,因为任务门存储的位置是IDT,而TSS段选择子存储的位置是GDT,所以比较麻烦
任务门执行流程
页
分页
物理地址
设置分页方式
改了之后分页方式就是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的形式
注意寻址的时候,第二个10要乘4,因为一个成员是4个字节,不过第一个10和第三个12不需要乘
PDE和PTE
注意所有寄存器中,只有cr3存储的是物理地址,其他存储的都是线性地址
PDT
对应上图的页目录表,也就是第一个10位寻址的对应的表。而PDE就是页目录表的元素
PTT
页表,第二个10位寻址的对应的表,PTE就是页表的元素
PTE特性
10-10-12最后一位是12的原因是2的12次方是4096,也就是一页的大小,这样才可以让物理页每个部分都可以被访问到
向0地址读写数据
0地址不能读写,会报错的原因是0对应的线性地址对应的物理页为空,没有物理页谈何读写存储数据呢,所以会报错。而如果我们在0线性地址对应的pte挂一个物理页上去,那么就可以正常的进行读写,十分的牛逼。
属性
p位
因为物理页的属性是PDE和PTE与的结果,所以p位必须两个都为1才能访问,不然挂了物理页也不能访问目标地址。
R/W位
U/S位
P/S位
意思就是,本来10-10-12分页是PDE,PTE,然后是物理页,这里不需要PTE了,直接10的PDE后跟22位的物理页,也就是大页,一页4mb。
A位
是否被访问过,访问过置1,没访问过置0.只访问了一个字节也会置1
D位
是否被写过,写过置1
页目录表基址
直接访问的线性地址
C0300000作为线性地址可以直接访问页目录表基址,也就是cr3对应的物理内存
拆分C0300000
页目录表基址(10-10-12)
如下公式:0xC0300000+ N * 4
实际上没有PDT,有的是PTT,PDT是PTT里一个特殊的元素,指向其他PTE,然后其他PTE指向物理内存
c0000000线性地址对应的是第一个PTT
c0001000线性地址对应的是第二个PTT
总结
有了0xc0300000和0xc0000000后
PDI为页目录表索引,PTI为页表索引
2-9-9-12分页
又称PAE(物理地址扩展分页)
为什么是10-10-12
为什么是2-9-9-12
2-9-9-12分页结构(PAE,物理地址扩展)
PDPTE结构
PDE结构
PTE结构
XD标志位(NX,No Excetion)
TLB
地址解析
TLB结构
一个CPU对应一个TLB
PDE中g位只有在PDE为大页的时候才去考虑,如果g位为1是全局页,就来给TLB来看的。
TLB种类
实验
TLB的存在,就是在a处挂一个物理页b,然后执行后把b换成c,然后继续访问a的物理页,会发现还是b,不是c,因为用了一次后存入TLB了,没有对新的物理页也就是c进行读写。
中断
是什么
非可屏蔽中断处理
可屏蔽中断处理
时钟中断
异常
是什么
异常处理
不可屏蔽中断走IDT的2号门,也就是0x2