@ -2,8 +2,8 @@ from __future__ import annotations
import math
import re
from dataclasses import dataclass
from typing import Dict
from typing import List
from typing import Tuple
import pwndbg
@ -31,6 +31,14 @@ def first_kernel_page_start():
return INVALID_ADDR
@dataclass
class PageTableLevel :
name : str
entry : int
virt : int # within physmap
idx : int
class ArchPagingInfo :
USERLAND = " userland "
KERNELLAND = " kernel [.text] "
@ -50,6 +58,7 @@ class ArchPagingInfo:
va_bits : int
pagetable_cache : Dict [ pwndbg . dbg_mod . Value , Dict [ int , int ] ] = { }
pagetableptr_cache : Dict [ int , pwndbg . dbg_mod . Value ] = { }
pagetable_level_names : Tuple [ str , . . . ]
@property
@pwndbg.lib.cache.cache_until ( " objfile " )
@ -99,27 +108,26 @@ class ArchPagingInfo:
return None
def pagewalk (
self , target , entry
) - > Tuple [ Tuple [ str , . . . ] , List [ Tuple [ int | None , int | None ] ] ] :
def pagewalk ( self , target , entry ) - > Tuple [ PageTableLevel , . . . ] :
raise NotImplementedError ( )
def pagewalk_helper ( self , target , entry ) - > List[ Tuple [ int | None , int | None ] ] :
def pagewalk_helper ( self , target , entry ) - > Tuple[ PageTableLevel , . . . ] :
base = self . physmap
if entry > base :
# user inputted a physmap address as pointer to pgd
entry - = base
level = self . paging_level
result : List [ Tuple [ int | None , int | None ] ] = [ ( None , None ) ] * ( level + 1 )
result = [ PageTableLevel ( None , None , None , None ) ] * ( level + 1 )
page_shift = self . page_shift
ENTRYMASK = ~ ( ( 1 << page_shift ) - 1 ) & ( ( 1 << self . va_bits ) - 1 )
IDXMASK = ( 1 << ( page_shift - math . ceil ( math . log2 ( pwndbg . aglib . arch . ptrsize ) ) ) ) - 1
for i in range ( level , 0 , - 1 ) :
vaddr = ( entry & ENTRYMASK ) + base - self . phys_offset
if self . should_stop_pagewalk ( entry ) :
break
shift = ( i - 1 ) * ( page_shift - 3 ) + page_shift
offset = target & ( ( 1 << shift ) - 1 )
idx = ( target & ( 0x1FF << shift ) ) >> shift
idx = ( target & ( IDXMASK << shift ) ) >> shift
entry = 0
try :
# with this optimization, roughly x2 as fast on average
@ -142,10 +150,15 @@ class ArchPagingInfo:
print ( M . warn ( f " Exception while page walking: { e } " ) )
entry = 0
if entry == 0 :
return result
result [ i ] = ( entry , vaddr )
result [ 0 ] = ( entry , ( entry & ENTRYMASK ) + base + offset - self . phys_offset )
return result
return tuple ( result )
result [ i ] = PageTableLevel ( self . pagetable_level_names [ i ] , entry , vaddr , idx )
result [ 0 ] = PageTableLevel (
self . pagetable_level_names [ 0 ] ,
entry ,
( entry & ENTRYMASK ) + base + offset - self . phys_offset ,
None ,
)
return tuple ( result )
def pageentry_flags ( self , level ) - > BitFlags :
raise NotImplementedError ( )
@ -313,12 +326,10 @@ class x86_64PagingInfo(ArchPagingInfo):
if pwndbg . aglib . regs [ pwndbg . aglib . regs . stack ] in page :
page . objfile = " kernel [stack] "
def pagewalk (
self , target , entry
) - > Tuple [ Tuple [ str , . . . ] , List [ Tuple [ int | None , int | None ] ] ] :
def pagewalk ( self , target , entry ) - > Tuple [ PageTableLevel , . . . ] :
if entry is None :
entry = pwndbg . aglib . regs [ " cr3 " ]
return self . page table_level_names, self . page walk_helper( target , entry )
return self . page walk_helper( target , entry )
def pageentry_flags ( self , is_last ) - > BitFlags :
return BitFlags ( [ ( " NX " , 63 ) , ( " PS " , 7 ) , ( " A " , 5 ) , ( " U " , 2 ) , ( " W " , 1 ) , ( " P " , 0 ) ] )
@ -606,16 +617,14 @@ class Aarch64PagingInfo(ArchPagingInfo):
pass
return 0x40000000 # default
def pagewalk (
self , target , entry
) - > Tuple [ Tuple [ str , . . . ] , List [ Tuple [ int | None , int | None ] ] ] :
def pagewalk ( self , target , entry ) - > Tuple [ PageTableLevel , . . . ] :
if entry is None :
if pwndbg . aglib . memory . is_kernel ( target ) :
entry = pwndbg . aglib . regs . TTBR1_EL1
else :
entry = pwndbg . aglib . regs . TTBR0_EL1
self . entry = entry
return self . page table_level_names, self . page walk_helper( target , entry )
return self . page walk_helper( target , entry )
def pageentry_flags ( self , is_last ) - > BitFlags :
if is_last :