Windows 虚拟地址 到底是如何映射到 物理地址 的?

windows,虚拟地址,到底,如何,映射,物理地址 · 浏览次数 : 857

小编点评

1: kd> !process 0 notepad.exePROCESS ffffe0011f9c9840 SessionId: 1 Cid: 11a8 Peb: 7ff63d8ff000 ParentCid: 0bf4 DirBase: 23c6d000 ObjectTable: ffffc00088bdcbc0 HandleCount: <Data Not Accessible> Image: notepad.exe1: kd> r cr3cr3=0000000023c6d0001: kd> !dp 23c6d000 + (0y011111111*8) L1#23c6d7f8 00900000`0b9108671: kd> !dp 0b910000 + (0y111100000*8) L1# b910f80 00f00000`1fa518671: kd> !dp 1fa51000+(0y111100000*8) L1#1fa51f00 81000000`0ad38025从卦中可以看到,四个地址和pfn都是对的,最后 pfn+页内偏移 = ad38050 ,也就是我们苦苦寻找的 物理地址,再次输出一下结果。1: kd> !dB ad38050 L30# ad38050 69 73 20 70 72 6f 67 72-61 6d 20 63 61 6e 6e 6f is program canno# ad38060 74 20 62 65 2e 0d 0d 0a-24 00 00 00 00 00 00 mode....$.......三:总结手工推算是不是非常有趣,可以让我们更加的理解Windows底层玩法,WinDbg在手,天下我有!

正文

一:背景

1. 讲故事

我发现有很多的 .NET程序员 写了很多年的代码都没弄清楚什么是 虚拟地址,更不用谈什么是 物理地址 以及Windows是如何实现地址映射的了?这一篇我们就来聊一聊这两者之间的联系。

二:地址映射研究

1. 找虚拟地址

怎么去找 虚拟地址 呢?相信很多朋友都知道应用程序用的是虚拟地址,所以从应用程序中取一个就好了,这里就拿 notepad 举例子吧。

开启一个装有 win10 的虚拟机,然后打开 notepad.exe,使用 windbg 进行它的内核态调式,参考代码如下:


0: kd> !process 0 0 notepad.exe
PROCESS ffffe0011f9c9840
    SessionId: 1  Cid: 11a8    Peb: 7ff63d8ff000  ParentCid: 0bf4
    DirBase: 23c6d000  ObjectTable: ffffc00088bdcbc0  HandleCount: <Data Not Accessible>
    Image: notepad.exe

0: kd> .process /i /p ffffe0011f9c9840
You need to continue execution (press 'g' <enter>) for the context
to be switched. When the debugger breaks in again, you will be in
the new process context.

0: kd> g
Break instruction exception - code 80000003 (first chance)
nt!DbgBreakPointWithStatus:
fffff801`bed59c50 cc              int     3

1: kd> .reload /user
Loading User Symbols
....................................

Press ctrl-c (cdb, kd, ntsd) or ctrl-break (windbg) to abort symbol loads that take too long.
Run !sym noisy before .reload to track down problems loading symbols.

......

1: kd> lm
start             end                 module name
00007ff6`3e1e0000 00007ff6`3e21a000   notepad    (deferred)             
00007ff9`83e60000 00007ff9`83fac000   UIAutomationCore   (deferred)             
...

1: kd> dB 00007ff6`3e1e0000+0x50 L30
00007ff6`3e1e0050  69 73 20 70 72 6f 67 72-61 6d 20 63 61 6e 6e 6f  is program canno
00007ff6`3e1e0060  74 20 62 65 20 72 75 6e-20 69 6e 20 44 4f 53 20  t be run in DOS 
00007ff6`3e1e0070  6d 6f 64 65 2e 0d 0d 0a-24 00 00 00 00 00 00 00  mode....$.......

从卦中可以看到 00007ff63e1e0050 处是一段字符串,接下来我们就以它为例吧。

2. 如何用 Windbg 推算

到底是如何映射的呢?如果你了解 Windows 的源码可能你就很清楚,不了解也没关系,我们可以用 WinDbg 帮我们计算,在 windbg 中有一个 !vtop 命令可以一键查找,输出如下:


1: kd> !vtop 0 00007ff63e1e0050
Amd64VtoP: Virt 00007ff63e1e0050, pagedir 0000000023c6d000
Amd64VtoP: PML4E 0000000023c6d7f8
Amd64VtoP: PDPE 000000002360aec0
Amd64VtoP: PDE 000000000b910f80
Amd64VtoP: PTE 000000001fa51f00
Amd64VtoP: Mapped phys 000000000ad38050
Virtual address 7ff63e1e0050 translates to physical address ad38050.

1: kd> !dB ad38050 L30
# ad38050 69 73 20 70 72 6f 67 72-61 6d 20 63 61 6e 6e 6f is program canno
# ad38060 74 20 62 65 20 72 75 6e-20 69 6e 20 44 4f 53 20 t be run in DOS 
# ad38070 6d 6f 64 65 2e 0d 0d 0a-24 00 00 00 00 00 00 00 mode....$.......

从卦中可以清晰的看到,虚拟地址 00007ff63e1e0050 所对应的物理地址为 ad38050,然后用 !dB 去观察物理地址也确实如此。

这里要提醒一下,如果你还想知道这个物理地址所属的 PDE (页目录项)PTE (页表项) ,可以用 !pte 命令帮我们一键显示,输出如下:


1: kd> !pte 00007ff63e1e0050
                                           VA 00007ff63e1e0050
PXE at FFFFF6FB7DBED7F8    PPE at FFFFF6FB7DAFFEC0    PDE at FFFFF6FB5FFD8F80    PTE at FFFFF6BFFB1F0F00
contains 009000002360A867  contains 00E000000B910867  contains 00F000001FA51867  contains 810000000AD38025
pfn 2360a     ---DA--UWEV  pfn b910      ---DA--UWEV  pfn 1fa51     ---DA--UWEV  pfn ad38      ----A--UR-V

从卦中可以看到,x64的地址有四级结构,不仅有 PDE,PTE,还有 PXE, PPE,并且从 pfn ad38 可以清楚的看到它的物理页号是 ad38,加上虚拟地址后的 12bit(050) 偏移,最后的物理地址也就是 ad38050

用 WinDbg 推算虽然简单,但不利于我们了解原理,为了加深理解,我们需要手工的去推算。

3. 如何手工推算

要明白手工推算,在脑子中一定要有一张架构图,有了这张架构图就方便行事了。

卦图中有几点要解释。

  1. 二进制怎么出来的?

可以用 windbg 的 .formats 命令。


1: kd> .formats 00007ff63e1e0050
Evaluate expression:
  Hex:     00007ff6`3e1e0050
  Decimal: 140695580835920
  Binary:  00000000 00000000 01111111 11110110 00111110 00011110 00000000 01010000

  1. CR3 是什么?

CR3 是Windows的控制寄存器,它记录着这个进程所属的虚拟地址首地址,专业点就是 BaseDir (基目录) 地址,参考如下输出:


1: kd> !process 0 0 notepad.exe
PROCESS ffffe0011f9c9840
    SessionId: 1  Cid: 11a8    Peb: 7ff63d8ff000  ParentCid: 0bf4
    DirBase: 23c6d000  ObjectTable: ffffc00088bdcbc0  HandleCount: <Data Not Accessible>
    Image: notepad.exe

  1. 各级页表占用多少bit位数?
  • PXE 占用 9bit(39-47)
  • PPE 占用 9bit(30-38)
  • PDE 占用 9bit(21-29)
  • PTE 占用 9bit(12-20)

有了这些信息之后,最后就是手工推算了,这里要提醒一下,每个表的首地址都把后 12bit 抹为0,因为他们是表的meta信息,详细输出如下:


1: kd> !process 0 0 notepad.exe
PROCESS ffffe0011f9c9840
    SessionId: 1  Cid: 11a8    Peb: 7ff63d8ff000  ParentCid: 0bf4
    DirBase: 23c6d000  ObjectTable: ffffc00088bdcbc0  HandleCount: <Data Not Accessible>
    Image: notepad.exe

1: kd> r cr3
cr3=0000000023c6d000

1: kd> !dp 23c6d000 + (0y011111111*8) L1
#23c6d7f8 00900000`2360a867

1: kd> !dp 2360a000+(0y111011000*8) L1
#2360aec0 00e00000`0b910867

1: kd> !dp 0b910000 + (0y111110000*8) L1

# b910f80 00f00000`1fa51867

1: kd> !dp 1fa51000+(0y111100000*8) L1
#1fa51f00 81000000`0ad38025

从卦中可以看到最后推算出来的是 810000000ad38025 ,抹掉 高32bit 和 末 12bit 之后就变成了 ad38,这个就是我们的 pfn (页帧号) ,如果你想核算一下 !dp 出来的值对不对,可以看下 !pte 命令中的 contains xxx 是不是这个值? 输出如下:


1: kd> !pte 00007ff63e1e0050
                                           VA 00007ff63e1e0050
PXE at FFFFF6FB7DBED7F8    PPE at FFFFF6FB7DAFFEC0    PDE at FFFFF6FB5FFD8F80    PTE at FFFFF6BFFB1F0F00
contains 009000002360A867  contains 00E000000B910867  contains 00F000001FA51867  contains 810000000AD38025
pfn 2360a     ---DA--UWEV  pfn b910      ---DA--UWEV  pfn 1fa51     ---DA--UWEV  pfn ad38      ----A--UR-V

从卦中可以看到,四个地址和pfn都是对的,最后 pfn+页内偏移 = ad38050 ,也就是我们苦苦寻找的 物理地址,再次输出一下结果。


1: kd> !dB ad38050 L30
# ad38050 69 73 20 70 72 6f 67 72-61 6d 20 63 61 6e 6e 6f is program canno
# ad38060 74 20 62 65 20 72 75 6e-20 69 6e 20 44 4f 53 20 t be run in DOS 
# ad38070 6d 6f 64 65 2e 0d 0d 0a-24 00 00 00 00 00 00 00 mode....$.......

三:总结

手工推算是不是非常的有意思,可以让我们更加的理解Windows底层玩法,WinDbg在手,天下我有!

图片名称

与Windows 虚拟地址 到底是如何映射到 物理地址 的?相似的内容:

Windows 虚拟地址 到底是如何映射到 物理地址 的?

## 一:背景 ### 1. 讲故事 我发现有很多的 .NET程序员 写了很多年的代码都没弄清楚什么是 `虚拟地址`,更不用谈什么是 `物理地址` 以及Windows是如何实现地址映射的了?这一篇我们就来聊一聊这两者之间的联系。 ## 二:地址映射研究 ### 1. 找虚拟地址 怎么去找 `虚拟地址

7.1 实现进程内存块枚举

在`Windows`操作系统中,每个进程的虚拟地址空间都被划分为若干内存块,每个内存块都具有一些属性,如内存大小、保护模式、类型等。这些属性可以通过`VirtualQueryEx`函数查询得到。该函数可用于查询进程虚拟地址空间中的内存信息的函数。它的作用类似于`Windows`操作系统中的`Task...

windows 安装postgresql 14

开源数据库 PostgreSQL 是 1980 年以加利福尼亚大学为中心开发出来的 DBMS,与 MySQL 一样,都是世界上广泛应用的开源数据库(DB)。本文将会介绍使用 64 位版的 Windows 安装程序(Win x86-64)在 Windows Server 2019(64 位)系统中安装

Windows Server上部署IoTDB 集群

本文是参考官方的 IoTDB 集群版(1.0.0)的安装及启动教程:https://iotdb.apache.org/zh/UserGuide/V1.0.x/Cluster/Cluster-Setup.html ,在Windows Server 2019上部署集群的实践记录。前置检查使用微软发布的O

在windows系统中设置MySQL数据库

> 博客地址:https://www.cnblogs.com/zylyehuo/ # MySQL搭建 ## 效果图 * ![](https://img2023.cnblogs.com/blog/3071480/202303/3071480-20230325161021159-839132685.pn

Windows 终端远程连接 Ubuntu

博客地址:https://www.cnblogs.com/zylyehuo/ 查看 ip 的方式参考以下链接 Ubuntu 下查看 ip - zylyehuo - 博客园 在 windows 终端中执行以下命令 ssh <用户名>@ # 示例如下 ssh root@127.0.0.1

windows 10 家庭版安装Docker和portainer汉化版

前景提要 这个笔记本是华为的Matebook14,本着原装系统比较稳定的原则,没有对其进行个人安装操作系统,但是对系统进行了升级,升级成了企业版,但是,目前看来内核还是原来的家庭版,这个安装起windows十分的费劲. 安装最新版的Docker需要wsl 2 ,按照百度到的方式,每次都会显示操作成功

2023年windows DockerDeskTop最新款4.18.0 全程保姆级安装

前景提示 想在windows10上安装一个docker容器的desktop版本,但是,总是安装wsl不好使,同时,windows store没有了,用命令行安装的linux系统无法启动,也无法连接,之前想到的方案是安装旧的版本,然后,快速关闭wsl的验证功能,勉强可以跑起来,但是,存在大量问题和功能

Windows电脑环境变量(用户变量、系统变量)的修改

本文介绍在Windows 10操作系统中,进行用户变量、系统变量等两种环境变量的新建、修改与删除的详细方法~

[转帖]Windows Server 2022 简体中文版、英文版下载 (updated Oct 2022)

https://sysin.org/blog/windows-server-2022/ Windows Server 2022 正式版,2022 年 10 月更新,VLSC Posted by sysin on 2022-10-27 Estimated Reading Time 8 Minutes