Windows虚拟地址转物理地址(原理+源码实现,附简单小工具)
By Lthis
上个月就想写了,一直没时间...网上大概搜了一下,原理与操作倒是一大堆,一直没看到源码实现,总得有人动手,这回轮到我了。东西写得很烂,请大牛勿喷。一直觉得靠源码的方式驱动学习是非常好的一种学习方法,比较直观!声明一下,本教程只有讨论开启PAE与关闭PAE两种,至于PSE是否开启没有管...我的虚拟机默认PSE貌似是开启滴?不知是不是写的小工具有问题....对于x64下的等我有时间再写吧。
东西都上传在压缩包中了,Codes文件夹下是工程源码,Demo文件夹下是测试案例,Tool文件夹放的是小工具的Demo和源码。
我的环境:开发环境(win7 sp1 x64 + vs2013社区版 update5 + wdk8.1)
测试环境(vm10 + win7 sp1 x86)
一、先说说未开启PAE的情况,祭出intel手册的经典图例:
这幅图就是虚拟地址转为物理地址的原理图(4k页面),看图说话,用伪代码描述一下:
1.Directory Entry(PDE) = PDBR[Directory];
2.Page-Table Entry(PTE) = PDE + Table * 4;
3.Physical Address = PTE + Offset;
由上可知,Linear Address(线性地址)中的Directory和Table其实就是个索引,在未开启PAE的情况下,PDE、PTE均是32bit(4字节,所以要Table*4),以上只是原理上的描述,实际上,PDE、PTE的后3位是属性值,所以需要把后3位抹掉。
下边上关键代码,基本都步骤都写了注释了,有需要的可以封装成函数。此外,本段代码只是测试用,写的很不规范,比如,在调用MmMapIoSpace应该调用MmUnMapIoSpace释放内存。
// 得到ring3传入的虚拟地址size_t* pOutAddress = (size_t*)MmGetSystemAddressForMdlSafe(pIrp->MdlAddress, NormalPagePriority);VIRTUAL_ADDRESS virtualAddress = { 0 };virtualAddress.ulVirtualAddress = *pOutAddress;ULONG pdbr;_asm{mov eax, cr3;mov pdbr, eax;}PHYSICAL_ADDRESS phyAddress = { 0 };phyAddress.LowPart = pdbr;PULONG pPdbr = (PULONG)MmMapIoSpace(phyAddress, sizeof(PHYSICAL_ADDRESS), MmNonCached);KdPrint(("pdbr = 0x%08X, 映射后的地址0x%p\n", pdbr, pPdbr));// pPdbr[ulDirBaseIdx] 页目录项ULONG ulDirBaseIdx = virtualAddress.stVirtualAddress.dirBaseIndex;ULONG ulDirIdx = virtualAddress.stVirtualAddress.dirIndex;KdPrint(("第一级,已找到页目录所在项:pPdbr[%d]:0x%08X", ulDirBaseIdx,pPdbr[ulDirBaseIdx]));ULONG ulDir = pPdbr[ulDirBaseIdx] & 0xFFFFF000; // 抹去后3位得到真正的页目录项 ULONG ulDirPlus = ulDir + ulDirIdx * 4; // 页表项phyAddress.LowPart = ulDirPlus;PULONG pDirPlus = (PULONG)MmMapIoSpace(phyAddress, sizeof(PHYSICAL_ADDRESS), MmNonCached);KdPrint(("第二级,已找到页表项:ulDirPlus = 0x%08X, 映射后的地址0x%p\n", ulDirPlus, pDirPlus));ULONG ulPageTable = *pDirPlus & 0xFFFFF000; // 抹去后3位得到真正的页表项// 得到物理地址ULONG ulPhyAddress = ulPageTable + virtualAddress.stVirtualAddress.offset;// 映射为虚拟地址,获取其值进行验证phyAddress.LowPart = ulPhyAddress;PWCHAR pPhyAddress = (PWCHAR)MmMapIoSpace(phyAddress, sizeof(PHYSICAL_ADDRESS), MmNonCached);KdPrint(("虚拟地址:0x%08X, 对应物理地址:0x%08X, Value:%S\n", *pOutAddress, ulPhyAddress, pPhyAddress));// 传出对应物理地址*pOutAddress = ulPhyAddress;
二、开启PAE的情况
同样是4k页面的,伪代码描述如下:
1.Dir.Pointer Entry(PDPTE) = PDPTR[Directory Pointer];
2.Director Entry(PDE) = PDPTE + Directory * 0x8;
3.Page-Table Entry(PTE) = PDE + Table * 0x8;
4.Physical Address = PTE+Offset;
在开启PAE的情况下,PDE、PTE均是64bit(8字节,所以要*8),同样PDE、PTE的后3位是属性值,所以需要把后3位抹掉。
关键代码如下:
// 得到传入的ring3层虚拟地址size_t* pOutAddress = (size_t*)MmGetSystemAddressForMdlSafe(pIrp->MdlAddress, NormalPagePriority);VIRTUAL_ADDRESS virtualAddress = { 0 };virtualAddress.ulVirtualAddress = *pOutAddress;ULONG pdbr;// 得到页目录指针物理地址 _asm{mov eax, cr3;mov pdbr, eax;}// 映射为虚拟地址以便取值PHYSICAL_ADDRESS phyAddress = { 0 };phyAddress.LowPart = pdbr;PULONG pPdbr = (PULONG)MmMapIoSpace(phyAddress, sizeof(PHYSICAL_ADDRESS), MmNonCached);KdPrint(("pdbr = 0x%08X, 映射后的地址0x%p\n", pdbr, pPdbr));// 定位页目录指针表并获取页目录表物理页地址// ulDirAddress 为页目录表物理页地址ULONG ulPointerIdx = virtualAddress.stVirtualAddress.dirPointer;ULONG ulDirBaseAddress = pPdbr[ulPointerIdx];ulDirBaseAddress &= 0xFFFFF000; // 中间物理地址// 定位页表项ULONG ulDirAddress = ulDirBaseAddress + virtualAddress.stVirtualAddress.dirIndex * 0x8;phyAddress.LowPart = ulDirAddress;PULONG pPageTable = (PULONG)MmMapIoSpace(phyAddress, sizeof(PHYSICAL_ADDRESS), MmNonCached);ULONG ulPageTable = *pPageTable;ulPageTable &= 0xFFFFF000; // 中间物理地址// 定位物理页面ulPageTable += virtualAddress.stVirtualAddress.tableIndex * 0x8;phyAddress.LowPart = ulPageTable;PULONG pPageBase = (PULONG)MmMapIoSpace(phyAddress, sizeof(PHYSICAL_ADDRESS), MmNonCached);ULONG ulPageBase = *pPageBase;ulPageBase &= 0xFFFFF000;// 得到物理地址ULONG ulPhyAddress = ulPageBase + virtualAddress.stVirtualAddress.offset;// 映射为虚拟地址,获取其值进行验证phyAddress.LowPart = ulPhyAddress;PWCHAR pPhyAddress = (PWCHAR)MmMapIoSpace(phyAddress, sizeof(PHYSICAL_ADDRESS), MmNonCached);KdPrint(("虚拟地址:0x%08X, 对应物理地址:0x%08X, Value:%S\n", *pOutAddress, ulPhyAddress, pPhyAddress));// 传出对应物理地址*pOutAddress = ulPhyAddress;pIrp->IoStatus.Information = cout;
以上代码步骤是参考安于此生的文章写的,看不懂的可以先看看安于此生的文章《启用PAE后虚拟地址到物理地址的转换》
另附上小工具源码,该工具用于检测系统是否开启PAE、PSE等。
#define BUFFERSIZE 0x3000 char g_szMemInfo[BUFFERSIZE] = { 0 };// 以下code在 DriverEntry 中 DWORD dwPE = 0; // Protection Enable cr0[0]DWORD dwWP = 0; // Write Protect cr0[16]DWORD dwPG = 0; // Paging cr0[31]DWORD dwPAE = 0; // 物理地址扩展 cr4[5]DWORD dwPSE = 0; // Page Size Extension cr4[4]DWORD dwCr0 = 0;DWORD dwCr4 = 0;// 注册卸载函数pDriverObj->DriverUnload = driverUnload;_asm{pushad;mov eax, cr0;mov dwCr0, eax;// PE标志位and eax, 0x01;mov dwPE, eax;mov eax, cr0;// WP标志位and eax, 0x10000;mov dwWP, eax;mov eax, cr0;// PG标志位and eax, 0x80000000;mov dwPG, eax;// PAE//mov eax, cr4; 机器码如下_emit 0x0F;_emit 0x20;_emit 0xE0;mov dwCr4, eax;and eax, 0x20;mov dwPAE, eax;// PSE_emit 0x0F;_emit 0x20;_emit 0xE0;and eax, 0x10;mov dwPSE, eax;popad;}KdPrint(("PE = 0x%08X\r\n",dwPE));KdPrint(("WP = 0x%08X\r\n",dwWP));KdPrint(("PG = 0x%08X\r\n",dwPG));KdPrint(("PAE = 0x%08X\r\n",dwPAE));KdPrint(("PSE = 0x%08X\r\n",dwPSE));KdPrint(("Cr0 = 0x%08X\r\n",dwCr0));KdPrint(("Cr4 = 0x%08X\r\n",dwCr4));//----------------------------------------------------------------------------// PE标志位if (0 != dwPE){RtlStringCchCatNA(g_szMemInfo, BUFFERSIZE, "----------------------保护模式(PE=1)-------------------\r\n",BUFFERSIZE - sizeof("----------------------保护模式(PE=1)-------------------\r\n"));}else{RtlStringCchCatNA(g_szMemInfo,BUFFERSIZE ,"----------------------实地址模式(PE=0)-------------------\r\n",BUFFERSIZE - sizeof("----------------------实地址模式(PE=0)-------------------\r\n"));}//----------------------------------------------------------------------------// WP标志位if (0 != dwWP){RtlStringCchCatA(g_szMemInfo,BUFFERSIZE,"内存写保护(WP)开启...\r\n");}else{RtlStringCchCatA(g_szMemInfo,BUFFERSIZE,"内存写保护(WP)禁止...\r\n");}//----------------------------------------------------------------------------// PG标志位if (0 != dwPG){RtlStringCchCatA(g_szMemInfo,BUFFERSIZE,"页机制(PG)启用\r\n");}else{RtlStringCchCatA(g_szMemInfo,BUFFERSIZE,"页机制(PG)禁止\r\n");}//----------------------------------------------------------------------------// PAE标志位if (0 != dwPAE){RtlStringCchCatA(g_szMemInfo,BUFFERSIZE,"物理地址扩展(PAE)已开启\r\n");}else{RtlStringCchCatA(g_szMemInfo,BUFFERSIZE,"物理地址扩展(PAE)未启用\r\n");}//----------------------------------------------------------------------------// PSE标志位if (0 != dwPSE){RtlStringCchCatA(g_szMemInfo,BUFFERSIZE,"页面大小扩展(PSE)已开启\r\n");}else{RtlStringCchCatA(g_szMemInfo,BUFFERSIZE,"页面大小扩展(PSE)未启用\r\n");}KdPrint(("%s\r\n", g_szMemInfo));
最后,看看效果运行图。Demo是在ring3层定义一个Unicoe字符串:“Lthis”,然后将其虚拟地址传入ring0层,ring0解析后传出对应的物理地址。
开启PAE下运行的效果:
未开启PAE的运行效果:
附件地址:链接:http://pan.baidu.com/s/1kTENdnL 密码:g5j7
转载于:https://www.cnblogs.com/Lthis/p/4746795.html
Windows虚拟地址转物理地址(原理+源码实现,附简单小工具)相关推荐
- 企业网站源码PHP附企业小程序源码
时间不会为任何人停留,企业网站开发也不例外.随着时代的变化,趋势也在不断变化,品牌的数字化形象现在比以往任何时候都更加重要.重点已转向移动:但是,网站开发同样重要. 企业网站源码技术选型 演示:m.j ...
- 【小程序源码】检讨书生成微信小程序工具源码-安装搭建简单
对于经常写检讨的小伙伴来说,福音来了 因为这是一款检讨书生成小程序 所以再也不用为了写检讨而烦恼了哦 支持自定义字数下线,主题自定义 支持多种类型检讨比如:学生党的,男朋友,领导演讲稿,共青团申请书等 ...
- 【小程序源码】精美UI强大娱乐功能组合微信小程序源码下载,安装简单
这是一个多娱乐功能的小程序 具体由以下功能组合: 在线音乐 短视频去印 外卖CPS(外卖平台优惠劵) 打车CPS(打车平台优惠劵) 头像功能(多分类头像,另外还支持姓氏头像制作) 图片加水印 表情包功 ...
- windows C++ Opengl基础框架源码
windows C++ Opengl基础框架源码 项目开发环境 项目功能 项目演示 项目源码传送门 项目开发环境 开发语言:C++和IDE:VS2017,操作系统Windows版本windows SD ...
- java简单计算器课程设计_java仿windows简易计算器课程设计 源码+报告
[实例简介] java仿windows简易计算器课程设计 源码+报告 课直接运行. [实例截图] [核心代码] Java课设-简易计算器 └── Java课设-简易计算器 ├── Java课程设计.d ...
- k线顶分型 python_顶底分型-(K线分类及顶底分型的一种数学原理 源码 贴图)...
好股票软件下载网(www.goodgupiao.com)提示:您正在下载的是:顶底分型-(K线分类及顶底分型的一种数学原理 源码 贴图) 参考缠论,研究了很多天终于将顶底分型进行了具体的数学量化,涵盖 ...
- Unity Fog 原理 源码分析 案例
Unity Fog 原理 源码分析 案例 效果图 简述 背景知识 clip空间坐标的范围 d3d (near,0), unity remapping to (0,far) 越靠近相机z值越小 open ...
- android 2.2下载地址,Windows下载android2.2完整源码
前两天看到有人给我留言,才发现很久没写过东西了.不过,最近也没做什么东西.下载了一个cygwin,在Windows下载android完整代码. 这个项目的名字来源于:GNU.Cygnus.Window ...
- Windows 12 网页版HTML源码
资源简介 安装和使用 下载代码,无需安装,打开start.html即可 功能可以自行增加或者二开等等 [在线预览] https://tjy-gitnub.github.io/win12/start.h ...
最新文章
- mysql where关键字_MySQL WHERE 子句
- 网管应当如何管理Windows操作系统
- 网站分析数据收集方式详解
- TFS 2015 敏捷开发实践 – 看板的使用
- 第一次听人用男女关系讲 N(Non-Blocking)I(进)O(出),涨姿势了
- tf.train.exponential_decay
- 软件项目管理0724:见供应商的体会
- Remastersys制作自己的Linux发行版
- 5G 时代,AI 如何破竹而出? | AI ProCon
- 化学人学python有前途吗-转载:python之蟒开启理论计算化学的新时代
- pythonwin1064位_在Windows 10 64位中安装Matplotlib
- 765. 情侣牵手--(每日一难phase2--day14)
- NRF24L01模块的2个注意点
- paypal快速支付流程图
- 666RPG(计数dp)
- easyui datagrid deleteRow(删除行)的BUG或者updateRow值更新了不展示问题
- 手机备忘录里的照片怎么保存到相册里
- 中小型企业开发门户网站我建议你选择阿里云的云速美站
- 2018年android常用的框架介绍
- 淘宝店铺如何做补单计划?
热门文章
- php简单分页,php简单实现分页查询的方法
- mysql blob取值_MySQL 数据类型:
- pymol怎么做底物口袋表面_怎么从文献中发掘一篇新文章?
- dart服务器开发性能,DartVM服务器开发(第四天)--代码优化
- python中下划线开头的命名_Python 中各种下划线的骚操作:_、_xx、xx_、__xx、__xx__、_classname_...
- arm板telnetd为什么运行不了_一种基于ARM的嵌入式系统开发的方案详细讲解
- 8086标志寄存器FLAG
- 8086除法指令DIV,IDIV
- css中的媒体查询_CSS中的媒体查询
- dbms支持哪几种数据模型_DBMS中不同类型的数据模型