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