Windows 虛擬地址 到底是如何映射到 物理地址 的?

来源:https://www.cnblogs.com/huangxincheng/archive/2023/08/25/17656346.html
-Advertisement-
Play Games

## 一:背景 ### 1. 講故事 我發現有很多的 .NET程式員 寫了很多年的代碼都沒弄清楚什麼是 `虛擬地址`,更不用談什麼是 `物理地址` 以及Windows是如何實現地址映射的了?這一篇我們就來聊一聊這兩者之間的聯繫。 ## 二:地址映射研究 ### 1. 找虛擬地址 怎麼去找 `虛擬地址 ...


一:背景

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在手,天下我有!

圖片名稱
您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • # if if if 判斷 和 if elif elif 判斷有什麼區別 ## 在Python中,if語句和if-elif-else語句都用於條件控制,但它們在處理條件和執行邏輯上有一些區別。 ### if語句:if語句用於執行一系列條件之一的代碼塊。 - 你可以使用多個if語句來檢查多個條件,但每 ...
  • 之前給大家推薦了很多後臺模版,有讀者希望推薦一些跟通用的好看組件,畢竟出了後臺還有很多其他場景嘛。所以,今天繼續給大家推薦一個廣受好評的UI組件庫:[**NextUI**](https://blog.didispace.com/tj-opensource-nextui/) ![NextUI](htt ...
  • 來源:https://heapdump.cn/article/1859160 通過這一個多月的努力,將 FullGC 從 40 次/天優化到近 10 天才觸發一次,而且 YoungGC 的時間也減少了一半以上,這麼大的優化,有必要記錄一下中間的調優過程。 對於 JVM 垃圾回收,之前一直都是處於理論 ...
  • ## 教程簡介 AOP為Aspect Oriented Programming的縮寫,意為:面向切麵編程,通過預編譯方式和運行期間動態代理實現程式功能的統一維護的一種技術。AOP是OOP的延續,是軟體開發中的一個熱點,也是Spring框架中的一個重要內容,是函數式編程的一種衍生範型。利用AOP可以對 ...
  • 上一篇介紹了`DataFrame`的顯示參數,主要是對`DataFrame`中值進行調整。 本篇介紹`DataFrame`的顯示樣式的調整,顯示樣式主要是對錶格本身的調整,比如顏色,通過顏色可以突出顯示重要的值,觀察數據時可以更加高效的獲取主要信息。 下麵介紹一些針對單個數據和批量數據的樣式調整方式 ...
  • 在Java語言中,創建線程並不像創建對象一樣簡單。雖然只需要使用new Thread()即可創建線程,但實際上創建線程比創建對象複雜得多。創建對象只需在JVM的堆中分配記憶體,而創建線程需要調用操作系統內核的API,併為線程分配一系列資源,這個成本相對較高。因此,線程被視為重量級的對象,應儘量避免頻繁... ...
  • 最近閱讀了《ASP.NET Core 技術內幕與項目實戰——基於DDD與前後端分離》(作者楊中科)的第八章,對於Core入門的我來說體會頗深,整理相關筆記。 JWT:全稱“JSON web toke”,目前流行的跨域身份驗證解決方案; 標識框架(identity):由ASP.NET Core提供的框 ...
  • 在項目中經常會遇到類似如下要求的需求,創建允許自由拖動的控制項,這樣的需求可以使用WPF的裝飾器Adorner來實現。 一、什麼是裝飾器? 裝飾器是一種特殊類型的FrameworkElement,裝飾器始終呈現在被裝飾元素的頂部,用於向用戶提供可視化提示。裝飾器可以在不改變原有控制項結構的基礎上,將功能 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...