Windows保护模式学习笔记(七)—— PDE&PTE

前言

一、学习自滴水编程达人中级班课程,官网:https://bcdaren.com
二、海东老师牛逼!

Cr3

描述:

在所有的寄存器中,只有Cr3存储的是物理地址,其它寄存器存的都是线性地址
Cr3所存储的物理地址指向了一个页目录表(PDT)
在Windows中,一个页的大小通常为4KB,即一个页可以存储1024个页目录表项(PDE)

物理页结构图:
物理页结构图

PDE(页目录表项)

描述:

页目录表(PDT)的每一项元素称为页目录表项(PDE)
每个页目录表项指向一个页表(PTT)
每个页表的大小为4KB,即一个页表可以存储1024个页表项(PTE)

PTE(页表项)

描述:

页表(PTT)的每一个元素称为页表项(PTE)
页表项(PTE)所指向的才是真正的物理页

特征:

  1. PTE可以指向一个物理页,也可以不指向物理页
  2. 多个PTE可以指向同一个物理页
  3. 一个PTE只能指向一个物理页

物理页的属性

物理页的属性=PDE属性& PTE属性
PDE属性
PTE属性
P位:是否有效位
注意:当PDE或PTE中有一个的属性P=0时,物理页就是无效的

R/W位:读写位
R/W=0:只读
R/W=1:可读可写

U/S位:权限位
U/S=0:特权用户
U/S=1:普通用户

PS位PDE特有
PS == PageSize
PS=1:PDE直接指向物理页,低22位=页内偏移,偏移最大值为4MB,俗称"大页"
PS=0:PDE指向PTE

A位:访问位
A=1:该PDE/PTE被访问过
A=0:该PDE/PTE未被访问过

D位:脏位
D=1:该PDE/PTE被写过
D=0:该PDE/PTE未被写过

注:其他位等学完控制寄存器与TLB才能讲,本篇不讲

10-10-12分页的补充

为什么要按10-10-12分页:

  1. 一个物理页的大小为4096字节,即2的12次方,若要遍历整个物理页,则需要12个比特位
  2. 一个页表有1024个页表项,1024等于2的十次方,即需要10个比特位
  3. 页目录表项同理,也需要10个比特位

注:以下实验的分页方式都为10-10-12分页

实验1:证明PTE的特征1

第一步:选择一个进程的Cr3

我这里启动了一个记事本:notepad.exe
记事本Cr3

第二步:查看页表

查看当线性地址为0时,进程的页表
线性地址0的页表
可以发现有许多页表项都为0,没有指向任何物理页

实验2:通过修改页表使C语言能在0地址处读写

第一步:得到一个变量的地址

运行代码如下:

#include <stdio.h>
#include <windows.h>

int main(int argc, char *argv[])
{
	int x = 1;

	printf("x的地址:%x\n", &x);

	getchar();

	// 向0地址写入数据
	*(int*)0 = 123;
	// 从0地址读出数据
	printf("0地址的数据:", *(int*)0);

	getchar();
	return 0;
}

程序运行后,首先会输出x的地址
x的地址

第二步:挂载PTE为0的物理页

使用WinDbg将虚拟机中断,将变量x所在的物理页挂载到线性地址0的PTE
挂载物理页

第三步:继续运行程序

运行结果:
运行结果
成功对0地址进行了读写,实验成功!

实验3:通过修改物理页属性使字符串常量可修改

第一步:运行程序

代码如下:

#include <stdio.h>
#include <windows.h>

int main(int argc, char *argv[])
{
	char *str = "Hello World";

	printf("线性地址:%x", str);

	getchar();						// 让程序执行到这里

	//修改只读变量
	str[0] = 'M';

	printf("修改后的值:%s\n",str);

	return 0;
}

这时候得到了str的地址:
str的地址

第二步:修改对应PTE的属性

修改PTE属性

第三步:继续运行程序

运行结果:
运行结果
修改成功!

实验4:通过修改物理页属性使普通用户读取高2G内存

第一步:运行如下代码

#include <stdio.h>
#include <windows.h>

int main(int argc, char *argv[])
{
	PDWORD p = (PDWORD)0x8003F00C;

	getchar();			// 让程序运行到这里

	printf("读取高2G内存:%x \n", *p);

	return 0;
}

第二步:修改PDE与PTE的U/S位

修改U/S位

第三步:继续运行程序

运行结果如下:
运行结果
成功读取了高2G的内存!

发布了45 篇原创文章 · 获赞 2 · 访问量 1860

猜你喜欢

转载自blog.csdn.net/qq_41988448/article/details/102627239