[windows內核]PDE&PTE

2020-08-10 01:53:36

Cr3

描述:

在所有的暫存器中,只有Cr3儲存的是實體地址,其它暫存器存的都是線性地址
Cr3所儲存的實體地址指向了一個頁目錄表(PDT)
在Windows中,一個頁的大小通常爲4KB,即一個頁可以儲存1024個頁目錄表項(PDE)

下面 下麪是手冊中的描述在第3卷2.5 CONTROL REGISTERS
在这里插入图片描述
物理頁結構圖:

在这里插入图片描述
注意:但其實上面這種結構方式是錯誤的,這個以後再解釋,先這樣理解

PDE(頁目錄表項)

描述:

頁目錄表(PDT)的每一項元素稱爲頁目錄表項(PDE)
每個頁目錄表項指向一個頁表(PTT)
每個頁表的大小爲4KB,即一個頁表可以儲存1024個頁表項(PTE)

PTE(頁表項)

描述:

頁表(PTT)的每一個元素稱爲頁表項(PTE)
頁表項(PTE)所指向的纔是真正的物理頁

特點:

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

物理頁的屬性

物理頁的屬性=PDE屬性& PTE屬性
在这里插入图片描述
下面 下麪兩張圖看得更直觀一些

PDE(頁目錄表項)
在这里插入图片描述
PTE(頁表項)
在这里插入图片描述
P 位 – 存在位,表示當前條目是否在實體記憶體中

R/W 位 – 讀寫許可權位,爲 0 表示只讀,爲 1 表示可讀寫

U/S 位 – 也稱爲許可權位,頁或一組頁的特權級,爲 0 表示系統級,對應 CPL 0、1、2,爲 1 表示使用者級,對應 CPL 3。

PWT – 頁表緩衝寫入機制 機製,爲 0 表示 write-back 模式,更新頁表緩衝區時,只標記爲已更新,不同步寫記憶體,只有被新進入的數據取代時才更新到記憶體,爲 1 表示 write-through 模式,更新頁表緩衝區時,同步寫記憶體,保證緩衝區與記憶體一致

PCD – 是否拒絕被緩衝,爲 0 表示可以被緩衝,爲 1 表示不可以被緩衝

A 位 – 是否被存取,CPU 會在存取到頁面時將該位置 1,但不會清除,只有軟體可以將 A 位復位

D 位 – 是否被寫入,CPU 會在寫入頁面時將該位置 1,但不會清除,只有軟體可以將 D 位復位

PS – PDE特有,頁大小位,爲 0 表示頁大小爲 4KB,且 PDE 指向頁表,爲 1 表示頁大小爲 4MB,且 PDE 指向 4MB 的整塊記憶體

PAT – 奔騰3以後的 CPU 引入的頁屬性表標識位,爲 1 開啓頁屬性表後,通過一系列專用暫存器(MBR)爲每個頁提供了詳細的屬性設定

G 位 – 全域性位,也稱爲髒位,如果該位與 CR4 暫存器的 PGE 位同時被置爲 1,則該頁或頁目錄項將不會在 TLB 中被逐出

20bits 基地址 – PDE 與 PTE 的高 20bits 都是下級頁基址,無論是頁目錄表還是頁表還是在記憶體中的頁,他們都是 4KB 對齊的,也就是說他們的首地址低12位元均爲0,這樣,只需要通過 20bits 的基地址 * 12 就可以得到計算後的 32 位實體地址了

10-10-12分頁的補充

爲什麼要按10-10-12分頁:

  1. 一個物理頁的大小爲4096位元組,即2的12次方,若要遍歷整個物理頁,則需要12個位元位
  2. 一個頁表有1024個頁表項,1024等於2的十次方,即需要10個位元位
  3. 頁目錄表項同理,也需要10個位元位

實驗

證明PTE特徵
PTE可以指向一個物理頁,也可以不指向物理頁
在这里插入图片描述
在这里插入图片描述

可以發現有許多頁表項都爲0,沒有指向任何物理頁

實驗2
通過修改頁表使C語言能在0地址處讀寫
編譯如下程式碼

#include <iostream>
#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地址的數據:%x\n", *(int*)0);

	getchar();
	return 0;
}

執行
在这里插入图片描述
得到地址後中斷進入windbg
使用WinDbg將虛擬機器中斷,將變數x所在的物理頁掛載到線性地址0的PTE
拆分

0012ff3c

0000 0000 0001 0010 1111 1111 0011 1100

0000 0000 00   //0
01 0010 1111   //0x12F
1111 0011 1100 //0xF3C

在这里插入图片描述
修改
在这里插入图片描述
返回繼續執行
在这里插入图片描述
在这里插入图片描述

成功對0地址進行了讀寫
由此可見,0地址是否能讀寫和其他無關只與PDE 和 PTE有關

實驗3
通過修改物理頁屬性使字串常數可修改

編譯如下程式碼

#include <iostream>
#include <windows.h>



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

	printf("線性地址:%x\n", str);

	getchar();						// 讓程式執行到這裏

	//修改只讀變數
	str[0] = 'M';

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

	getchar();
}

開啓x32dbg,我們可以看到

在这里插入图片描述
去記憶體佈局裡尋找字串位置,發現字串再.rdata段,而rdata段只有可讀屬性,並沒有可寫屬性

在这里插入图片描述
如果繼續執行到修改的時候,就會產生一個0xc0000005異常

在这里插入图片描述
我們再次執行程式

在这里插入图片描述
得到str地址,進入windbg中斷,得到Cr3

在这里插入图片描述
拆分地址

00413160

0000 0000 0100 0001 0011 0001 0110 0000

0000 0000 01   //1
00 0001 0011   //0x13
0001 0110 0000 //0x160

在这里插入图片描述
拆分

0x2277E005
0010 0010 0111 0111 1110 0000 0000 0101

從上面的圖片可知道PTE的第1位是R/W 位,所以修改後爲

0x2277E007
0010 0010 0111 0111 1110 0000 0000 0111

在这里插入图片描述
然後繼續執行程式

在这里插入图片描述
成功修改str,所以可以看出記憶體的讀寫只與PDE 和 PTE有關於其他無關,這裏可以看出一個有意思的東西,就是PTE雖然有R/W位但是沒有標記記憶體是否可以執行,其實對於CPU來說任何它能識別的code都是可以執行的,但是爲什麼再程式裡卻有些記憶體有執行屬性有些記憶體卻沒有,這裏有興趣的可以自行拓展一下

實驗4
通過修改物理頁屬性使普通使用者讀取高2G記憶體

編譯如下程式碼

#include <iostream>
#include <windows.h>



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

	getchar();			// 讓程式執行到這裏

	printf("讀取高2G記憶體:%x \n", *p);
	
	getchar();
	return 0;
}

在这里插入图片描述
再次啓動程式,執行,中斷進入windbg,檢視cr3

在这里插入图片描述

拆分

0x84279a7a

1000 0100 0010 0111 1001 1010 0111 1010

1000 0100 00   //0x210
10 0111 1001   //0x279
1010 0111 1010 //0xA7A

然後修改PDE與PTE的U/S位
在这里插入图片描述

通過上圖我們可以知道U/S位在第二位
拆分

0x001C3063
000111000011000001100011

0x4279125
0100001001111001000100100101

修改後

0x001C3067
000111000011000001100111

0x4279125
0100001001111001000100100101

在这里插入图片描述
返回繼續執行程式

在这里插入图片描述
在这里插入图片描述

成功讀取高2G記憶體,由此可見讀取的許可權只與PDE 和 PTE有關,與其他無關