1import struct 2 3from core import ( 4 gettype, 5 xnu_format, 6 SBValueFormatter, 7) 8from core.iterators import ( 9 RB_HEAD, 10) 11 12from .kmem import MemoryRange 13from .btlog import BTLog, BTLibrary 14from .whatis import * 15 16 17@SBValueFormatter.converter("vm_prot") 18def vm_prot_converter(prot): 19 PROT_STR = "-rw?x" 20 return PROT_STR[prot & 1] + PROT_STR[prot & 2] + PROT_STR[prot & 4] 21 22 23class VMMap(object): 24 """ Helper class to manipulate a vm_map_t """ 25 26 def __init__(self, vm_map, name=None): 27 self.sbv = vm_map 28 self.name = name 29 self.rb = RB_HEAD( 30 vm_map.chkGetValueForExpressionPath(".hdr.rb_head_store"), 31 "entry", 32 self.entry_compare 33 ) 34 35 vme_type = gettype('struct vm_map_entry') 36 self.to_entry = vme_type.xContainerOfTransform('store') 37 38 def entry_compare(self, rb_entry, address): 39 vme = self.to_entry(rb_entry) 40 41 if vme.xGetScalarByPath(".links.end") <= address: 42 return 1 43 if address < vme.xGetScalarByPath(".links.start"): 44 return -1 45 return 0 46 47 def find(self, address): 48 ent = self.rb.find(address) 49 return self.to_entry(ent) if ent else None 50 51 def describe(self, verbose=False): 52 fmt = ( 53 "VM Map Info\n" 54 " vm map : {&v:#x} \n" 55 ) 56 if self.name: 57 fmt += ( 58 " vm map name : {m.name:s} \n" 59 ) 60 fmt += ( 61 " pmap : {$v.pmap:#x} \n" 62 " vm size : {$v.size|human_size} ({$v.size:,d} bytes) \n" 63 " entries : {$v.hdr.nentries} \n" 64 " map range : " 65 "{$v.hdr.links.start:#x} - {$v.hdr.links.end:#x}\n" 66 " map pgshift : {$v.hdr.page_shift}\n" 67 ) 68 print(xnu_format(fmt, m=self, v=self.sbv)) 69 70 71class VMMapEntry(MemoryObject): 72 """ Memory Object for a kernel map memory entry """ 73 74 MO_KIND = "kernel map entry" 75 76 def __init__(self, kmem, address, vm_map): 77 super().__init__(kmem, address) 78 self.vm_map = vm_map 79 self.sbv = vm_map.find(address) 80 81 @property 82 def object_range(self): 83 sbv = self.sbv 84 if sbv: 85 return MemoryRange( 86 sbv.xGetScalarByPath('.links.start'), 87 sbv.xGetScalarByPath('.links.end') 88 ) 89 90 base = self.address & ~self.kmem.page_mask 91 return MemoryRange(base, base + self.kmem.page_size) 92 93 @property 94 def vme_offset(self): 95 return self.sbv.xGetScalarByName('vme_offset') << 12 96 97 @property 98 def vme_object_type(self): 99 sbv = self.sbv 100 if sbv.xGetScalarByName('is_sub_map'): 101 return "submap" 102 if sbv.xGetScalarByName('vme_kernel_object'): 103 return "kobject" 104 return "vm object" 105 106 @property 107 def vme_object(self): 108 kmem = self.kmem 109 sbv = self.sbv 110 111 if sbv.xGetScalarByName('is_sub_map'): 112 addr = sbv.xGetScalarByName('vme_submap') << 2 113 return (addr, kmem.vm_map_type) 114 115 if sbv.xGetScalarByName('vme_kernel_object'): 116 return (kmem.vm_kobject.GetLoadAddress(), kmem.vmo_type) 117 118 packed = sbv.xGetScalarByName('vme_object_or_delta') 119 addr = kmem.vm_page_packing.unpack(packed) 120 return (addr, kmem.vmo_type) 121 122 @property 123 def pages(self): 124 return self.object_range.size >> self.kmem.page_shift 125 126 def describe(self, verbose=False): 127 128 self.vm_map.describe() 129 130 if not self.sbv: 131 fmt = ( 132 "Kernel Map Entry Info\n" 133 " No memory mapped at this address\n" 134 ) 135 print(xnu_format(fmt)) 136 return 137 138 fmt = ( 139 "VM Map Entry Info\n" 140 " vm entry : {&v:#x}\n" 141 " start / end : " 142 "{$v.links.start:#x} - {$v.links.end:#x} " 143 "({0.pages:,d} pages)\n" 144 " vm tag : {$v.vme_alias|vm_kern_tag}\n" 145 ) 146 range_id = next(( 147 i 148 for i, r in enumerate(self.kmem.kmem_ranges) 149 if r.contains(self.address) 150 ), None) 151 if range_id: 152 fmt += ( 153 " vm range id : {range_id}\n" 154 ) 155 fmt += ( 156 " protection : " 157 "{$v.protection|vm_prot}/{$v.max_protection|vm_prot}\n" 158 " vm object : " 159 "{0.vme_object_type} ({0.vme_object[0]:#x})\n" 160 " entry offset : {0.vme_offset:#x}\n" 161 ) 162 print(xnu_format(fmt, self, v=self.sbv, range_id=range_id)) 163 164 165@whatis_provider 166class KernelMapWhatisProvider(WhatisProvider): 167 """ 168 Whatis Provider for the kernel map ranges 169 """ 170 171 def claims(self, address): 172 kmem = self.kmem 173 174 return any(r.contains(address) for r in kmem.kmem_ranges) or \ 175 any(r.contains(address) for r in kmem.iokit_ranges) 176 177 def lookup(self, address): 178 kmem = self.kmem 179 180 if any(r.contains(address) for r in kmem.kmem_ranges): 181 return VMMapEntry(kmem, address, VMMap(kmem.kernel_map, 'kernel_map')) 182 183 idx = next(idx 184 for idx, r 185 in enumerate(kmem.iokit_ranges) 186 if r.contains(address)) 187 gps = kmem.target.chkFindFirstGlobalVariable('gIOKitPageableSpace') 188 map = gps.chkGetValueForExpressionPath('.maps[{}].map'.format(idx)).Dereference() 189 name = 'gIOKitPageableFixed{}'.format(idx) 190 return VMMapEntry(kmem, address, VMMap(map, name)) 191 192 193 194__all__ = [ 195 VMMap.__name__, 196 VMMapEntry.__name__, 197 KernelMapWhatisProvider.__name__, 198] 199