def handleNexus5StackDump(self, hcipkt): checksum_correct = self.verifyChecksum(hcipkt.data[5:]) packet_type = u8(hcipkt.data[4]) if packet_type == 0x2C: data = hcipkt.data[6:] values = [u32(data[i:i + 4]) for i in range(0, 64, 4)] log.debug("Stack Dump (%s):\n%s" % ( "checksum correct" if checksum_correct else "checksum NOT correct", "\n".join([hex(x) for x in values]), )) if data[0] == "\x02": # This is the second stack dump event (contains register values) log.warn("Received Stack-Dump Event (contains %d registers):" % (u8(data[1]))) registers = ( "pc: 0x%08x lr: 0x%08x sp: 0x%08x r0: 0x%08x r1: 0x%08x\n" % (values[2], values[3], values[1], values[4], values[5])) registers += ( "r2: 0x%08x r3: 0x%08x r4: 0x%08x r5: 0x%08x r6: 0x%08x\n" % tuple(values[6:11])) log.warn(registers) return True elif packet_type == 0xF0: # RAM dump self.handleRamDump(hcipkt.data[10:]) elif packet_type == 0x4C: # RAM dump (last frame) self.handleRamDump(hcipkt.data[10:]) # This is the last pkt ouput: self.finishStackDump() return True return False
def from_connection_buffer(connection): # Possible TODO: Convert this to a Katai Struct parser with a proper .ksy grammar. return ConnectionInformation( u32(connection[:4]), connection[0x28:0x2E][::-1], u32(connection[0x4C:0x50]), u32(connection[0x1C:0x20]) & 1 << 15 == 0, u16(connection[0x64:0x66]), connection[0x78:0x88], u8(connection[0xA7:0xA8]), connection[0x68:0x68 + u8(connection[0xA7:0xA8])], u8(connection[0x9C:0x9D]) - 127, connection[0x30:0x38], connection[0x38:0x40], connection[0x0C:0x0D], )
def handleRamDump(self, data): """ Data should be a byte string containing the address (4 byte) followed by the actual ram dump (at this address) """ addr = u32(data[:4]) if self.memdump_addr == None: self.memdump_addr = addr self.memdumps[addr - self.memdump_addr] = data[4:] log.debug("Stack dump handling addr %08x", addr - self.memdump_addr)
def _read_btsnoop_hdr(self): """ Read the btsnoop header (see RFC 1761) from the snoop socket (s_snoop). """ data = self.s_snoop.recv(16) if len(data) < 16: return None if (self.write_btsnooplog) and self.btsnooplog_file.tell() == 0: self.btsnooplog_file.write(data) self.btsnooplog_file.flush() btsnoop_hdr = ( data[:8], u32(data[8:12], endian="big"), u32(data[12:16], endian="big"), ) log.debug("BT Snoop Header: %s, version: %d, data link type: %d" % btsnoop_hdr) return btsnoop_hdr
def handleS10StackDump(self, hcipkt): """ Packets in stack dump: 1b 03 90: contains pc and r0 1b 03 9c 1b 03 00 (x3) 1b 03 f0 (whole ram) """ checksum_correct = self.verifyChecksum(hcipkt.data[3:]) packet_type = u8(hcipkt.data[2]) if packet_type == 0x90: data = hcipkt.data[4:] values = [u32(data[i:i + 4]) for i in range(0, 64 * 2, 4)] log.debug("Stack Dump (%s):\n%s" % ( "checksum correct" if checksum_correct else "checksum NOT correct", "\n".join([hex(x) for x in values]), )) # Values different than in other stack dump formats, experimental output! log.warn("Received S10 Stack-Dump Event (contains %d registers):" % (u8(data[1]))) registers = ( "pc: 0x%08x lr: 0x%08x sp: 0x%08x r0: 0x%08x r1: 0x%08x\n" % (values[16], values[17], values[23], values[19], values[20])) registers += ( "r2: 0x%08x r3: 0x%08x r4: 0x%08x r5: 0x%08x r6: 0x%08x\n" % (values[21], values[22], values[23], values[24], values[25])) log.warn(registers) return True # log.info("%x" % u32(hcipkt.data[8:12])) # no last packet for S10e, just the size counts here... also is sometimes longer and sometimes shorter if packet_type == 0xF0 and u32(hcipkt.data[8:12]) == 0x230080: # This is the last pkt ouput: self.finishStackDump() return True return False
def handleEvalStackDump(self, hcipkt): """ Handles a core dump from the evaluation board. To trigger a dump execute: sendhcicmd 0xfc4e e81e2000 This executes some memory set to ffff which is an invalid command. Many events like executing address 0x0 will only crash the chip but not trigger a proper stack dump. The evaluation board has quite a lot of memory, RAM dump takes ages... dbfw_coredump_exception_cm3() generates the following dumps: 2c: CoreDumpInfo 2c: CoreDumpCPURegs 90: CoreDumpCPURegsExtend f0: CoreDumpRAMImage 78: CoreDumpRAMImage EOF 9c: CoreDumpHWRegs 01: CoreDumpEnd :param hcipkt: stack dump packet :return: returns True if dump could be decoded. """ checksum_correct = self.verifyChecksum(hcipkt.data[3:]) packet_type = u8(hcipkt.data[2]) log.debug("packet type %x", packet_type) # TODO CoreDumpInfo (shows LMP/HCI version, memory dumps) # CoreDumpCPURegs if packet_type == 0x2C: data = hcipkt.data[4:] values = [u32(data[i:i + 4]) for i in range(0, 64, 4)] log.debug("Stack Dump (%s):\n%s" % ( "checksum correct" if checksum_correct else "checksum NOT correct", "\n".join([hex(x) for x in values]), )) if data[0] == "\x02": # This is the second stack dump event (contains register values) log.warn( "Received Evaluation Stack-Dump Event (contains %d registers):" % (u8(data[1]))) registers = ( "pc: 0x%08x lr: 0x%08x sp: 0x%08x r0: 0x%08x r1: 0x%08x\n" % (values[2], values[3], values[1], values[4], values[5])) registers += ( "r2: 0x%08x r3: 0x%08x r4: 0x%08x r5: 0x%08x r6: 0x%08x\n" % tuple(values[6:11])) log.warn(registers) return True # CoreDumpRAMImage # TODO: Eval board produces this twice: # for 0x200000+0x50000 and 0x270000+0x10000 elif packet_type == 0xF0: self.handleRamDump(hcipkt.data[8:]) return True # Last packet produced by CoreDumpRAMImage elif packet_type == 0x78: # RAM dump (last frame), TODO not sure if this works # This is the last pkt ouput: log.info("End of stackdump block...") self.finishStackDump() return True # On a Raspberry Pi 3, the last packet of a stack dump is '1b0340df0338'.... so it's 0x40 elif packet_type == 0xE8: # FIXME Raspi memdump is divided in two parts! # address change from 0001fe38 to packet type e8 and then it's computing addr -0130000 # negative addr does not work with finishStackDump() # so even though the last packet is 0x40, let's just finish on 0xe8 log.info( "End of first stackdump block, writing to file and skipping second..." ) self.finishStackDump() return True return False
def getHciDeviceList(self): # type: () -> List[Device] """ Get a list of available HCI devices. The list is obtained by executing ioctl syscalls HCIGETDEVLIST and HCIGETDEVINFO. The returned list contains dictionaries with the following fields: dev_id : Internal ID of the device (e.g. 0) dev_name : Name of the device (e.g. "hci0") dev_bdaddr : MAC address (e.g. "00:11:22:33:44:55") dev_flags : Device flags as decimal number dev_flags_str : Device flags as String (e.g. "UP RUNNING" or "DOWN") """ # Open Bluetooth socket to execute ioctl's: try: s = socket.socket(socket.AF_BLUETOOTH, socket.SOCK_RAW, socket.BTPROTO_HCI) # Ticket 6: does not run on Windows with Kali subsystem except socket.error: log.warn( "Opening a local Bluetooth socket failed. Not running on native Linux?" ) return [] # Do ioctl(s,HCIGETDEVLIST,arg) to get the number of available devices: # arg is struct hci_dev_list_req (/usr/include/bluetooth/hci.h) arg = p32(16) # dl->dev_num = HCI_MAX_DEV which is 16 (little endian) arg += b"\x00" * (8 * 16) devices_raw = fcntl.ioctl(s.fileno(), HCIGETDEVLIST, arg) num_devices = u16(devices_raw[:2]) log.debug("Found %d HCI devices via ioctl(HCIGETDEVLIST)!" % num_devices) device_list = [] for dev_nr in range(num_devices): dev_struct_start = 4 + 8 * dev_nr dev_id = u16(devices_raw[dev_struct_start:dev_struct_start + 2]) # arg is struct hci_dev_info (/usr/include/bluetooth/hci.h) arg = p16(dev_id) # di->dev_id = <device_id> arg += b"\x00" * 20 # Enough space for name, bdaddr and flags dev_info_raw = bytearray( fcntl.ioctl(s.fileno(), HCIGETDEVINFO, arg)) dev_name = dev_info_raw[2:10].replace(b"\x00", b"").decode() dev_bdaddr = ":".join( ["%02X" % x for x in dev_info_raw[10:16][::-1]]) dev_flags = u32(dev_info_raw[16:20]) if dev_flags == 0: dev_flags_str = "DOWN" else: dev_flags_str = " ".join([ name for flag, name in zip( bin(dev_flags)[2:][::-1], [ "UP", "INIT", "RUNNING", "PSCAN", "ISCAN", "AUTH", "ENCRYPT", "INQUIRY", "RAW", "RESET", ], ) if flag == "1" ]) device_list.append({ "dev_id": dev_id, "dev_name": dev_name, "dev_bdaddr": dev_bdaddr, "dev_flags": dev_flags, "dev_flags_str": dev_flags_str, }) s.close() return cast("List[Device]", device_list)