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. 找虚拟地址 怎么去找 `虚拟地址

Nginx 简单应用(Windows os)

实际问题如下: 我的电脑上有vm虚拟机,我有两个网络,一个叫137,一个叫102 ,我现在vm的网络是102的网络(137不允许被vm使用),但是别人都是137的网络,如何让137的局域网访问我的vm中的网站/应用 我的解决办法是使用Nginx来将vm中的102网络反向代理到宿主机上(137), 比

前端认识docker

Docker 是什么 先看看百科的定义: Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的镜像中,然后发布到任何流行的Linux或Windows操作系统的机器上,也可以实现虚拟化。容器是完全使用沙箱机制,相互之间不会有任何接口。 容器引擎?镜像?容器?虚拟化

7.1 实现进程内存块枚举

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

基于 Vagrant 手动部署多个 Redis Server

环境准备 宿主机环境:Windows 10 虚拟机环境:Vagrant + VirtualBox Vagrantfile 配置 首先,我们需要编写一个 Vagrantfile 来定义我们的虚拟机配置。假设已经在 D:\Vagrant\redis 目录下创建了一个 Vagrantfile,其内容如下:

一个与 WSL2 建立远程的简单方法

前言 众所周知,windows 会通过虚拟交换机给本机和 wsl2(Linux 子系统)分别分配 ip。于是本机重启或重启 wsl 服务的时候会重新分配 ip。之前所作的端口转发,监听之类的都会失效。 而如果你搜索 “如何固定 wsl 的 ip”,又会得到一系列复杂的配置方法。 且不说是否有用,但这

【Azure 环境】微软云上主机,服务的安全更新疑问

【问题一】微软云上的虚拟机,不论是Windows系统or Linux 系统,系统的安全补丁是由微软云平台 打上补丁进行修复,还是使用虚拟机的用户手动更新修复呢? 【答】这些补丁不会由平台来直接操作更新上去,而是由用户根据情况选择性安装修复。 【问题二】安全更新中提及的漏洞,是否会影响PaaS服务?

ARM下KVM虚拟化的损耗验证--redis

# ARM下KVM虚拟化的损耗验证 ## 摘要 ``` 看Windows 上面的 Workstation的虚拟机的 网络层的延迟特别高. 突然想之前统计都是直接在本地验证的, 只考虑了虚拟化CPU的性能损耗 没有考虑虚拟化层网络层的损耗. 所以想验证完了 Windows 和 intel平台 再抓紧验

windows下使用dockerdesktop进行部署

Docker部署springboot项目 环境准备 要在windows上使用docker需要确认系统的需求 需要启用虚拟化支持的CPU 启用适用于windows的Linux子系统功能 保证足够的内存 下载dockerdesktop 下载后会提示安装对应的环境 坑点 安装过程中需要安装wsl环境,会遇

使用虚拟机搭建代码托管、持续集成系统

目录 目录 摘要 下载镜像 安装系统 创建虚拟机 安装系统 检查网络 开启 SSH 远程登录功能 使用 windows powershell 连接终端 Windows Terminal 添加快速访问终端 端口映射 防火墙设置 外网访问 Tailscale 安装与使用 自建中继服务器 共享主机文件夹