1from xnu import * 2import xnudefines 3from kdp import * 4from utils import * 5 6def ReadPhysInt(phys_addr, bitsize = 64, cpuval = None): 7 """ Read a physical memory data based on address. 8 params: 9 phys_addr : int - Physical address to read 10 bitsize : int - defines how many bytes to read. defaults to 64 bit 11 cpuval : None (optional) 12 returns: 13 int - int value read from memory. in case of failure 0xBAD10AD is returned. 14 """ 15 if "kdp" == GetConnectionProtocol(): 16 return KDPReadPhysMEM(phys_addr, bitsize) 17 18 #NO KDP. Attempt to use physical memory 19 paddr_in_kva = kern.PhysToKernelVirt(long(phys_addr)) 20 if paddr_in_kva : 21 if bitsize == 64 : 22 return kern.GetValueFromAddress(paddr_in_kva, 'uint64_t *').GetSBValue().Dereference().GetValueAsUnsigned() 23 if bitsize == 32 : 24 return kern.GetValueFromAddress(paddr_in_kva, 'uint32_t *').GetSBValue().Dereference().GetValueAsUnsigned() 25 if bitsize == 16 : 26 return kern.GetValueFromAddress(paddr_in_kva, 'uint16_t *').GetSBValue().Dereference().GetValueAsUnsigned() 27 if bitsize == 8 : 28 return kern.GetValueFromAddress(paddr_in_kva, 'uint8_t *').GetSBValue().Dereference().GetValueAsUnsigned() 29 return 0xBAD10AD 30 31@lldb_command('readphys') 32def ReadPhys(cmd_args = None): 33 """ Reads the specified untranslated address 34 The argument is interpreted as a physical address, and the 64-bit word 35 addressed is displayed. 36 usage: readphys <nbits> <address> 37 nbits: 8,16,32,64 38 address: 1234 or 0x1234 39 """ 40 if cmd_args == None or len(cmd_args) < 2: 41 print "Insufficient arguments.", ReadPhys.__doc__ 42 return False 43 else: 44 nbits = ArgumentStringToInt(cmd_args[0]) 45 phys_addr = ArgumentStringToInt(cmd_args[1]) 46 print "{0: <#x}".format(ReadPhysInt(phys_addr, nbits)) 47 return True 48 49lldb_alias('readphys8', 'readphys 8 ') 50lldb_alias('readphys16', 'readphys 16 ') 51lldb_alias('readphys32', 'readphys 32 ') 52lldb_alias('readphys64', 'readphys 64 ') 53 54def KDPReadPhysMEM(address, bits): 55 """ Setup the state for READPHYSMEM64 commands for reading data via kdp 56 params: 57 address : int - address where to read the data from 58 bits : int - number of bits in the intval (8/16/32/64) 59 returns: 60 int: read value from memory. 61 0xBAD10AD: if failed to read data. 62 """ 63 retval = 0xBAD10AD 64 if "kdp" != GetConnectionProtocol(): 65 print "Target is not connected over kdp. Nothing to do here." 66 return retval 67 68 input_address = unsigned(addressof(kern.globals.manual_pkt.input)) 69 len_address = unsigned(addressof(kern.globals.manual_pkt.len)) 70 data_address = unsigned(addressof(kern.globals.manual_pkt.data)) 71 if not WriteInt32ToMemoryAddress(0, input_address): 72 return retval 73 74 kdp_pkt_size = GetType('kdp_readphysmem64_req_t').GetByteSize() 75 if not WriteInt32ToMemoryAddress(kdp_pkt_size, len_address): 76 return retval 77 78 data_addr = int(addressof(kern.globals.manual_pkt)) 79 pkt = kern.GetValueFromAddress(data_addr, 'kdp_readphysmem64_req_t *') 80 81 header_value =GetKDPPacketHeaderInt(request=GetEnumValue('kdp_req_t::KDP_READPHYSMEM64'), length=kdp_pkt_size) 82 83 if ( WriteInt64ToMemoryAddress((header_value), int(addressof(pkt.hdr))) and 84 WriteInt64ToMemoryAddress(address, int(addressof(pkt.address))) and 85 WriteInt32ToMemoryAddress((bits/8), int(addressof(pkt.nbytes))) and 86 WriteInt16ToMemoryAddress(xnudefines.lcpu_self, int(addressof(pkt.lcpu))) 87 ): 88 89 if WriteInt32ToMemoryAddress(1, input_address): 90 # now read data from the kdp packet 91 data_address = unsigned(addressof(kern.GetValueFromAddress(int(addressof(kern.globals.manual_pkt.data)), 'kdp_readphysmem64_reply_t *').data)) 92 if bits == 64 : 93 retval = kern.GetValueFromAddress(data_address, 'uint64_t *').GetSBValue().Dereference().GetValueAsUnsigned() 94 if bits == 32 : 95 retval = kern.GetValueFromAddress(data_address, 'uint32_t *').GetSBValue().Dereference().GetValueAsUnsigned() 96 if bits == 16 : 97 retval = kern.GetValueFromAddress(data_address, 'uint16_t *').GetSBValue().Dereference().GetValueAsUnsigned() 98 if bits == 8 : 99 retval = kern.GetValueFromAddress(data_address, 'uint8_t *').GetSBValue().Dereference().GetValueAsUnsigned() 100 return retval 101 102 103def KDPWritePhysMEM(address, intval, bits): 104 """ Setup the state for WRITEPHYSMEM64 commands for saving data in kdp 105 params: 106 address : int - address where to save the data 107 intval : int - integer value to be stored in memory 108 bits : int - number of bits in the intval (8/16/32/64) 109 returns: 110 boolean: True if the write succeeded. 111 """ 112 if "kdp" != GetConnectionProtocol(): 113 print "Target is not connected over kdp. Nothing to do here." 114 return False 115 input_address = unsigned(addressof(kern.globals.manual_pkt.input)) 116 len_address = unsigned(addressof(kern.globals.manual_pkt.len)) 117 data_address = unsigned(addressof(kern.globals.manual_pkt.data)) 118 if not WriteInt32ToMemoryAddress(0, input_address): 119 return False 120 121 kdp_pkt_size = GetType('kdp_writephysmem64_req_t').GetByteSize() 122 if not WriteInt32ToMemoryAddress(kdp_pkt_size, len_address): 123 return False 124 125 data_addr = int(addressof(kern.globals.manual_pkt)) 126 pkt = kern.GetValueFromAddress(data_addr, 'kdp_writephysmem64_req_t *') 127 128 header_value =GetKDPPacketHeaderInt(request=GetEnumValue('kdp_req_t::KDP_WRITEPHYSMEM64'), length=kdp_pkt_size) 129 130 if ( WriteInt64ToMemoryAddress((header_value), int(addressof(pkt.hdr))) and 131 WriteInt64ToMemoryAddress(address, int(addressof(pkt.address))) and 132 WriteInt32ToMemoryAddress((bits/8), int(addressof(pkt.nbytes))) and 133 WriteInt16ToMemoryAddress(xnudefines.lcpu_self, int(addressof(pkt.lcpu))) 134 ): 135 136 if bits == 8: 137 if not WriteInt8ToMemoryAddress(intval, int(addressof(pkt.data))): 138 return False 139 if bits == 16: 140 if not WriteInt16ToMemoryAddress(intval, int(addressof(pkt.data))): 141 return False 142 if bits == 32: 143 if not WriteInt32ToMemoryAddress(intval, int(addressof(pkt.data))): 144 return False 145 if bits == 64: 146 if not WriteInt64ToMemoryAddress(intval, int(addressof(pkt.data))): 147 return False 148 if WriteInt32ToMemoryAddress(1, input_address): 149 return True 150 return False 151 152 153def WritePhysInt(phys_addr, int_val, bitsize = 64): 154 """ Write and integer value in a physical memory data based on address. 155 params: 156 phys_addr : int - Physical address to read 157 int_val : int - int value to write in memory 158 bitsize : int - defines how many bytes to read. defaults to 64 bit 159 returns: 160 bool - True if write was successful. 161 """ 162 if "kdp" == GetConnectionProtocol(): 163 if not KDPWritePhysMEM(phys_addr, int_val, bitsize): 164 print "Failed to write via KDP." 165 return False 166 return True 167 #We are not connected via KDP. So do manual math and savings. 168 print "Failed: Write to physical memory is not supported for %s connection." % GetConnectionProtocol() 169 return False 170 171@lldb_command('writephys') 172def WritePhys(cmd_args=None): 173 """ writes to the specified untranslated address 174 The argument is interpreted as a physical address, and the 64-bit word 175 addressed is displayed. 176 usage: writephys <nbits> <address> <value> 177 nbits: 8,16,32,64 178 address: 1234 or 0x1234 179 value: int value to be written 180 ex. (lldb)writephys 16 0x12345abcd 0x25 181 """ 182 if cmd_args == None or len(cmd_args) < 3: 183 print "Invalid arguments.", WritePhys.__doc__ 184 else: 185 nbits = ArgumentStringToInt(cmd_args[0]) 186 phys_addr = ArgumentStringToInt(cmd_args[1]) 187 int_value = ArgumentStringToInt(cmd_args[2]) 188 print WritePhysInt(phys_addr, int_value, nbits) 189 190 191lldb_alias('writephys8', 'writephys 8 ') 192lldb_alias('writephys16', 'writephys 16 ') 193lldb_alias('writephys32', 'writephys 32 ') 194lldb_alias('writephys64', 'writephys 64 ') 195 196def _PT_Step(paddr, index, verbose_level = vSCRIPT): 197 """ 198 Step to lower-level page table and print attributes 199 paddr: current page table entry physical address 200 index: current page table entry index (0..511) 201 verbose_level: vHUMAN: print nothing 202 vSCRIPT: print basic information 203 vDETAIL: print basic information and hex table dump 204 returns: (pt_paddr, pt_valid, pt_large) 205 pt_paddr: next level page table entry physical address 206 or null if invalid 207 pt_valid: 1 if $kgm_pt_paddr is valid, 0 if the walk 208 should be aborted 209 pt_large: 1 if kgm_pt_paddr is a page frame address 210 of a large page and not another page table entry 211 """ 212 entry_addr = paddr + (8 * index) 213 entry = ReadPhysInt(entry_addr, 64, xnudefines.lcpu_self ) 214 out_string = '' 215 if verbose_level >= vDETAIL: 216 for pte_loop in range(0, 512): 217 paddr_tmp = paddr + (8 * pte_loop) 218 out_string += "{0: <#020x}:\t {1: <#020x}\n".format(paddr_tmp, ReadPhysInt(paddr_tmp, 64, xnudefines.lcpu_self)) 219 paddr_mask = ~((0xfff<<52) | 0xfff) 220 paddr_large_mask = ~((0xfff<<52) | 0x1fffff) 221 pt_valid = False 222 pt_large = False 223 pt_paddr = 0 224 if verbose_level < vSCRIPT: 225 if entry & 0x1 : 226 pt_valid = True 227 pt_large = False 228 pt_paddr = entry & paddr_mask 229 if entry & (0x1 <<7): 230 pt_large = True 231 pt_paddr = entry & paddr_large_mask 232 else: 233 out_string+= "{0: <#020x}:\n\t{1:#020x}\n\t".format(entry_addr, entry) 234 if entry & 0x1: 235 out_string += " valid" 236 pt_paddr = entry & paddr_mask 237 pt_valid = True 238 else: 239 out_string += " invalid" 240 pt_paddr = 0 241 pt_valid = False 242 #Stop decoding other bits 243 entry = 0 244 if entry & (0x1 << 1): 245 out_string += " writable" 246 else: 247 out_string += " read-only" 248 249 if entry & (0x1 << 2): 250 out_string += " user" 251 else: 252 out_string += " supervisor" 253 254 if entry & (0x1 << 3): 255 out_string += " PWT" 256 257 if entry & (0x1 << 4): 258 out_string += " PCD" 259 260 if entry & (0x1 << 5): 261 out_string += " accessed" 262 263 if entry & (0x1 << 6): 264 out_string += " dirty" 265 266 if entry & (0x1 << 7): 267 out_string += " large" 268 pt_large = True 269 else: 270 pt_large = False 271 272 if entry & (0x1 << 8): 273 out_string += " global" 274 275 if entry & (0x3 << 9): 276 out_string += " avail:{0:x}".format((entry >> 9) & 0x3) 277 278 if entry & (0x1 << 63): 279 out_string += " noexec" 280 print out_string 281 return (pt_paddr, pt_valid, pt_large) 282 283 284 285 286def _PmapL4Walk(pmap_addr_val,vaddr, verbose_level = vSCRIPT): 287 """ Walk the l4 pmap entry. 288 params: pmap_addr_val - core.value representing kernel data of type pmap_addr_t 289 vaddr : int - virtual address to walk 290 """ 291 is_cpu64_bit = int(kern.globals.cpu_64bit) 292 pt_paddr = unsigned(pmap_addr_val) 293 pt_valid = (unsigned(pmap_addr_val) != 0) 294 pt_large = 0 295 pframe_offset = 0 296 if pt_valid and is_cpu64_bit: 297 # Lookup bits 47:39 of linear address in PML4T 298 pt_index = (vaddr >> 39) & 0x1ff 299 pframe_offset = vaddr & 0x7fffffffff 300 if verbose_level > vHUMAN : 301 print "pml4 (index {0:d}):".format(pt_index) 302 (pt_paddr, pt_valid, pt_large) = _PT_Step(pt_paddr, pt_index, verbose_level) 303 if pt_valid: 304 # Lookup bits 38:30 of the linear address in PDPT 305 pt_index = (vaddr >> 30) & 0x1ff 306 pframe_offset = vaddr & 0x3fffffff 307 if verbose_level > vHUMAN: 308 print "pdpt (index {0:d}):".format(pt_index) 309 (pt_paddr, pt_valid, pt_large) = _PT_Step(pt_paddr, pt_index, verbose_level) 310 if pt_valid and not pt_large: 311 #Lookup bits 29:21 of the linear address in PDPT 312 pt_index = (vaddr >> 21) & 0x1ff 313 pframe_offset = vaddr & 0x1fffff 314 if verbose_level > vHUMAN: 315 print "pdt (index {0:d}):".format(pt_index) 316 (pt_paddr, pt_valid, pt_large) = _PT_Step(pt_paddr, pt_index, verbose_level) 317 if pt_valid and not pt_large: 318 #Lookup bits 20:21 of linear address in PT 319 pt_index = (vaddr >> 12) & 0x1ff 320 pframe_offset = vaddr & 0xfff 321 if verbose_level > vHUMAN: 322 print "pt (index {0:d}):".format(pt_index) 323 (pt_paddr, pt_valid, pt_large) = _PT_Step(pt_paddr, pt_index, verbose_level) 324 paddr = 0 325 paddr_isvalid = False 326 if pt_valid: 327 paddr = pt_paddr + pframe_offset 328 paddr_isvalid = True 329 330 if verbose_level > vHUMAN: 331 if paddr_isvalid: 332 pvalue = ReadPhysInt(paddr, 32, xnudefines.lcpu_self) 333 print "phys {0: <#020x}: {1: <#020x}".format(paddr, pvalue) 334 else: 335 print "no translation" 336 337 return 338 339def _PmapWalkARMLevel1Section(tte, vaddr, verbose_level = vSCRIPT): 340 paddr = 0 341 out_string = "" 342 #Supersection or just section? 343 if (tte & 0x40000) == 0x40000: 344 paddr = ( (tte & 0xFF000000) | (vaddr & 0x00FFFFFF) ) 345 else: 346 paddr = ( (tte & 0xFFF00000) | (vaddr & 0x000FFFFF) ) 347 348 if verbose_level >= vSCRIPT: 349 out_string += "{0: <#020x}\n\t{1: <#020x}\n\t".format(addressof(tte), tte) 350 #bit [1:0] evaluated in PmapWalkARM 351 # B bit 2 352 b_bit = (tte & 0x4) >> 2 353 # C bit 3 354 c_bit = (tte & 0x8) >> 3 355 #XN bit 4 356 if (tte & 0x10) : 357 out_string += "no-execute" 358 else: 359 out_string += "execute" 360 #Domain bit [8:5] if not supersection 361 if (tte & 0x40000) == 0x0: 362 out_string += " domain ({:d})".format(((tte & 0x1e0) >> 5) ) 363 #IMP bit 9 364 out_string += " imp({:d})".format( ((tte & 0x200) >> 9) ) 365 # AP bit 15 and [11:10] merged to a single 3 bit value 366 access = ( (tte & 0xc00) >> 10 ) | ((tte & 0x8000) >> 13) 367 out_string += xnudefines.arm_level2_access_strings[access] 368 369 #TEX bit [14:12] 370 tex_bits = ((tte & 0x7000) >> 12) 371 #Print TEX, C , B all together 372 out_string += " TEX:C:B({:d}{:d}{:d}:{:d}:{:d})".format( 373 1 if (tex_bits & 0x4) else 0, 374 1 if (tex_bits & 0x2) else 0, 375 1 if (tex_bits & 0x1) else 0, 376 c_bit, 377 b_bit 378 ) 379 # S bit 16 380 if tte & 0x10000: 381 out_string += " shareable" 382 else: 383 out_string += " not-shareable" 384 # nG bit 17 385 if tte & 0x20000 : 386 out_string += " not-global" 387 else: 388 out_string += " global" 389 # Supersection bit 18 390 if tte & 0x40000: 391 out_string += " supersection" 392 else: 393 out_string += " section" 394 #NS bit 19 395 if tte & 0x80000 : 396 out_string += " no-secure" 397 else: 398 out_string += " secure" 399 400 print out_string 401 return paddr 402 403 404 405def _PmapWalkARMLevel2(tte, vaddr, verbose_level = vSCRIPT): 406 """ Pmap walk the level 2 tte. 407 params: 408 tte - value object 409 vaddr - int 410 returns: str - description of the tte + additional informaiton based on verbose_level 411 """ 412 pte_base = kern.PhysToKernelVirt(tte & 0xFFFFFC00) 413 pte_index = (vaddr >> 12) & 0xFF 414 pte_base_val = kern.GetValueFromAddress(pte_base, 'pt_entry_t *') 415 pte = pte_base_val[pte_index] 416 out_string = '' 417 if verbose_level >= vSCRIPT: 418 out_string += "{0: <#020x}\n\t{1: <#020x}\n\t".format(addressof(tte), tte) 419 # bit [1:0] evaluated in PmapWalkARM 420 # NS bit 3 421 if tte & 0x8: 422 out_string += ' no-secure' 423 else: 424 out_string += ' secure' 425 #Domain bit [8:5] 426 out_string += " domain({:d})".format(((tte & 0x1e0) >> 5)) 427 # IMP bit 9 428 out_string += " imp({:d})".format( ((tte & 0x200) >> 9)) 429 out_string += "\n" 430 if verbose_level >= vSCRIPT: 431 out_string += "second-level table (index {:d}):\n".format(pte_index) 432 if verbose_level >= vDETAIL: 433 for i in range(256): 434 tmp = pte_base_val[i] 435 out_string += "{0: <#020x}:\t{1: <#020x}\n".format(addressof(tmp), unsigned(tmp)) 436 437 paddr = 0 438 if pte & 0x2: 439 paddr = (unsigned(pte) & 0xFFFFF000) | (vaddr & 0xFFF) 440 441 if verbose_level >= vSCRIPT: 442 out_string += " {0: <#020x}\n\t{1: <#020x}\n\t".format(addressof(pte), unsigned(pte)) 443 if (pte & 0x3) == 0x0: 444 out_string += " invalid" 445 else: 446 if (pte & 0x3) == 0x1: 447 out_string += " large" 448 # XN bit 15 449 if pte & 0x8000 == 0x8000: 450 out_string+= " no-execute" 451 else: 452 out_string += " execute" 453 else: 454 out_string += " small" 455 # XN bit 0 456 if (pte & 0x1) == 0x01: 457 out_string += " no-execute" 458 else: 459 out_string += " execute" 460 # B bit 2 461 b_bit = (pte & 0x4) >> 2 462 c_bit = (pte & 0x8) >> 3 463 # AP bit 9 and [5:4], merged to a single 3-bit value 464 access = (pte & 0x30) >> 4 | (pte & 0x200) >> 7 465 out_string += xnudefines.arm_level2_access_strings[access] 466 467 #TEX bit [14:12] for large, [8:6] for small 468 tex_bits = ((pte & 0x1c0) >> 6) 469 if (pte & 0x3) == 0x1: 470 tex_bits = ((pte & 0x7000) >> 12) 471 472 # Print TEX, C , B alltogether 473 out_string += " TEX:C:B({:d}{:d}{:d}:{:d}:{:d})".format( 474 1 if (tex_bits & 0x4) else 0, 475 1 if (tex_bits & 0x2) else 0, 476 1 if (tex_bits & 0x1) else 0, 477 c_bit, 478 b_bit 479 ) 480 # S bit 10 481 if pte & 0x400 : 482 out_string += " shareable" 483 else: 484 out_string += " not-shareable" 485 486 # nG bit 11 487 if pte & 0x800: 488 out_string += " not-global" 489 else: 490 out_string += " global" 491 print out_string 492 return paddr 493 #end of level 2 walking of arm 494 495 496def PmapWalkARM(pmap, vaddr, verbose_level = vHUMAN): 497 """ Pmap walking for ARM kernel. 498 params: 499 pmapval: core.value - representing pmap_t in kernel 500 vaddr: int - integer representing virtual address to walk 501 """ 502 paddr = 0 503 # shift by TTESHIFT (20) to get tte index 504 tte_index = ((vaddr - unsigned(pmap.min)) >> 20 ) 505 tte = pmap.tte[tte_index] 506 if verbose_level >= vSCRIPT: 507 print "First-level table (index {:d}):".format(tte_index) 508 if verbose_level >= vDETAIL: 509 for i in range(0, 4096): 510 ptr = unsigned(addressof(pmap.tte[i])) 511 val = unsigned(pmap.tte[i]) 512 print "{0: <#020x}:\t {1: <#020x}".format(ptr, val) 513 if (tte & 0x3) == 0x1: 514 paddr = _PmapWalkARMLevel2(tte, vaddr, verbose_level) 515 elif (tte & 0x3) == 0x2 : 516 paddr = _PmapWalkARMLevel1Section(tte, vaddr, verbose_level) 517 else: 518 paddr = 0 519 if verbose_level >= vSCRIPT: 520 print "Invalid First-Level Translation Table Entry: {0: #020x}".format(tte) 521 522 if verbose_level >= vHUMAN: 523 if paddr: 524 print "Translation of {:#x} is {:#x}.".format(vaddr, paddr) 525 else: 526 print "(no translation)" 527 528 return paddr 529 530def PmapWalkX86_64(pmapval, vaddr): 531 """ 532 params: pmapval - core.value representing pmap_t in kernel 533 vaddr: int - int representing virtual address to walk 534 """ 535 _PmapL4Walk(pmapval.pm_cr3, vaddr, config['verbosity']) 536 537def assert_64bit(val): 538 assert(val < 2**64) 539 540def PmapWalk(pmap, vaddr, verbose_level = vHUMAN): 541 if kern.arch == 'x86_64': 542 return PmapWalkX86_64(pmap, vaddr) 543 elif kern.arch == 'arm': 544 return PmapWalkARM(pmap, vaddr, verbose_level) 545 else: 546 raise NotImplementedError("PmapWalk does not support {0}".format(kern.arch)) 547 548@lldb_command('pmap_walk') 549def PmapWalkHelper(cmd_args=None): 550 """ Perform a page-table walk in <pmap> for <virtual_address>. 551 Syntax: (lldb) pmap_walk <pmap> <virtual_address> [-v] 552 Multiple -v's can be specified for increased verbosity 553 """ 554 if cmd_args == None or len(cmd_args) < 2: 555 raise ArgumentError("Too few arguments to pmap_walk.") 556 557 pmap = kern.GetValueAsType(cmd_args[0], 'pmap_t') 558 addr = unsigned(kern.GetValueFromAddress(cmd_args[1], 'void *')) 559 PmapWalk(pmap, addr, config['verbosity']) 560 return 561