给0地址挂上物理页,吧VirtualAlloc函数开辟的线性地址物理页给0地址挂上,这样这两个线性地址访问的就是同一个物理页,
内存映射的本质就是相同或者不同进程的两个线性地址,使用同一个物理页
这个是2-9-9-12分页的,如果10-10-12分页会更简单,代码可以在此基础上改
这里我将只提几个需要注意到的问题
1.memset填充是为了 VirutalAlloc开辟内存后,线性地址并不会马上挂上物理页,PTE没有指向物理页需要注意
2.那个裸函数注释掉的代码需要注意,虽然说要把那个线性地址PDE和PTE给0挂上,但是0本身有PDE而且一张PTT表(
写可以找到2MB的物理内存)异常 而ring3堆栈 在0x0013XXXX 所以ring3堆栈访问的时候需要依赖0线性地址本身的PDE
一个PDE项可以访问2MB,0-0x00200000 这段线性地址公有一个PDE,所以如果给0地址挂上PDE直接就挂了,(Ring3下)访问堆栈的指令就全都完了,我调试了大半天在才发现这第2个错误需要大家注意
如果想理解PDE和PTE公式计算的本质,或者页机制的本质可以看这篇帖子https://blog.csdn.net/taolaodawho/article/details/109183883,里面详细的描述了页表是如何映射到线性地址的
#include "stdafx.h"
#include <Windows.h>
typedef struct AddresSegment{ //这个用于扩展,这里面并没有用到
DWORD PDPI;
DWORD PDEI;
DWORD PTEI;
}ADDRESSSEGMENT;
//将目标线性地址开始的一个页,挂到源地址上上
typedef struct PageAttrib{
DWORD PTELOW;
DWORD PTEHIGH;
DWORD PDELOW;
DWORD PDEHIGH;
DWORD SrcAddress; //源地址线性地址
DWORD DestAddress; //目标线性地址
DWORD PDESrcAddress;
DWORD PTESrctAddress;
DWORD PDEDestAddress;
DWORD PTEDestAddress;
ADDRESSSEGMENT DestSeg;
ADDRESSSEGMENT SrcSeg;
}PAGEATTRIB;
PAGEATTRIB Page;
void InitAddress(){
Page.DestAddress=0x10000000;
Page.SrcAddress=0x0;
Page.DestSeg.PDPI =((Page.DestAddress&0xC0000000)>>30);
Page.DestSeg.PDEI =((Page.DestAddress&0x3FE00000)>>21); //0011 1111 1110
Page.DestSeg.PTEI =((Page.DestAddress&0x001FF000)>>12);
Page.SrcSeg.PDPI =((Page.SrcAddress&0xC0000000)>>30);
Page.SrcSeg.PDEI =((Page.SrcAddress&0x3FE00000)>>21);
Page.SrcSeg.PTEI =((Page.SrcAddress&0x001FF000)>>12);
Page.PDESrcAddress =0xC0600000+((Page.SrcAddress>>18)&0x3FF8);
Page.PTESrctAddress=0xC0000000+((Page.SrcAddress>>9)&0x7ffff8);
Page.PDEDestAddress=0xC0600000+((Page.DestAddress>>18)&0x3FF8);
Page.PTEDestAddress=0xC0000000+((Page.DestAddress>>9)&0x7ffff8);
}
void _declspec(naked) print(){
__asm{
pushad
pushfd
mov eax,dword ptr ds:[Page.PDEDestAddress]
mov ecx,dword ptr ds:[Page.PTEDestAddress]
mov ebx,[eax]
mov edx,[eax+4]
mov dword ptr ds:[Page.PDELOW],ebx
mov dword ptr ds:[Page.PDEHIGH],edx //获得目标 物理页 PDE
mov ebx,[ecx]
mov edx,[ecx+4]
mov dword ptr ds:[Page.PTELOW],ebx
mov dword ptr ds:[Page.PTEHIGH],edx
#if 0
mov eax,Page.PDELOW
mov ecx,Page.PDEHIGH
mov edx,Page.PDESrcAddress
mov dword ptr ds:[edx],eax
mov dword ptr ds:[edx+4],ecx
#endif
mov eax,Page.PTELOW
mov ecx,Page.PTEHIGH
mov edx,Page.PTESrctAddress
mov dword ptr ds:[edx],eax
mov dword ptr ds:[edx+4],ecx
popfd
popad
retf
}
}
int main(int argc, char* argv[])
{
char buf[6];
char* Addr=(char*)VirtualAlloc((void*)0x10000000,0x1000,MEM_RESERVE | MEM_COMMIT,PAGE_READWRITE);
if(NULL==Addr){
MessageBox(0,0,"开辟内存失败",0);
}
memset(Addr,0x66,0x1000);
*(WORD*)&buf[4]=0x48;
InitAddress();
printf("Address=%p\n",print);
__asm{
call fword ptr buf;
mov ax,0x3b
mov fs,ax
}
int* p=NULL;
*p=0x1231435;
printf("Hello World!\n");
return 0;
}