前言: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位(十六進制的情況下)是否相同來判斷是否在同一個物理頁