Paging – Virtual to Physical address translation via WinDbg

本文详细介绍了在PAE模式下如何进行虚拟地址到物理地址的转换,包括手动过程及使用Windbg工具简化这一过程的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

转自:http://blog.nandaka.io/paging-virtual-to-physical-address-translation-via-windbg/

PAE/Non-PAE参考:

Paging – Virtual to Physical address translation
Paging in PAE-mode – Virtual to Physical Address Translation

We have covered the address translation for PAE and non-PAE mode in x86 in previous articles. In this article we will see the address translation in action. We will first do it manually and then learn ‘!pte’ command in WinDbg which will dump the PDE and PTE for us without much of effort.

I am using Win7 x86 VM and PAE mode is by default enabled so we will go through the 3 levels of translations.

It is strongly recommended that you go through the previous articles on address translation before continuing further.

 

Figure below will help you recall how the virtual address is divided in PAE mode.

clip_image001

 

Here is the memory address translation process in PAE mode:

clip_image002

Image taken from the book, Windows Internals by M Russinovich, D A Solomon, A Ionescu.

Each PTE\PDE entry is 64 bit wide and PFN bits that are used to locate the base of physical page are 24 bits as compared to 20 bits in 32 bit PTE\PDE.

clip_image003

 

Let’s start with the translation. We know that in PAE mode, CR3 CPU register holds the base address of Page Directory Pointer Table(PDPT). Each process running on Windows has its own Directory Base(DirBase) which stores the physical address of PDPT. CR3 CPU register is loaded with this DirBase whenever a context switch happens for the thread which belong to a process different than the current running thread. You can dump the DirectoryTableBase with the following WinDbg command:

 

1: kd> !process 0 0 explorer.exe

PROCESS 84d59030  SessionId: 1  Cid: 045c    Peb: 7ffd5000  ParentCid: 00f0

    DirBase: 3ec331a0  ObjectTable: 8ce0eb20  HandleCount: 641.

    Image: explorer.exe

 

0: kd> dt nt!_KPROCESS 84d59030   -y dir

   +0x018 DirectoryTableBase : 0x3ec331a0

 

Let’s dump CR3 register.

 

0: kd> r cr3

cr3=00185000

 

I just mentioned that DirBase would be same as CR3 register however it is showing different value. The problem is that you are not in context of the process. This is a very common mistake so please make sure you are in the context of the process in WinDbg before you check CR3.

 

1: kd> .process /i 84d59030 

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.

 

1: kd> g

Break instruction exception – code 80000003 (first chance)

nt!RtlpBreakWithStatusInstruction:

8266b394 cc              int     3

 

Now we are in the context of the process ‘explorer.exe’. If you dump CR3 CPU register now you will see the DirBase in CR3.

0: kd> r cr3

cr3=3ec331a0

 

Let’s pick a virtual address to do the translation, say process address itself i.e. 84d59030 

 

84d59030  ——> 10 000100110 101011001 000000110000

 

PDPT Index                                                                   10 = 2

PDT Index                                                                     000100110 = 38 or 0x26

PT Index                                                                        101011001 = 345 or 0x159

Byte Index                                                                    000000110000 = 48 or 0x30

 

CR3 CPU register or DirBase contains the physical address of base of PDPT. There are 4 possible entries in PDPT and virtual address PDPT index is 2. You can dump the physical memory via ‘!d’ WinDbg command as shown below.

 

Let’s dump the PDPT:

0: kd> !dq 3ec331a0 l4

#3ec331a0 00000000`10df0801 00000000`11271801

#3ec331b0 00000000`10e32801 00000000`11173801

 

 

Or you can directly dump the index 2 of PDPT as follow:

0: kd> !dq 3ec331a0 + (2*8) l1

#3ec331b0 00000000`10e32801

 

PDPT Entry  contains  00000000`10e32801

 

Revisit the format of the PDE\PTE in PAE mode. First 12 bits are for various flags and next 24 bits are for PFN. Highlighted in Green is the PFN part of the PDPT Entry in PAE mode.

 

PFN of PDT base is  0`10e32 (24 bits in PAE mode).

 

Physical address of PDT base is 10e32000 (appended by 12 bits)

 

First level of table (PDPT) is translated and we have the base of PDT. Let’s move to the PDE of the virtual address 84d59030.

 

PDT Index from virtual address is decimal 38 or hex 26.

0: kd> ?10e32000+(26*8)

Evaluate expression: 283320624 = 10e32130

 

0: kd> !dq 10e32130 l1

#10e32130 00000000`3fec7863

 

PDE contains 00000000`3fec7863

 

Extract the PFN part:

PFN of base of Page Table(PT) is 3fec7 (24 bit in PAE Mode)

 

Physical address of PT base is 03fec7000 (appended by 12 bits)

 

0: kd> ?03fec7000+(0x159*8)

Evaluate expression: 1072462536 = 3fec7ac8

 

0: kd> !dq 3fec7ac8 l1

#3fec7ac8 00000000`3ef59963

 

PTE contains 00000000`3ef59963

 

PFN of the page where the virtual address resides is 03ef59

 

Base of the page is 03ef59000 (appended by 12 bits)

 

DWORD referred by the virtual address resides at the hex 30 byte offset:

 

0: kd> ?03ef59000+30

Evaluate expression: 1056280624 = 3ef59030

 

0: kd> !dd 3ef59030 l1

#3ef59030 00260003

 

Dump the content of the virtual memory by ‘dd’ command.

0: kd> dd 84d59030 l1

84d59030  00260003

 

Above translation can be easily done via ‘!pte’ WinDbg command as shown below.

 

0: kd> !pte 84d59030 

                    VA 84d59030

PDE at C0602130                           PTE at C0426AC8

contains 000000003FEC7863      contains 000000003EF59963

pfn 3fec7     —DA–KWEV             pfn 3ef59     -G-DA–KWEV

 

 

Or

 

clip_image004

Debugger does not show the PDPT in the output of ‘!pte’ Command but I have dumped it manually during the translation. Flags corresponds to the PDE\PTE flags mentioned above. Physical page where the virtual address points to is given by the PFN of PTE as shown above

 

 

In x64, it is no different except, additional levels of translation. Here is 64 bit PDE\PTE entry and translation process:

clip_image005

 

clip_image006

Image taken from the book, Windows Internals by M Russinovich, D A Solomon, A Ionescu.

 

PROCESS ffffe000ac169080

    SessionId: 1  Cid: 0228    Peb: f7a9cd5000  ParentCid: 01d4

    DirBase: 2ecbd000  ObjectTable: ffffc00134a5b7c0  HandleCount: <Data Not Accessible>

    Image: winlogon.exe

 

0: kd> r cr3

cr3=000000002ecbd000

 

Note: Make sure you are in the context of the process

 

Here is the output of ‘!pte’ command for 64 bit OS. I have taken the process address for translation. The offset in page is 80 highlighted in green.

0: kd> !pte ffffe000ac169080

                                              VA ffffe000ac169080

PXE at FFFFF6FB7DBEDE00    PPE at FFFFF6FB7DBC0010    PDE at FFFFF6FB78002B00    PTE at FFFFF6F000560B48

contains 0000000000532863  contains 0000000000331863  contains 0000000034BD9863  contains 8000000030342963

pfn 532       —DA–KWEV  pfn 331       —DA–KWEV  pfn 34bd9     —DA–KWEV  pfn 30342     -G-DA–KW-V

 

Or

clip_image007

 

The base address of the physical page is 30342000 and offset in 4K page is 080. Let’s first get the content via virtual address ffffe000ac169080.

 

0: kd> dq ffffe000ac169080 l1

ffffe000`ac169080  00000000`00b60003

 

Let’s do it via physical address obtained from PTE above and add offset hex 80 to it.

0: kd> !dq 30342000+80 l1

   #30342080 00000000`00b60003

 

 

Alright, so we have covered the address translation successfully. You can follow the manual process on x64 as well but just make sure that you are in the context of the process for which you are translating the virtual address and take caution while using hex and decimal number conversion.







### 解决方案概述 当遇到 `Unable to handle kernel paging request at virtual address` 错误时,这通常意味着内核尝试访问一个无效或未映射的虚拟地址。此类错误可能是由多种原因引起的,包括但不限于硬件故障、驱动程序问题、内存管理单元(MMU)配置不当以及不正确的内存操作。 #### 原因分析与排查方法 1. **检查日志信息** 日志中的具体地址可以帮助进一步诊断问题所在。如果该地址看起来异常(例如全零或非常大的数值),则可能是由于指针为空或其他编程错误引起[^1]。 2. **验证模块加载过程** 如果是在插入新模块(`insmod`)期间发生的此错误,则需仔细审查模块初始化代码,确保所有资源正确分配并初始化完毕再进行实际工作[^3]。 3. **确认数据对齐情况** 对于某些架构(如ARM),特定指令要求其操作数按一定边界对齐;违反这些规定可能会触发上述类型的页面错误。因此,在编写涉及直接硬件交互的底层代码时要特别注意这一点[^4]。 4. **利用调试工具辅助定位** 使用GDB等调试器可以更精确地找到引发崩溃的具体函数调用链路及其上下文环境。此外还可以借助`addr2line`命令将堆栈跟踪转换成对应的源文件路径及行号以便快速查阅相关实现细节[^2]。 ```bash # 示例:使用 GDB 调试内核 $ gdb vmlinux /proc/kcore (gdb) bt full # 获取完整的回溯信息 (gdb) info registers # 查看寄存器状态 ``` 5. **启用更多调试选项** 编译Linux内核时可以选择开启更多的调试特性来收集额外的信息用于后续分析。特别是对于难以重现的问题而言,详细的运行时记录往往能提供宝贵线索。 ```makefile CONFIG_DEBUG_KERNEL=y CONFIG_KALLSYMS_ALL=y CONFIG_PRINTK_TIME=y ``` 6. **更新固件和软件版本** 确认所使用的操作系统镜像及相关组件均为最新稳定版,因为旧版本可能存在已知漏洞或是与其他部分存在兼容性冲突的情况。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值