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