【问题标题】:Windows 10 x64: Unable to get PXE on WindbgWindows 10 x64:无法在 Windbg 上获取 PXE
【发布时间】:2019-03-29 01:11:39
【问题描述】:

无法理解 Windows 内存管理器的工作原理。 我查看了附加的用户进程 (dbgview.exe)。 它是 WOW64 进程。在指定的地址 (0x76560000) 有 .text 模块的 kernel32.dll 部分(也是 WOW64)。 为什么进程页表中没有PTE等表指向那些虚拟地址?

kd> db 76560000
00000000`76560000  8b ff 55 8b ec 51 56 57-33 f6 89 55 fc 56 68 80  ..U..QVW3..U.Vh.
<...>

kd> !pte 76560000
                                           VA 0000000076560000
PXE at FFFFF6FB7DBED000    PPE at FFFFF6FB7DA00008    PDE at FFFFF6FB40001D90    PTE at FFFFF680003B2B00
Unable to get PXE FFFFF6FB7DBED000

kd> db FFFFF680003B2B00 
fffff680`003b2b00  ?? ?? ?? ?? ?? ?? ?? ??-?? ?? ?? ?? ?? ?? ?? ?? ???????????????
<...>

我知道在第一次访问(有页面错误)发生后会分配页面,但是为什么没有原型 PTE 呢?

【问题讨论】:

    标签: windows debugging winapi memory-management windbg


    【解决方案1】:

    首先,将任意虚拟地址转换为物理地址,使用!vtop查看正在转换的进程的dirbase,或者使用!process查找进程的dirbase

    lkd> .process /p fffffa8046a2e5f0
    Implicit process is now fffffa80`46a2e5f0
    lkd> .context 77fa90000
    lkd> !vtop 0 13fe60000
    Amd64VtoP: Virt 00000001`3fe60000, pagedir 7`7fa90000
    Amd64VtoP: PML4E 7`7fa90000
    Amd64VtoP: PDPE 1`c2e83020
    Amd64VtoP: PDE 7`84e04ff8
    Amd64VtoP: PTE 4`be585300
    Amd64VtoP: Mapped phys 6`3efae000
    Virtual address 13fe60000 translates to physical address 63efae000.
    

    然后在 PFN 数据库中找到该物理帧(在这种情况下,PML4 的物理页面(cr3 page aka.dirbase)是77fa90,完整的物理地址为77fa90000

    lkd> !pfn 77fa90
        PFN 0077FA90 at address FFFFFA80167EFB00
        flink       FFFFFA8046A2E5F0  blink / share count 00000005  pteaddress FFFFF6FB7DBEDF68
        reference count 0001    used entry count  0000      Cached    color 0   Priority 0
        restore pte 00000080  containing page        77FA90  Active     M
        Modified
    

    因此地址FFFFF6FB7DBED000 是PML4 页面的虚拟地址,FFFFF6FB7DBEDF68 是PML4E 自引用条目的虚拟地址(1ed*8 = f68)。

    FFFFF6FB7DBED000 = 1111111111111111111101101111101101111101101111101101000000000000

    1111111111111111 111101101 111101101 111101101 111101101 000000000000

    PML4 只能位于 PML4E、PDTPE、PDE 和 PTE 索引相同的虚拟地址,因此实际上存在 2^9 的不同组合,Windows 7 始终选择 0x1ed111101101。这样做的原因是因为 PML4 包含一个指向自身的 PML4,即 PML4 的物理框架,因此它需要在层次结构的每个级别上保持对同一位置的索引。

    PML4作为页表页,必须驻留在内核中,内核地址是高规范的,即以1111111111111111为前缀,内核地址以00001开头到11111即从08开始给ff

    因此,使用 8TiB 作为用户地址空间的 64 位操作系统可以放置的可能地址范围是 31*(2^4) = 496 个不同的可能位置,而不是实际上 2^9

    1111111111111111 000010000 000010000 000010000 000010000 000000000000

    1111111111111111 111111111 111111111 111111111 111111111 000000000000

    即第一个是FFFF080402010000,第二个是FFFF088442211000,最后一个是FFFFFFFFFFFFF000

    Note:

    在 Windows 10 TH2 之前,Self-Reference PML4 条目的神奇索引是0x1ed,如上所述。但是从 1607 开始的 Windows 10 呢?好吧,微软升级了他们的游戏,作为提高 Windows 安全性的持续战斗,索引在启动时是随机的,所以0x1ed 现在是 512 [原文如此。 (496)] 自引用条目索引可以具有的可能值(即 9 位索引)。还有副作用,它还破坏了一些自己的工具,比如!pte2vaWinDbg 命令。

    0xFFFFF68000000000 是第一个页表页中第一个 PTE 的地址,所以基本上是 MmPteBase,除了因为在 Windows 10 1607 上 PML4E 可以是 0x1ed 以外的其他地址,基并不总是 @987654359 @ 作为结果,它使用变量nt!MmPteBase 立即知道页表页面分配的基础从哪里开始。以前,ntoskrnl.exe 中不存在此符号,因为它有一个硬编码的基址 0xFFFFF68000000000。第一个和最后一个页表页的地址是:

                            first   last
     *   pml4e_offset     : 0x1ed   0x1ed
     *   pdpe_offset      : 0x000   0x1ff
     *   pde_offset       : 0x000   0x1ff
     *   pte_offset       : 0x000   0x1ff
     *   offset           : 0x000   0x000
    

    当 PML4E 索引为 0x1ed 时,这为第一个页表页提供 0xFFFFF68000000000,为最后一个页表页提供 0xFFFFF6FFFFFFF000。 PDEs + PDPTEs + PML4Es + PTEs 分配在这个范围内。

    因此,为了能够将虚拟地址转换为其 PTE 虚拟地址(!pte2va 与此相反),请将111101101 附加到虚拟地址的开头,然后截断最后 12 位(页面偏移量,不再有用),然后将其乘以 8 个字节(PTE 大小)(即在末尾添加 3 个零,这会从最后一级索引到包含PTE 乘以 PTE 结构的大小)。将 PML4E 索引连接到开头只会导致它循环一次,以便您实际获得 PTE 而不是 PTE 指向的内容。将其连接到开头与将其添加到 MmPteBase 相同。

    下面是简单的 C++ 代码:

    // pte.cpp
    #include<iostream>
    #include<string>
    
    int main(int argc, char *argv[]) {
        unsigned long long int input = std::stoull(argv[1], nullptr, 16);
        long long int ptebase = 0xFFFFF68000000000;
        long long int pteaddress = ptebase + ((input >> 12) << 3);
        std::cout << "0x" << std::hex << pteaddress;
    }
    
    C:\> pte 13fe60000
    0xfffff680009ff300
    

    要获得 PDE 虚拟地址,您必须将其附加两次,然后截断最后 21 位,然后乘以 8。这就是 !pte 的工作方式,与 !pte2va 正好相反。

    类似地,PDEs + PDPTEs + PML4Es 分配在范围内:

                            first   last
     *   pml4e_offset     : 0x1ed   0x1ed
     *   pdpe_offset      : 0x1ed   0x1ed
     *   pde_offset       : 0x000   0x1ff
     *   pte_offset       : 0x000   0x1ff
     *   offset           : 0x000   0x000
    

    因为当你在页表页面范围内到达0x1ed 的 pdpte 偏移量时,突然之间,你又在 PML4 中循环,所以你得到了 PDE。

    如果它说虚拟页面中的地址没有 PTE,对应的物理框架显示为 VMMap 工作集的一部分,那么您可能遇到my issue,您需要使用@ 987654376@ 如果您正在进行实时内核调试(本地或远程),以明确告诉调试器您要在进程上下文中转换用户和内核地址,而不是调试器。

    【讨论】:

      【解决方案2】:

      我发现自 Windows 10 周年更新(1607、10.0.14393)以来,PML4 表已被随机化以减轻内核堆喷射。 这意味着页面表可能放置在0xFFFFF6800000

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2017-07-08
        • 1970-01-01
        • 2022-10-04
        • 1970-01-01
        • 2018-11-28
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多