Tuesday, June 11, 2024

A Workaround for "Levels not implemented for this platform"

The Windows kernel people may be familiar with a cool built-in "pte" extension that can help you troubleshoot ugly BSODs by checking if some kernel memory address is inaccessible.


0: kd> !pte ffff8d89`cce3efe8 
                                           VA ffff8d89cce3efe8
PXE at FFFF91C8E47238D8    PPE at FFFF91C8E471B138    PDE at FFFF91C8E3627338    PTE at FFFF91C6C4E671F0
contains 0A0000021E002863  contains 0A00000002903863  contains 0A0000012845B863  contains 8A0000015AD4F963
pfn 21e002    ---DA--KWEV  pfn 2903      ---DA--KWEV  pfn 12845b    ---DA--KWEV  pfn 15ad4f    -G-DA--KW-V

0: kd> dt nt!_HARDWARE_PTE FFFF91C6C4E671F0
   +0x000 Valid            : 0y1
   +0x000 Write            : 0y1
   +0x000 Owner            : 0y0
   +0x000 WriteThrough     : 0y0
   +0x000 CacheDisable     : 0y0
   +0x000 Accessed         : 0y1
   +0x000 Dirty            : 0y1
   +0x000 LargePage        : 0y0
   +0x000 Global           : 0y1
   +0x000 CopyOnWrite      : 0y0
   +0x000 Prototype        : 0y0
   +0x000 reserved0        : 0y1
   +0x000 PageFrameNumber  : 0y000000000000000101011010110101001111 (0x15ad4f)
   +0x000 reserved1        : 0y0000
   +0x000 SoftwareWsIndex  : 0y00010100000 (0xa0)
   +0x000 NoExecute        : 0y1


Normally it shows PTE address among with other information, but unfortunately it has been broken for a quite some time (and his colleague vtop - too):


0: kd> !pte fffff807`1f8a7c58
Levels not implemented for this platform


And it doesn't look like MS is going to fix it anytime soon, see:

https://learn.microsoft.com/en-us/answers/questions/1010386/windbg-pte-command-levels-not-implemented-for-this?page=1#answer-1315958

https://github.com/microsoftfeedback/WinDbg-Feedback/issues/8


It's no problem if you have a single occasional BSOD, but if you really need to use this extension for a number of dumps in a row it's getting annoying.

Sooo, I decided to use my small and nice (and a little bit outdated) code emulator and emulate nt!MiGetPteAddress instead:


0: kd> .load c:\orthia\orthia.dll;!orthia.profile /f %temp%\test.db; !orthia.vm_vm_def
0: kd> !orthia.vm_vm_call 0 nt!MiGetPteAddress --print rcx=fffff807`1f8a7c58

Diana Error Code: DI_END
rax=fffff6fc038fc538 rbx=fffff8071b881180 rcx=0000007c038fc538
rdx=0000025800000000 rsi=0000000000000001 rdi=000000000000000d
rip=0000000000000000 rsp=fffff8071f8a7c58 rbp=ffff940947d3e040
r8=0000000000000018  r9=ffff9409476e0000 r10=000000000000000b
r11=0000000000009ee6 r12=0000000000000000 r13=fffff8071b881180
r14=0000000000000001 r15=ffffffffffffff00
cs=0010  ss=0018  ds=002b  es=002b  fs=0053  gs=002b  efl=00000282
Commands count: 6
Modified pages:
Done

0: kd> dt ntkrnlmp!_HARDWARE_PTE fffff6fc038fc538
 +0x000 Valid            : 0y1
 +0x000 Write            : 0y1
 +0x000 Owner            : 0y0
 +0x000 WriteThrough     : 0y0
   +0x000 CacheDisable     : 0y0
   +0x000 Accessed         : 0y1
 +0x000 Dirty            : 0y1
   +0x000 LargePage        : 0y0
 +0x000 Global           : 0y0
 +0x000 CopyOnWrite      : 0y0
 +0x000 Prototype        : 0y0
 +0x000 reserved0        : 0y1
 +0x000 PageFrameNumber  : 0y000000000000000000000110110010100111 (0x6ca7)
 +0x000 reserved1        : 0y0000
 +0x000 SoftwareWsIndex  : 0y00010010000 (0x90)
 +0x000 NoExecute        : 0y1

As you can see there were just 6 assembler instruction to emulate, so it handled them successfully.

The extension is here: https://github.com/ligen-ua/diana-dasm/releases/tag/v1.1-tools

The sources and this case study is there:

https://github.com/ligen-ua/diana-dasm?tab=readme-ov-file#pte-case-study


No comments: