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