PDE_PTE和PDE_PTE屬性(P位和R/W位)


前言:PDE_PTE的學習筆記

這篇學完后,就可以知道物理地址中的任何的一個內存地址,沒有地方是訪問不了的,最重要的就是保護模式,其實也就是繞過保護模式來實現任意物理地址的讀寫,更准確的就是學習PDE和PTE來實現對物理頁的修改操作

上篇學習分頁10-10-12的筆記中,潦草的概述的相關的一級,二級物理頁,這篇筆記來學習記錄相關的物理頁的知識點

PDE與PTE

從這張圖中可以看出來,其實一級物理頁對應的就是頁目錄表,頁目錄表中有1024個頁目錄項(也就是PDE結構,每個占四個字節),所以頁目錄項的大小為4096個字節

接着就是二級物理頁對應的就是頁表,頁表中有1024個頁目錄項(也就是PTE結構,每個占四個字節),所以頁表的大小為4096個字節

其中PTE指向的物理頁,其實就是代表着一個線性地址在物理內存中的真正存儲的地址

知識點:

1、PTE可以沒有物理頁,且只能對應一個物理頁.

2、多個PTE也可以指向同一個物理頁.

物理頁的屬性

PTE所指向的物理頁的屬性是由PDE中的屬性和PTE的屬性共同決定的 => 物理頁的屬性 = PDE屬性 & PTE屬性

PDE的結構

PTE的結構

P位

通過觀察下面的PDE和PTE的結構,這里一些屬性我們需要了解,這里可以先看P位的屬性,想要看物理頁是否有效,就需要看PDE與PTE的P位是否都為1,只有都為1的才是有效的物理頁

R/W位

當PDE和PTE的R/W = 0 只讀屬性

當PDE和PTE的R/W = 1 可讀可寫

練習,查分0地址,觀察PTE是否有物理頁

測試代碼如下,經過windbg調試,可以發現一個進程中0地址的PTE中是沒有物理頁的

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

int main()
{
	int* p = 0;
	printf("%x\n", p);
	getchar();

	return 0;
}

練習,線性地址0為什么不能讀寫?實現將0地址設置可讀可寫,嘗試讀寫數據

默認線性地址0不能讀寫的原因就是默認一個進程中0地址的PTE中是沒有物理頁的

所以如果想要實現0地址設置可讀可寫,那么我們就需要修改其線性0地址所對應的PTE和PDE的屬性,也就是十六進制的后三位

測試代碼如下圖所示,然后來構造定義的x變量的地址為0x12ff7c,拆分如下

0012ff7C 
-> 
0000 0000 00
01 0010 1111  -> 4BC
f7C

然后接着就是該線性地址0x12ff7c的物理地址,如下圖所示,這個地址0x3a14f867,就是PTE中存儲的地址的值,那么這個值就是指向一個物理頁的地址

這里將0地址中默認存儲的PTE為00000000的值改為3a14f867(這里的867后12位也需要一樣的,因為都是需要可讀可寫),也就是上面變量x的PTE中存儲的值,那么此時0線性地址中指向的物理頁和變量x所指向的物理頁是同一個物理頁

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

int main()
{
	int x=1;
	printf("&x = %x\n", &x);
	getchar();
	printf("NULL地址數據:%x\n",*(int*)NULL);
	*(int*)NULL = 0x12345678;	
	printf("NULL地址數據:%x\n",*(int*)NULL); // 0x12345678
	return 0;
}

練習,為變量x再映射一個地址,並通過新的地址來讀取變量x的值

自己的想法是這樣的,通過新的地址來讀取變量x的值,然后這個新的地址又不能跟變量x的線性地址一樣,所以想要讓一樣就需要讓PTE都是指向同一個物理頁即可,那么就需要讓偏移量一樣,所以這里自己主動申請一個地址,然后在相同10-10-12,其中12后三位的偏移地址計算,計算公式為 ((int)pAddr & 0xFFFFF000) |((int)&x & 0x00000FFF)

測試代碼如下:

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

int main()
{
	int x=0x1;
	printf("&x = %x\n", &x);
	int* pAddr = (int*)VirtualAlloc(NULL,0x1000,MEM_COMMIT,PAGE_READWRITE);
	memset(pAddr, 0, 0x1000);
	int* pi = pAddr;
	if(pAddr != NULL ){
		printf("virtualAlloc succeed, addr is %x\n", pAddr);
		printf("addr: %x\n", ((int)pAddr & 0xFFFFF000) |((int)&x & 0x00000FFF)); // get
	}else{
		printf("virtualAlloc failed!\n", pAddr);
	}
	pi = (int*)(((int)pAddr & 0xFFFFF000) |((int)&x & 0x00000FFF));
	printf("*pi -> %d\n", *pi);
	printf("pi -> %x\n", pi);
	getchar();
	printf("%d\n", *pi);
	return 0;
}

getchar()之后,然后修改新申請的(同變量的偏移地址)的線性地址來進行修改相關的PTE,如下圖所示

0012ff7C (變量x)
-> 
0000 0000 00
01 0010 1111 *4 -> 4BC
f7C

003a0f7c (新申請的地址,后12位同偏移)
->
0000 0000 00
11 1010 0000 *4 = E80
f7c

x變量的PTE為36b91867,如下圖所示

接着找到新申請的地址003a0f7c的地方

找到新申請的地址003a0f7c,將其線性地址所指向的PTE修改為新的PTE(也就是修改為X線性地址的PTE),命令為!ed 36978e80 36b91867

結果如下

練習,10-10-12分頁模式物理內存能夠識別的最多范圍是多少?

10-10-12,分別就是2^10 * 2^10 * 2^12 ,也就是2^32,那么最多范圍就是4G尋址

練習,如何判斷2個線性地址是否在同一個物理頁?

一個進程中,2個線性地址可以通過線性地址的前5位(十六進制的情況下)是否相同來判斷是否在同一個物理頁


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM