(18)修改 PTE 实现挂物理页读写空指针
一、10-10-12二級映射
下圖是101012二級映射結(jié)構(gòu):
二、讀寫NULL指針
正常編程中,不能讀寫NULL,原因是NULL指針沒有對應(yīng)的物理頁,因此,只要我們讓NULL指針最終映射到一塊可讀寫的物理頁,就可以用NULL去讀寫數(shù)據(jù)了。
代碼短小精悍,也很好理解,關(guān)鍵步驟都在windbg里操作。下面先讓程序跑起來,停在getchar()處。
// PDE_PTE.cpp : Defines the entry point for the console application. //#include "stdafx.h"int _tmain(int argc, _TCHAR* argv[]) {int x = 1; // 讓NULL指向x所在的物理頁printf("x的地址:%x\n", &x);getchar(); // 在windbg里修改NULL 的PTE// NULL不能讀寫,原因是PTE為0,即沒有分配物理頁// 所以只要給NULL的PTE分配物理頁,就能讀寫NULL了 printf("NULL地址數(shù)據(jù):%x\n",*(int*)NULL);*(int*)NULL = 0x112233; printf("NULL地址數(shù)據(jù):%x\n",*(int*)NULL); // 0x112233return 0; }然后,在windbg里按照上一節(jié)課的做法,找到 x 的物理地址。
拆分x的地址 0x0012ff60
00000000?00 0x0
0100101111 0x12f
111101100000? 0xf60
!process 0 0 查到CR3=1915d000,CR3的值是PDT表的基址。
!dd 1915d000+40 查到x對應(yīng)的PDE也就是PDT[0]=07842067,屬性清零后是 07842000,這個值是x的PTT的基址。
!dd 07842000+412f 查x的PTE也就是PTT[12f]=0ce53067,屬性清零后就得到x的物理頁基址 0ce53000
!dd 0ce53000+f60 以dword形式查看x的內(nèi)存
NULL = 0
拆分得:
00000000?00
00000000?00
00000000?0000
下標(biāo)全是0。
CR3是一樣的,一個進(jìn)程只有一個,CR3=1915d000
找NULL的PDE,!dd 1915d000,因為下標(biāo)都是0,所以NULL 的PDE 和 x的PDE是一樣的,不用改,都是 07842067。
所以 07842000 就是NULL的PTT,然后NULL的第二個下標(biāo)也是0,所以 !dd 07842000 就能查到PTT[0] 即 NULL的PTE,值是0.
用!ed指令改寫成x的PTE 0ce53067
!ed 7842000 0ce53067
回顧一下剛開始的二級映射結(jié)構(gòu)圖:
現(xiàn)在x和NULL的PTE值相同,NULL和x處于同一個物理頁,物理頁基址是 0ce53000,但是物理地址仍然是不同的,因為x在物理頁內(nèi)的偏移是 0xf60,而NULL的偏移是0。
但是沒有關(guān)系,NULL已經(jīng)指向了一塊可用的物理頁了,現(xiàn)在可以對NULL進(jìn)行讀寫了。
三、為變量x再映射一個線性地址,并通過這個新的地址讀取x的值
方法是調(diào)用 VirtualAlloc 申請一個物理頁,得到一個指針p,拆分地址,將p后12位改成和x的后12位相同,這樣就構(gòu)造好了一個新的線性地址。
解釋一下為什么要VirtualAlloc,目的是確保有一塊可用的物理頁,并且和x的物理頁不是同一個;而修改p的后12位,目的是讓p的物理頁偏移和x一樣。
接下來,只需要修改p的PDE和PTE,使得p和x指向同一個物理頁即可。
// PDE_PTE.cpp : Defines the entry point for the console application. //#include "stdafx.h" #include <Windows.h>int _tmain(int argc, _TCHAR* argv[]) {int x = 0x1;printf("x的地址:%x\n", &x);// 申請一個新的物理頁,將p的PTE和物理頁內(nèi)偏移改成和x一樣int p = (int)VirtualAlloc(NULL,0x1000,MEM_COMMIT,PAGE_READWRITE);int p_bak = p;memset((int*)p,0,0x1000);p &= 0xFFFFF000;p |= ((int)&x & 0x00000FFF);printf("新的線性地址:%x\n", p);getchar(); // 在windbg里修改 p 的 PTE// 用新的線性地址讀xprintf("*addr:%x\n",*(int*)p); // 0x1// 用新的線性地址寫x*(int*)p = 0x112233;printf("x:%x\n",x); // 0x112233getchar();VirtualFree((int*)p_bak,0x1000,MEM_DECOMMIT);return 0; }讓程序跑起來:
然后將p的PTE改成和x的PTE一樣,這個過程步驟繁瑣:
拆分x:
0x0012ff60
00000000?00 0x0
0100101111 0x12f
111101100000? 0xf60
拆分p:
0x003b0f60
00000000?00 0x0
1110110000 0x3b0
111101100000? 0xf60
查CR3:
!process 0 0
CR3 = 0ef6f000
查PDEx
!dd 0ef6f000
PDEx = 09f43067
查PTEx
!dd 09f43000+4*12f
PTEx = 0f461047
查PTEp
!dd 09f43000+4*3b0
改PTEp
!ed 9f43ec0 0f461047
執(zhí)行剩余的代碼:
實驗成功,用新的線性地址讀寫了x。
然后,就藍(lán)屏了,我不知道是什么原因。報錯說是 Probably caused by : memory_corruption ( nt!MiSwapWslEntries+157 ),看不懂呀!
四、10-10-12分頁模式物理內(nèi)存能夠識別的最多范圍是多少
頁目錄表有1024項,頁表有1024項,物理頁有4KB
尋址范圍:1024 * 1024 * 4096 = 4GB
五、如何判斷2個線性地址是否在同一個物理頁?
看線性地址前20位,只要相同就在同一個物理頁。
因為前20位確定了PDE 和 PTE,PTE相同一定是同一個物理頁。
總結(jié)
以上是生活随笔為你收集整理的(18)修改 PTE 实现挂物理页读写空指针的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: (17)10-10-12分页
- 下一篇: (19)修改PDE PTE 的RW位使物