Пример #1
0
    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
Пример #2
0
    def _setupSockets(self):
        """
        Connect to the iOS Bluetooth device over usbmuxd and internalblued 
        """

        try:
            self.s_inject = self.mux.connect(self.interface, 1234)
        except MuxError:
            log.warn(
                "Could not connect to iOS proxy. Is internalblued running on the connected device?"
            )
            return False

        self.s_inject.settimeout(0.5)

        # with on iOS the send and receive sockets are the same
        self.s_snoop = self.s_inject

        # empty the socket (can sometimes still hold data if the previous execution
        # of internalblue was cancelled or crashed)
        try:
            self.s_inject.recv(1024)
        except socket.error:
            pass

        return True
Пример #3
0
    def device_list(self):
        """
        Get a list of connected devices
        """

        # prevent access on non-available socket if usbmuxd failed
        if self.muxconnecterror:
            return []

        if self.exit_requested:
            self.shutdown()

        if self.running:
            log.warn("Already running. Call shutdown() first!")
            return []

        # because we need to call process for every device that is connected
        # and we don't really know how much are connected, we just call process
        # 8 times (which should be a reasonable limit for the amount of connected
        # iOS devices) with a very short timeout.
        for i in range(0, 8):
            self.mux.process(0.01)

        self.devices = self.mux.devices
        if not self.devices:
            log.info("No iOS devices connected")

        device_list = []
        for dev in self.devices:
            dev_id = "iOS Device (" + dev.serial.decode("utf-8") + ")"
            device_list.append((self, dev, dev_id))

        return device_list
Пример #4
0
    def _sendThreadFunc(self):
        log.debug("Send Thread started.")
        while not self.exit_requested:
            # Little bit ugly: need to re-apply changes to the global context to the thread-copy
            context.log_level = self.log_level

            # Wait for 'send task' in send queue
            try:
                task = self.sendQueue.get(timeout=0.5)
            except queue2k.Empty:
                continue

            # Extract the components of the task
            h4type, data, queue, filter_function = task

            # Prepend UART TYPE and length.
            out = p8(h4type) + p8(len(data)) + data

            # Send command to the chip using IOBluetoothExtended framework
            h4type, data, queue, filter_function = task
            data = bytearray(data)
            opcode = format(data[1], "02x") + format(data[0], "02x")

            log.debug("Sending command: 0x" +
                      "".join(format(x, "02x")
                              for x in data) + ", opcode: " + opcode)

            if not (h4type == 0x01 or h4type == 0x02):
                log.warn("H4 Type {0} not supported by macOS Core!".format(
                    str(h4type)))
                if queue is not None:
                    queue.put(None)
                continue

            # if the caller expects a response: register a queue to receive the response
            if queue is not None and filter_function is not None:
                recvQueue = queue2k.Queue(1)
                self.registerHciRecvQueue(recvQueue, filter_function)

            # Sending command
            self.s_inject.sendto(out, ("127.0.0.1", self.hciport + 1))

            # if the caller expects a response:
            # Wait for the HCI event response by polling the recvQueue
            if queue is not None and filter_function is not None:
                try:
                    record = recvQueue.get(timeout=10)
                    hcipkt = record[0]
                    data = hcipkt.data
                except queue2k.Empty:
                    log.warn("_sendThreadFunc: No response from the firmware.")
                    data = None
                    self.unregisterHciRecvQueue(recvQueue)
                    continue

                queue.put(data)
                self.unregisterHciRecvQueue(recvQueue)

        log.debug("Send Thread terminated.")
Пример #5
0
    def finishStackDump(self):
        dump = flat(self.memdumps)
        log.warn("Stack dump @0x%08x written to %s!" %
                 (self.memdump_addr, self.stack_dump_filename))
        f = open(self.stack_dump_filename, "wb")
        f.write(dump)
        f.close()

        # Shut down:
        self.stack_dump_has_happend = True
Пример #6
0
    def local_connect(self):
        """
        """

        if not self.interface:
            log.warn("No HCI identifier is set")
            return False

        if not self._setupSockets():
            log.critical("HCI socket could not be established!")
            return False

        return True
Пример #7
0
    def finishStackDump(self):
        """
        Write the stack dump to a file once it is finished.
        """
        dump = flat(
            self.memdumps)  # flatten, as we have one entry per address chunk
        log.warn("Stack dump @0x%08x written to %s!" %
                 (self.memdump_addr, self.stack_dump_filename))
        f = open(self.stack_dump_filename, "wb")
        f.write(dump)
        f.close()

        # Shut down:
        self.stack_dump_has_happend = True
Пример #8
0
    def _recvThreadFunc(self):

        log.debug("Receive Thread started.")

        while not self.exit_requested:
            # Little bit ugly: need to re-apply changes to the global context to the thread-copy
            context.log_level = self.log_level

            # read record data
            try:
                data, addr = self.s_snoop.recvfrom(1024)
                record_data = bytearray(data)
            except socket.timeout:
                continue  # this is ok. just try again without error

            if not self.exit_requested:
                # Put all relevant infos into a tuple. The HCI packet is parsed with the help of hci.py.
                record = (
                    hci.parse_hci_packet(record_data),
                    0,
                    0,
                    0,
                    0,
                    0,
                )  # TODO not sure if this causes trouble?
                log.debug("Recv: " + str(record[0]))

                # Put the record into all queues of registeredHciRecvQueues if their
                # filter function matches.
                for (
                    queue,
                    filter_function,
                ) in (
                    self.registeredHciRecvQueues
                ):  # TODO filter_function not working with bluez modifications
                    try:
                        queue.put(record, block=False)
                    except queue.Full:
                        log.warn(
                            "recvThreadFunc: A recv queue is full. dropping packets..>"
                            + str(record_data)
                        )

                # Call all callback functions inside registeredHciCallbacks and pass the
                # record as argument.
                for callback in self.registeredHciCallbacks:
                    callback(record)

        log.debug("Receive Thread terminated.")
Пример #9
0
    def device_list(self):
        """
        Get a list of connected devices
        """

        if self.exit_requested:
            self.shutdown()

        if self.running:
            log.warn("Already running. Call shutdown() first!")
            return []

        # assume that a explicitly specified iPhone exists
        device_list = [(self, "mac", "mac")]

        return device_list
Пример #10
0
    def local_connect(self):
        """
        """
        if not self.host:
            log.warn("No BTstack daemon host defined")
            return False

        if not self.port:
            log.warn("No BTstack daemon port defined")
            return False

        if not self._setupSockets():
            log.critical("HCI socket could not be established!")
            return False

        return True
Пример #11
0
    def _setupSockets(self):
        """
        Connect to the iOS bluetooth device over internalblue-ios-proxy
        """

        self.s_inject = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        try:
            self.s_inject.connect((self.ios_addr, int(self.ios_port)))
            self.s_inject.settimeout(0.5)
        except socket.error:
            log.warn(
                "Could not connect to iPhone, is internalblue-ios-proxy running?"
            )
            return False

        # with ios proxy the send and receive sockets are the same
        self.s_snoop = self.s_inject

        return True
Пример #12
0
    def device_list(self):
        """
        Get a list of the connected devices
        """

        if self.exit_requested:
            self.shutdown()

        if self.running:
            log.warn("Already running. call shutdown() first!")
            return []

        if self.replay:
            return [(self, "adb_replay", "adb: ReplayDevice")]
        # Check for connected adb devices
        try:
            adb_devices = adb.devices()
        except ValueError:
            log.info(
                "Could not find devices with pwnlib. If you see devices with `adb devices`, try to remove the lines 'for field in fields[2:]:... = v' in `pwnlib/adb/adb.py`."
            )
            adb_devices = 0
        except:
            adb_devices = 0

        if adb_devices == 0 or len(adb_devices) == 0:
            log.info("No adb devices found.")
            return []

        # At least one device found
        log.info("Found multiple adb devices")

        # Enumerate over found devices and put them into an array of tupple
        # First index is a self reference of the class
        # Second index is the identifier which is passed to connect()
        # Third index is the label which is shown in options(...)
        device_list = []
        for d in adb_devices:
            device_list.append(
                (self, d.serial, "adb: %s (%s)" % (d.serial, d.model)))

        return device_list
Пример #13
0
    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
Пример #14
0
    def sendH4(self, h4type, data, timeout=0.5):
        """
        Send an arbitrary HCI packet by pushing a send-task into the
        sendQueue. This function blocks until the response is received
        or the timeout expires. The return value is the Payload of the
        HCI Command Complete Event which was received in response to
        the command or None if no response was received within the timeout.
        """

        queue = queue2k.Queue(1)

        try:
            self.sendQueue.put((h4type, data, queue, None), timeout=timeout)
            ret = queue.get(timeout=timeout)
            return ret
        except queue2k.Empty:
            log.warn("sendH4: waiting for response timed out!")
            return None
        except queue2k.Full:
            log.warn("sendH4: send queue is full!")
            return None
Пример #15
0
    def _recvThreadFunc(self):

        log.debug("Receive Thread started.")

        if self.write_btsnooplog:
            log.warn("Writing btsnooplog is not supported with iOS.")

        while not self.exit_requested:
            # Little bit ugly: need to re-apply changes to the global context to the thread-copy
            context.log_level = self.log_level

            # read record data
            try:
                received_data = self.s_snoop.recv(1024)
            except socket.timeout:
                continue  # this is ok. just try again without error

            log.debug("H4 Data: %s", received_data)

            (record_data,
             is_more) = self._getLatestH4Blob(new_data=received_data)
            while record_data is not None:
                # Put all relevant infos into a tuple. The HCI packet is parsed with the help of hci.py.
                record = (hci.parse_hci_packet(record_data), 0, 0, 0, 0, 0)

                log.debug("Recv: " + str(record[0]))

                # Put the record into all queues of registeredHciRecvQueues if their
                # filter function matches.
                for (
                        queue,
                        filter_function,
                ) in (
                        self.registeredHciRecvQueues
                ):  # TODO filter_function not working with bluez modifications
                    try:
                        queue.put(record, block=False)
                    except queue2k.Full:
                        log.warn(
                            "recvThreadFunc: A recv queue is full. dropping packets.."
                        )

                # Call all callback functions inside registeredHciCallbacks and pass the
                # record as argument.
                for callback in self.registeredHciCallbacks:
                    callback(record)

                # Check if the stackDumpReceiver has noticed that the chip crashed.
                if self.stackDumpReceiver.stack_dump_has_happend:
                    # A stack dump has happend!
                    log.warn(
                        "recvThreadFunc: The controller send a stack dump. stopping.."
                    )
                    self.exit_requested = True

                (record_data, is_more) = self._getLatestH4Blob()
                if not is_more:
                    break

        log.debug("Receive Thread terminated.")
Пример #16
0
    def _setupSockets(self):
        """
        Forward the HCI snoop and inject ports from the Android device to
        the host (using adb). Open TCP sockets (s_snoop, s_inject) to connect
        to the forwarded ports. Read the btsnoop header from the s_snoop
        socket in order to verify that the connection actually works correctly.
        """

        # In order to support multiple parallel instances of InternalBlue
        # (with multiple attached Android devices) we must not hard code the
        # forwarded port numbers. Therefore we choose the port numbers
        # randomly and hope that they are not already in use.
        self.hciport = random.randint(
            60000, 65534
        )  # minus 1, as we are using hciport + 1
        log.debug(
            "_setupSockets: Selected random ports snoop=%d and inject=%d"
            % (self.hciport, self.hciport + 1)
        )

        # Forward ports 8872 and 8873. Ignore log.info() outputs by the adb function.
        saved_loglevel = context.log_level
        context.log_level = "warn"
        try:
            adb.adb(["forward", "tcp:%d" % (self.hciport), "tcp:8872"])
            adb.adb(["forward", "tcp:%d" % (self.hciport + 1), "tcp:8873"])
        except PwnlibException as e:
            log.warn("Setup adb port forwarding failed: " + str(e))
            return False
        finally:
            context.log_level = saved_loglevel

        # Connect to hci injection port
        self.s_inject = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        try:
            self.s_inject.connect(("127.0.0.1", self.hciport + 1))
            self.s_inject.settimeout(0.5)
        except socket.error:
            log.warn("Could not connect to adb. Is your device authorized?")
            return False

        # Connect to hci snoop log port
        self.s_snoop = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.s_snoop.connect(("127.0.0.1", self.hciport))
        self.s_snoop.settimeout(0.5)

        # Read btsnoop header
        if self._read_btsnoop_hdr() == None:
            log.warn("Could not read btsnoop header")
            self.s_inject.close()
            self.s_snoop.close()
            self.s_inject = self.s_snoop = None
            context.log_level = "warn"
            adb.adb(["forward", "--remove", "tcp:%d" % (self.hciport)])
            adb.adb(["forward", "--remove", "tcp:%d" % (self.hciport + 1)])
            context.log_level = saved_loglevel
            return False
        return True
Пример #17
0
    def _teardownSockets(self):
        """
        Close s_snoop and s_inject sockets. Remove port forwarding with adb.
        """

        if self.s_inject != None:
            self.s_inject.close()
            self.s_inject = None
        if self.s_snoop != None:
            self.s_snoop.close()
            self.s_snoop = None

        saved_loglevel = context.log_level
        context.log_level = "warn"
        if self.hciport is not None:
            hciport = self.hciport
            try:
                adb.adb(["forward", "--remove", f"tcp:{hciport}"])
                adb.adb(["forward", "--remove", f"tcp:{hciport + 1}"])
            except PwnlibException as e:
                log.warn("Removing adb port forwarding failed: " + str(e))
                return False
            finally:
                context.log_level = saved_loglevel
Пример #18
0
    def bringHciDeviceUp(self, dev_id):
        """
        Uses HCIDEVUP ioctl to bring HCI device with id dev_id up.
        Requires root priviledges (CAP_NET_ADMIN).
        """

        if dev_id < 0 or dev_id > 16:
            log.warn("bringHciDeviceUp: Invalid device id: %d." % dev_id)
            return False

        # Open bluetooth socket to execute ioctl's:
        s = socket.socket(socket.AF_BLUETOOTH, socket.SOCK_RAW,
                          socket.BTPROTO_HCI)

        # Do ioctl(s, HCIDEVUP, dev_id) to bring device up:
        try:
            fcntl.ioctl(s.fileno(), HCIDEVUP, dev_id)
            s.close()
            log.info("Device with id=%d was set up successfully!" % dev_id)
            return True
        except IOError as e:
            s.close()
            log.warn("Error returned by ioctl: %s" % str(e))
            return False
Пример #19
0
    def _setupSerialSu(self):
        """
        To run on any rooted device, we can also use some shellscripting.
        This is slower but at least works on any device.
        Commands on a S10e with Samsung Stock ROM + Magisk + busybox:

             tail -f -n +0 /data/log/bt/btsnoop_hci.log | nc -l -p 8872

             nc -l -p 8873 >/sdcard/internalblue_input.bin
             tail -f /sdcard/internalblue_input.bin >>/dev/ttySAC1

        Locations of the Bluetooth serial interface and btsnoop log file might differ.
        The second part *could* be combined, but it somehow does not work (SELinux?).

        The ADB Python bindings will kill the processes automatically :)

        """

        # In sending direction, the format is different.
        self.serial = True

        saved_loglevel = context.log_level
        context.log_level = "warn"

        try:
            # check dependencies
            if adb.which("su") is None:
                log.critical("su not found, rooted smartphone required!")
                return False

            if adb.process(["su", "-c", "which", "nc"]).recvall() == "":
                log.critical("nc not found, install busybox!")
                return False

            # automatically detect the proper serial device with lsof
            logfile = (adb.process([
                "su", "-c",
                "lsof | grep btsnoop_hci.log | tail -1 | awk '{print $NF}'"
            ]).recvall().strip().decode("utf-8"))
            log.info("Android btsnoop logfile %s...", logfile)
            interface = (adb.process([
                "su", "-c",
                "lsof | grep bluetooth | grep tty | awk '{print $NF}'"
            ]).recvall().strip().decode("utf-8"))
            log.info("Android Bluetooth interface %s...", interface)

            if logfile == "":
                log.critical(
                    "Could not find Bluetooth logfile. Enable Bluetooth snoop logging."
                )
                return False

            if interface == "":
                log.critical(
                    "Could not find Bluetooth interface. Enable Bluetooth.")
                return False

            # spawn processes
            adb.process(
                ["su", "-c",
                 "tail -f -n +0 %s | netcat -l -p 8872" % logfile])
            adb.process([
                "su", "-c", "netcat -l -p 8873 >/sdcard/internalblue_input.bin"
            ])
            adb.process([
                "su", "-c",
                "tail -f /sdcard/internalblue_input.bin >>%s" % interface
            ])
            sleep(2)

        except PwnlibException as e:
            log.warn("Serial scripting setup failed: " + str(e))
            return False
        finally:
            context.log_level = saved_loglevel

        return True
Пример #20
0
    def _recvThreadFunc(self):
        """
        This is the run-function of the recvThread. It receives HCI events from the
        s_snoop socket. The HCI packets are encapsulated in btsnoop records (see RFC 1761).
        Received HCI packets are being put into the queues inside registeredHciRecvQueues and
        passed to the callback functions inside registeredHciCallbacks.
        The thread stops when exit_requested is set to True. It will do that on its own
        if it encounters a fatal error or the stackDumpReceiver reports that the chip crashed.
        """

        log.debug("Receive Thread started.")

        while not self.exit_requested:
            # Little bit ugly: need to re-apply changes to the global context to the thread-copy
            context.log_level = self.log_level

            # Read the record header
            record_hdr = b""
            while not self.exit_requested and len(record_hdr) < 24:
                try:
                    recv_data = self.s_snoop.recv(24 - len(record_hdr))
                    log.debug("recvThreadFunc: received bt_snoop data " +
                              bytes_to_hex(recv_data))
                    if len(recv_data) == 0:
                        log.info(
                            "recvThreadFunc: bt_snoop socket was closed by remote site. stopping recv thread..."
                        )
                        self.exit_requested = True
                        break
                    record_hdr += recv_data
                except socket.timeout:
                    pass  # this is ok. just try again without error

            if not record_hdr or len(record_hdr) != 24:
                if not self.exit_requested:
                    log.warn(
                        "recvThreadFunc: Cannot recv record_hdr. stopping.")
                    self.exit_requested = True
                break

            if self.write_btsnooplog:
                self.btsnooplog_file.write(record_hdr)
                self.btsnooplog_file.flush()

            orig_len, inc_len, flags, drops, time64 = struct.unpack(
                ">IIIIq", record_hdr)

            # Read the record data
            record_data = bytearray()
            while not self.exit_requested and len(record_data) < inc_len:
                try:
                    recv_data = self.s_snoop.recv(inc_len - len(record_data))
                    if len(recv_data) == 0:
                        log.info(
                            "recvThreadFunc: bt_snoop socket was closed by remote site. stopping.."
                        )
                        self.exit_requested = True
                        break
                    record_data += bytearray(recv_data)
                except socket.timeout:
                    pass  # this is ok. just try again without error

            if not record_data or len(record_data) != inc_len:
                if not self.exit_requested:
                    log.warn("recvThreadFunc: Cannot recv data. stopping.")
                    self.exit_requested = True
                break

            if self.write_btsnooplog:
                self.btsnooplog_file.write(record_data)
                self.btsnooplog_file.flush()

            try:
                parsed_time = self._btsnoop_parse_time(time64)
            except OverflowError:
                parsed_time = None

            # Put all relevant infos into a tuple. The HCI packet is parsed with the help of hci.py.
            record = (
                hci.parse_hci_packet(record_data),
                orig_len,
                inc_len,
                flags,
                drops,
                parsed_time,
            )

            log.debug("_recvThreadFunc Recv: [" + str(parsed_time) + "] " +
                      str(record[0]))

            # Put the record into all queues of registeredHciRecvQueues if their
            # filter function matches.
            for queue, filter_function in self.registeredHciRecvQueues:
                if filter_function == None or filter_function(record):
                    try:
                        queue.put(record, block=False)
                    except queue2k.Full:
                        log.warn(
                            "recvThreadFunc: A recv queue is full. dropping packets.."
                        )

            # Call all callback functions inside registeredHciCallbacks and pass the
            # record as argument.
            for callback in self.registeredHciCallbacks:
                callback(record)

            # Check if the stackDumpReceiver has noticed that the chip crashed.
            # if self.stackDumpReceiver and self.stackDumpReceiver.stack_dump_has_happend:
            # A stack dump has happend!
            # log.warn("recvThreadFunc: The controller sent a stack dump.")
            # self.exit_requested = True

        log.debug("Receive Thread terminated.")
Пример #21
0
#!/usr/bin/env python3

# Jiska Classen

# Get receive statistics on a Samsung Galaxy S8 for BLE connection events

from builtins import range
from internalblue.adbcore import ADBCore
import internalblue.hci as hci
import internalblue.cli as cli
from internalblue.utils.pwnlib_wrapper import log, asm, u8, u16
internalblue = ADBCore(serial=True)
device_list = internalblue.device_list()
if len(device_list) == 0:
    log.warn("No HCI devices connected!")
    exit(-1)
internalblue.interface = device_list[0][1] # just use the first device


"""
# _connTaskRxDone has a Patchram position, S8 fixed almost everything in BLE, because
# they had to for Bluetooth 5 compliance.
# The base address is 0x5E324, and this will jump into the Patchram.
# You need to adjust the RX_DONE_HOOK_ADDRESS in the beginning.
"""
#RX_DONE_HOOK_ADDRESS = 0x1344D0  # on S8 with Patchlevel May 1 2019 on stock ROM
#RX_DONE_HOOK_ADDRESS = 0x134500  # on S8 with Lineage OS Nightly from August 30 2019
RX_DONE_HOOK_ADDRESS = 0x134514  # on S8 with Patchlevel September 1 2019 on stock ROM
HOOKS_LOCATION = 0x210500
ASM_HOOKS = """
Пример #22
0
#!/usr/bin/env python2

# Dennis Mantz
from internalblue import Address
from internalblue.adbcore import ADBCore
from internalblue.utils.pwnlib_wrapper import log, asm
#internalblue = core.InternalBlue()

internalblue = ADBCore()
device_list = internalblue.device_list()
if len(device_list) == 0:
    log.warn("No ADB devices connected!")
    exit(-1)
internalblue.interface = device_list[0][1]  # just use the first device

PK_RECV_HOOK_ADDRESS = Address(0x2FED8)
PK_SEND_HOOK_ADDRESS = Address(0x030098)
GEN_PRIV_KEY_ADDRESS = Address(0x48eba)
HOOKS_LOCATION = 0xd7800
ASM_HOOKS = """
b pk_recv_hook
b pk_send_hook
b gen_priv_key

// overwrite y-coordinate of received PK point
pk_recv_hook:
    push {r0-r3,lr}
    strb.w  r0, [r4, 170]
    ldr r0, =0x205614
    mov r1, 6
    mov r2, 0
Пример #23
0
    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
Пример #24
0
    def _recvThreadFunc(self):
        """
        This is the run-function of the recvThread. It receives HCI events from the
        s_snoop socket. The HCI packets are encapsulated in btsnoop records (see RFC 1761).
        Received HCI packets are being put into the queues inside registeredHciRecvQueues and
        passed to the callback functions inside registeredHciCallbacks.
        The thread stops when exit_requested is set to True. It will do that on its own
        if it encounters a fatal error or the stackDumpReceiver reports that the chip crashed.
        """

        log.debug("Receive Thread started.")

        while not self.exit_requested:
            # Little bit ugly: need to re-apply changes to the global context to the thread-copy
            context.log_level = self.log_level

            # Read the record data
            try:
                record_data = self.s_snoop.recv(1024)
                record_data = bytearray(record_data)
            except socket.timeout:
                continue  # this is ok. just try again without error
            except Exception as e:
                log.critical(
                    "Lost device interface with exception {}, terminating receive thread..."
                    .format(e))
                self.exit_requested = True
                continue

            # btsnoop record header data:
            btsnoop_orig_len = len(record_data)
            btsnoop_inc_len = len(record_data)
            btsnoop_flags = 0
            btsnoop_drops = 0
            btsnoop_time = datetime.datetime.now()

            # Put all relevant infos into a tuple. The HCI packet is parsed with the help of hci.py.
            record = (
                hci.parse_hci_packet(record_data),
                btsnoop_orig_len,
                btsnoop_inc_len,
                btsnoop_flags,
                btsnoop_drops,
                btsnoop_time,
            )

            log.debug("_recvThreadFunc Recv: [" + str(btsnoop_time) + "] " +
                      str(record[0]))

            # Write to btsnoop file:
            if self.write_btsnooplog:
                btsnoop_record_hdr = struct.pack(
                    ">IIIIq",
                    btsnoop_orig_len,
                    btsnoop_inc_len,
                    btsnoop_flags,
                    btsnoop_drops,
                    self._btsnoop_pack_time(btsnoop_time),
                )
                with self.btsnooplog_file_lock:
                    self.btsnooplog_file.write(btsnoop_record_hdr)
                    self.btsnooplog_file.write(record_data)
                    self.btsnooplog_file.flush()

            # Put the record into all queues of registeredHciRecvQueues if their
            # filter function matches.
            for queue, filter_function in self.registeredHciRecvQueues:
                if filter_function is None or filter_function(record):
                    try:
                        queue.put(record, block=False)
                    except queue2k.Full:
                        log.warn(
                            "recvThreadFunc: A recv queue is full. dropping packets.."
                        )

            # Call all callback functions inside registeredHciCallbacks and pass the
            # record as argument.
            for callback in self.registeredHciCallbacks:
                callback(record)

            # Check if the stackDumpReceiver has noticed that the chip crashed.
            # if self.stackDumpReceiver.stack_dump_has_happend:
            # A stack dump has happend!
            # log.warn("recvThreadFunc: The controller send a stack dump.")
            # self.exit_requested = True

        log.debug("Receive Thread terminated.")
Пример #25
0
    def _setupSockets(self):
        """
        Linux already allows to open HCI sockets to Bluetooth devices,
        they include H4 information, we simply use it.
        """

        # Check if hci device is in state "UP". If not, set it to "UP" (requires root)
        device = [
            dev for dev in self.getHciDeviceList()
            if dev["dev_name"] == self.interface
        ]
        if len(device) == 0:
            log.warn("Device not found: " + self.interface)
            return False
        device = device[0]

        if device["dev_flags"] == 0:
            log.warn("Device %s is DOWN!" % self.interface)
            log.info("Trying to set %s to state 'UP' (requires root)" %
                     self.interface)
            if not self.bringHciDeviceUp(device["dev_id"]):
                log.warn("Failed to bring up %s." % self.interface)
                return False

        # TODO unload btusb module and check error messages here to give the user some output if sth fails

        # Connect to HCI socket
        self.s_snoop = socket.socket(socket.AF_BLUETOOTH, socket.SOCK_RAW,
                                     socket.BTPROTO_HCI)
        self.s_snoop.setsockopt(socket.SOL_HCI, socket.HCI_DATA_DIR, 1)
        self.s_snoop.setsockopt(socket.SOL_HCI, socket.HCI_TIME_STAMP, 1)
        """
        struct hci_filter {
            uint32_t type_mask;     -> 4
            uint32_t event_mask[2]; -> 8
            uint16_t opcode;        -> 2
        };
        """
        # TODO still seems to only forward incoming events?!
        self.s_snoop.setsockopt(
            socket.SOL_HCI,
            socket.HCI_FILTER,
            b"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x00\x00\x00\x00",
        )  # type mask, event mask, event mask, opcode

        interface_num = device["dev_id"]
        log.debug("Socket interface number: %s" % interface_num)
        self.s_snoop.bind((interface_num, ))
        self.s_snoop.settimeout(2)
        log.debug("_setupSockets: Bound socket.")

        # same socket for input and output (this is different from adb here!)
        self.s_inject = self.s_snoop

        # Write Header to btsnoop file (if file is still empty):
        if self.write_btsnooplog and self.btsnooplog_file.tell() == 0:
            # BT Snoop Header: btsnoop\x00, version: 1, data link type: 1002
            btsnoop_hdr = (b"btsnoop\x00" + p32(1, endian="big") +
                           p32(1002, endian="big"))
            with self.btsnooplog_file_lock:
                self.btsnooplog_file.write(btsnoop_hdr)
                self.btsnooplog_file.flush()

        return True
Пример #26
0
    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)