Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/opengl/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Windows 10 x64:无法在Windbg上获取PXE_Windows_Debugging_Winapi_Memory Management_Windbg - Fatal编程技术网

Windows 10 x64:无法在Windbg上获取PXE

Windows 10 x64:无法在Windbg上获取PXE,windows,debugging,winapi,memory-management,windbg,Windows,Debugging,Winapi,Memory Management,Windbg,无法理解Windows内存管理器是如何工作的。 我查看附加的用户进程(dbgview.exe)。 这是WOW64过程。在指定的地址(0x76560000)上有内核32.dll模块(也是WOW64)的.text部分。 为什么进程页表中没有指向这些虚拟地址的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. <...>

无法理解Windows内存管理器是如何工作的。 我查看附加的用户进程(
dbgview.exe
)。 这是WOW64过程。在指定的地址(
0x76560000
)上有
内核32.dll
模块(也是WOW64)的
.text
部分。 为什么进程页表中没有指向这些虚拟地址的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  ?? ?? ?? ?? ?? ?? ?? ??-?? ?? ?? ?? ?? ?? ?? ?? ???????????????
<...>
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>!私人股本76560000
弗吉尼亚州00000000 76560000
FFFFF 6FB7DBED000处的PXE,FFFFF 6FB7DA00008处的PPE,FFFFF 6FB40001D90处的PDE,FFFFF 680003B2B00处的PTE
无法获取PXE FFFFF 6FB7DBED000
kd>db FFFFF 68003B2B00
FFFFF 680`003b2b00???????????????

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

我发现,自从Windows 10周年更新(1607,10.0.14393)以来,PML4表被随机分配,以减少内核堆溢出。
这意味着页表可能未放置在
0xFFFFF6800000

首先,使用
将任意虚拟地址转换为物理地址!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页又名.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
因此,地址
FFFFF 6FB7DBED000
是PML4页面的虚拟地址,
FFFFF 6FB7DBEDF68
是PML4E自参考条目的虚拟地址(
1ed*8
=
f68

fffff 6fb7dbed000
=
111111111111111111111101101101000000000000

111111111111111111111101111101101111101101111101101111101101000000000000000000

PML4只能位于PML4E、PDTPE、PDE和PTE索引相同的虚拟地址,因此实际上有
2^9
不同的组合,windows 7总是选择
0x1ed
,即
111101101
。这是因为PML4包含指向自身的PML4,即物理帧PML4的索引,所以它需要在层次结构的每个级别上保持对同一位置的索引

PML4是一个页表页,必须位于内核中,内核地址是高度规范的,即前缀为
1111111111
,内核地址从
00001
11111
开始,即从
08
ff

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

1111111111111 00001000010000000000000000000000000000

111111111111111111111111111111111111111111111111000000000000000000

即第一个是
FFFF080402010000
,第二个是
FF088442211000
,最后一个是
FFFFFFFFFF000

:

在Windows10th2之前,自引用PML4条目的魔法索引是上文提到的
0x1ed
。但是1607年的Windows10呢?微软升级了他们的游戏,作为提高Windows安全性的持续战斗,索引在引导时是随机的,因此
0x1ed
现在是512个索引之一[sic.(496)]自引用条目索引可能具有的值(即9位索引)。此外,它还破坏了一些自己的工具,如
!pte2va
WinDbg命令

0xFFF6800000000
是第一页表格页面中第一个PTE的地址,因此基本上
MmPteBase
,除了因为在Windows 10 1607上PML4E可以是一个非
0x1ed
的地址之外,因此基数并不总是
0xFFF6800000000
,它使用变量
nt!MmPteBase
来了解insta页表页分配的基址的起始位置。以前,此符号在
ntoskrnl.exe
中不存在,因为它具有硬编码的基址
0xFFFFF6800000000
。第一页和最后一页表页的地址将是:

                        first   last
 *   pml4e_offset     : 0x1ed   0x1ed
 *   pdpe_offset      : 0x000   0x1ff
 *   pde_offset       : 0x000   0x1ff
 *   pte_offset       : 0x000   0x1ff
 *   offset           : 0x000   0x000
当PML4E索引为
0x1ed
时,第一页的表页为
0xFFFFF6800000000
,最后一页的表页为
0xFFFFFFF000
。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;
}
要获取PDE虚拟地址,必须将其粘贴两次,然后将最后21位截断,然后再乘以8。这就是
!pte
的工作原理,与
!pte2va
相反

类似地,PDE+PDPTE+PML4E的分配范围如下:

                        first   last
 *   pml4e_offset     : 0x1ed   0x1ed
 *   pdpe_offset      : 0x1ed   0x1ed
 *   pde_offset       : 0x000   0x1ff
 *   pte_offset       : 0x000   0x1ff
 *   offset           : 0x000   0x000
因为当您到达页面表页面范围内的pdpte偏移量的
0x1ed
时,突然之间,您正在PML4 o中循环
                        first   last
 *   pml4e_offset     : 0x1ed   0x1ed
 *   pdpe_offset      : 0x1ed   0x1ed
 *   pde_offset       : 0x000   0x1ff
 *   pte_offset       : 0x000   0x1ff
 *   offset           : 0x000   0x000