예제 #1
0
    def scan(self, bdaddr, addr_type, include_descriptor: bool):
        """
        bdaddr - Remote BD_ADDR
        """
        def run_mainloop():
            mainloop.run()

        mainloop_thread = threading.Thread(target=run_mainloop, args=[])
        mainloop_thread.start()

        try:
            try:
                target = Peripheral(bdaddr,
                                    iface=self.devid,
                                    addrType=addr_type)
            except BTLEDisconnectError as e:
                logger.error("BTLEDisconnectError")
                print(ERROR_INDENT, e, sep='')
                return

            services = target.getServices()
            print("Number of services: %s\n\n" % len(services))

            # Show service
            for service in services:
                logger.debug('Start handle: {}'.format(service.hndStart))
                logger.debug('End handle: {}'.format(service.hndEnd))

                try:
                    characteristics = []
                    characteristics = service.getCharacteristics()
                except BTLEException as e:
                    logger.warning("BTLEException")
                    print(WARNING_INDENT, e, sep='')
                    # continue

                print(
                    blue('Service'), '(0x%04x - 0x%04x, %s characteristics)' %
                    (service.hndStart, service.hndEnd, len(characteristics)))
                print(
                    indent + 'Handle: 0x%04x' % service.hndStart
                )  # ", "\"attr handle\" by using gatttool -b <BD_ADDR> --primary
                print(indent + 'Type: (May be primary service 0x2800)')
                print(indent + 'Value (Service UUID): ',
                      blue(str(service.uuid).replace(sig_uuid_suffix, '')),
                      end=' ')
                try:
                    print(
                        '(' +
                        services_spec['0x' +
                                      ("%s" %
                                       service.uuid)[4:8].upper()]['Name'] +
                        ')', '\x1B[0m')
                except KeyError:
                    print('(' + red('unknown') + ')', '\x1B[0m')
                print(
                    indent +
                    'Permission: Read Only, No Authentication, No Authorization\n'
                )

                # Show characteristic
                for characteristic in characteristics:
                    descriptors = []
                    # 对每个 characteristic 都获取 descriptor 会很耗时
                    # 有些设备会因此断开连接。于是这里提供了一个是否获取 descriptor 的选项
                    if include_descriptor:
                        descriptors = characteristic.getDescriptors()

                    try:
                        print(indent + yellow('Characteristic'),
                              '(%s descriptors)' % len(descriptors))
                        #print('-'*8)
                        print(indent * 2 + 'Handle: %#06x' %
                              (characteristic.getHandle() - 1))
                        print(indent * 2 + 'Type: 0x2803 (Characteristic)')
                        print(indent * 2 + 'Value:')
                        print(indent * 3 + 'Characteristic properties:',
                              green(characteristic.propertiesToString()))
                        print(indent * 3 +
                              'Characteristic value handle: %#06x' %
                              characteristic.getHandle())
                        print(
                            indent * 3 + 'Characteristic UUID: ',
                            green(
                                str(characteristic.uuid).replace(
                                    sig_uuid_suffix, '')),
                            end=' '
                        )  # This UUID is also the type field of characteristic value declaration attribute.
                        try:
                            print('(' + characteristics_spec['0x' + (
                                "%s" %
                                characteristic.uuid)[4:8].upper()]['Name'] +
                                  ')')
                        except KeyError:
                            print('(' + red('unknown') + ')')
                        print(
                            indent * 3 +
                            'Permission: Read Only, No Authentication, No Authorization'
                        )

                        if characteristic.supportsRead():
                            print(indent + yellow('Characteristic value'))
                            print(indent * 2 + 'Handle:',
                                  green('%#06x' % characteristic.getHandle()))
                            print(
                                indent * 2 + 'Type:',
                                str(characteristic.uuid).replace(
                                    sig_uuid_suffix, ''))
                            print(indent * 2 + 'Value:',
                                  green(str(characteristic.read())))
                            print(
                                indent * 2 +
                                'Permission: Higher layer profile or implementation-specific'
                            )
                    except BTLEException as e:
                        print('        ' + str(e))

                    # Show descriptor
                    for descriptor in descriptors:
                        try:
                            print(indent + yellow('Descriptor'))
                            print(indent * 2 + 'Handle:',
                                  green('%#06x' % descriptor.handle))
                            print(indent * 2 + 'Type:',
                                  str(descriptor.uuid).replace(
                                      sig_uuid_suffix, ''),
                                  end=' ')
                            try:
                                print('(' + descriptors_spec['0x' + (
                                    "%s" %
                                    descriptor.uuid)[4:8].upper()]['Name'] +
                                      ')')
                            except KeyError:
                                print('(Unknown descriptor)')
                            print(indent * 2 + 'Value:',
                                  green(str(descriptor.read())))
                            print(indent * 2 + 'Permissions:')
                        except BTLEException as e:
                            print(indent * 2 + str(e))
                    print()
                print()

            # Set remote device untursted
            output = subprocess.check_output(' '.join(
                ['bluetoothctl', 'untrust', bdaddr]),
                                             stderr=STDOUT,
                                             timeout=60,
                                             shell=True)
            logger.info(output.decode())

            # output = subprocess.check_output(
            #     ' '.join(['sudo', 'systemctl', 'stop', 'bluetooth.service']),
            #     stderr=STDOUT, timeout=60, shell=True)

            # output = subprocess.check_output(
            #     ' '.join(['sudo', 'rm', '-rf', '/var/lib/bluetooth/' + \
            #               self.hci_bdaddr + '/' + bdaddr.upper()]),
            #     stderr=STDOUT, timeout=60, shell=True)

            # output = subprocess.check_output(
            #     ' '.join(['sudo', 'systemctl', 'start', 'bluetooth.service']),
            #     stderr=STDOUT, timeout=60, shell=True)
        finally:
            if self.agent_registered:
                self.agent_mgr_1_iface.UnregisterAgent(
                    ObjectPath(self.bluescan_agent.path))
                logger.info('Unregistered Agent object')

                mainloop.quit()
예제 #2
0
def pp_adv_phych_pdu(pdu: bytes, ch: int) -> list:
    '''Parse and print advertising physical channel PDU

    ref 
    BLUETOOTH CORE SPECIFICATION Version 5.2 | Vol 6, Part B page 2871, 
    2.3 ADVERTISING PHYSICAL CHANNEL PDU

    Advertising physical channel PDU
    +------------------+
    | Header | Payload |
    |--------|---------|
    | 16 b   | 1-255 B |
    +------------------+

    Header
    +-------------------------------------------------+
    | PDU Type | RFU | ChSel | TxAdd | RxAdd | Length |
    |----------|-----|-------|-------|-------|--------|
    | 4 b      | 1 b | 1 b   | 1 b   | 1 b   | 8 b    |
    +-------------------------------------------------+
    '''
    header = pdu[:2]
    payload = pdu[2:]

    pdu_type = (header[0] & PDU_TYPE_MSK) >> PDU_TYPE_POS
    rfu = (header[0] & RFU_MSK) >> RFU_POS
    ch_sel = (header[0] & CH_SEL_MSK) >> CH_SEL_POS
    tx_add = (header[0] & TX_ADD_MSK) >> TX_ADD_POS
    rx_add = (header[0] & RX_ADD_MSK) >> RX_ADD_POS

    addrs = []

    print("[{}] ".format(ch), end='')
    if pdu_type == ADV_IND:
        adv_a = payload[:6][::-1]
        addrs = [{
            'BD_ADDR': adv_a,
            'type': 'public' if tx_add == 0b0 else 'random'
        }]

        print("[{}]".format(blue('ADV_IND')))
        print("{} AdvA: {}".format('public' if tx_add == 0b0 else 'random',
                                   ':'.join('%02X' % b for b in adv_a)))
        # print("AdvData:", payload[6:])
    elif pdu_type == ADV_DIRECT_IND:
        adv_a = payload[:6][::-1]
        target_a = payload[6:][::-1]
        addrs = [
            {
                'BD_ADDR': adv_a,
                'type': 'public' if tx_add == 0b0 else 'random'
            },
            {
                'BD_ADDR': target_a,
                'type': 'public' if rx_add == 0b0 else 'random'
            },
        ]
        print("[{}]".format(blue('ADV_DIRECT_IND')))
        print("{} AdvA: {}".format('public' if tx_add == 0b0 else 'random',
                                   ':'.join('%02X' % b for b in adv_a)))
        print("{} TargetA: {}".format('public' if rx_add == 0b0 else 'random',
                                      ':'.join('%02X' % b for b in target_a)))
    elif pdu_type == ADV_NONCONN_IND:
        adv_a = payload[:6][::-1]
        addrs = [{
            'BD_ADDR': adv_a,
            'type': 'public' if tx_add == 0b0 else 'random'
        }]
        print("[{}]".format(red('ADV_NONCONN_IND')))
        print("{} AdvA: {}".format('public' if tx_add == 0b0 else 'random',
                                   ':'.join('%02X' % b for b in adv_a)))
        # print("AdvData:", payload[6:])
    elif pdu_type == ADV_SCAN_IND:
        adv_a = payload[:6][::-1]
        addrs = [{
            'BD_ADDR': adv_a,
            'type': 'public' if tx_add == 0b0 else 'random'
        }]
        print("[{}]".format(blue('ADV_SCAN_IND')))
        print("{} AdvA: {}".format('public' if tx_add == 0b0 else 'random',
                                   ':'.join('%02X' % b for b in adv_a)))
        # print("AdvData:", payload[6:])
    elif pdu_type == ADV_EXT_IND:
        print("[{}]".format(yellow('ADV_EXT_IND')))
        print("raw: {}".format(payload))
    elif pdu_type == SCAN_REQ:
        scan_a = payload[:6][::-1]
        adv_a = payload[6:][::-1]
        addrs = [
            {
                'BD_ADDR': scan_a,
                'type': 'public' if tx_add == 0b0 else 'random'
            },
            {
                'BD_ADDR': adv_a,
                'type': 'public' if rx_add == 0b0 else 'random'
            },
        ]
        print("[{}]".format(blue('SCAN_REQ')))
        print("{} ScanA: {}".format('public' if tx_add == 0b0 else 'random',
                                    ':'.join('%02X' % b for b in scan_a)))
        print("{} AdvA: {}".format('public' if rx_add == 0b0 else 'random',
                                   ':'.join('%02X' % b for b in adv_a)))
    elif pdu_type == SCAN_RSP:
        adv_a = payload[:6][::-1]
        addrs = [{
            'BD_ADDR': adv_a,
            'type': 'public' if tx_add == 0b0 else 'random'
        }]
        print("[{}]".format(blue('SCAN_RSP')))
        print("{} AdvA: {}".format('public' if tx_add == 0b0 else 'random',
                                   ':'.join('%02X' % b for b in adv_a)))
        # print("ScanRspData:", payload[6:])
    elif pdu_type == CONNECT_IND:
        init_a = payload[:6]
        adv_a = payload[6:12]
        print('init_a:', ':'.join('%02x' % b for b in init_a))
        print('adv_a:', ':'.join('%02x' % b for b in adv_a))
        addrs = [
            {
                'BD_ADDR': init_a,
                'type': 'public' if tx_add == 0b0 else 'random'
            },
            {
                'BD_ADDR': adv_a,
                'type': 'public' if rx_add == 0b0 else 'random'
            },
        ]
        print("[{}]".format(green('CONNECT_IND')))
        print("{} InitA: {}".format('public' if tx_add == 0b0 else 'random',
                                    ':'.join('%02X' % b for b in init_a)))
        print("{} AdvA: {}".format('public' if rx_add == 0b0 else 'random',
                                   ':'.join('%02X' % b for b in adv_a)))
        # print("LLData:", payload[12:])
    else:
        logger.warning("Unknown PDU type 0x%02x'%pdu_type")

    return addrs
예제 #3
0
    def print(self):
        if self.addr is None or self.addr_type is None:
            return

        print("Number of services: {}".format(len(self.services)))
        print()
        print()  # Two empty lines before Service Group

        # Prints each service group
        for service in self.services:
            uuid_str_for_show = self.uuid2str_for_show(service.declar.value)

            try:
                service_name = green(ServiceUuids[service.declar.value].name)
            except KeyError:
                service_name = red("Unknown")

            print(
                blue("Service"),
                "(0x{:04x} - 0x{:04x}, {} characteristics)".format(
                    service.start_handle, service.end_handle,
                    len(service.get_characts())))
            print(INDENT + blue("Declaration"))
            print(INDENT + "Handle: 0x{:04x}".format(service.start_handle))
            print(INDENT + "Type:   {:04X} ({})".format(
                service.declar.type.int16, service.declar.type.name))
            print(INDENT + "Value:  {} ({})".format(green(uuid_str_for_show),
                                                    service_name))
            print(INDENT + "Permissions:", service.declar.permissions_desc)
            print()  # An empty line before Characteristic Group

            # Prints each Gharacteristic group
            for charact in service.characts:
                uuid_str_for_show = self.uuid2str_for_show(
                    charact.declar.value.uuid)

                # if type(uuid) is int:
                #     uuid = "0x{:04X}".format(uuid)

                # value_declar_uuid = charact.value_declar.type
                # if type(value_declar_uuid) is int:
                #     value_declar_uuid = "0x{:04X}".format(value_declar_uuid)

                # if charact.declar.value.uuid != charact.value_declar.type:
                #     pass
                #     logger.warning("charact.declar.value['UUID'] != charact.value_declar.type")

                try:
                    charact_name = green(
                        GattAttrTypes[charact.declar.value.uuid].name)
                    # charact_name = green(charact_names[charact.declar.value.uuid])
                except KeyError:
                    charact_name = red("Unknown")

                print(INDENT + yellow("Characteristic"),
                      '({} descriptors)'.format(len(charact.descriptors)))
                print(INDENT * 2 + yellow("Declaration"))
                print(INDENT * 2 +
                      "Handle: 0x{:04x}".format(charact.declar.handle))
                print(INDENT * 2 + "Type:   {:04X} ({})".format(
                    charact.declar.type.int16, charact.declar.type.name))
                print(INDENT * 2 + "Value:")
                print(INDENT * 3 + "Properties: {}".format(
                    green(', '.join(charact.declar.get_property_names()))))
                print(INDENT * 3 + "Handle:    ",
                      green("0x{:04x}".format(charact.declar.value.handle)))
                print(INDENT * 3 + "UUID:       {} ({})".format(
                    green(uuid_str_for_show), charact_name))
                print(INDENT * 2 + "Permissions: {}\n".format(
                    charact.declar.permissions_desc))

                if charact.value_declar is not None:
                    try:
                        value_declar_name = GattAttrTypes[
                            charact.value_declar.type].name
                    except KeyError:
                        value_declar_name = "Unknown"

                    type_str_for_show = self.uuid2str_for_show(
                        charact.value_declar.type)

                    error = charact.value_declar.get_read_error()
                    if error != None:
                        value_print = red(error.desc)
                    elif charact.value_declar.value is None:
                        value_print = red('Unknown')
                    else:
                        value_print = green(str(charact.value_declar.value))

                    print(INDENT * 2 + yellow("Value declaration"))
                    print(
                        INDENT * 2 +
                        "Handle: 0x{:04x}".format(charact.value_declar.handle))
                    print(INDENT * 2 + "Type:   {} ({})".format(
                        type_str_for_show, value_declar_name))
                    print(INDENT * 2 + "Value:  {}".format(value_print))
                    print(INDENT * 2 + "Permissions: {}\n".format(
                        charact.value_declar.permissions_desc))

                # Prints each Characteristic Descriptor
                for descriptor in charact.get_descriptors():
                    uuid = descriptor.type
                    if type(uuid) is int:
                        uuid = "0x{:04X}".format(uuid)

                    error = descriptor.get_read_error()
                    if error != None:
                        value_print = red(error.desc)
                    else:
                        if descriptor.value is None:
                            value_print = red('Unknown')
                        else:
                            value_print = green(str(descriptor.value))

                    print(INDENT * 2 + yellow("Descriptor"))
                    print(INDENT * 2 + "Handle: {}".format(
                        green('0x{:04x}'.format(descriptor.handle))))
                    print(INDENT * 2 + "Type:   {} ({})".format(
                        green("{:04X}".format(descriptor.type.int16)),
                        yellow(descriptor.type.name)))
                    print(INDENT * 2 + "Value: ", value_print)
                    print(INDENT * 2 + "Permissions: {}\n".format(
                        descriptor.permissions_desc))
예제 #4
0
파일: gatt_scan.py 프로젝트: qemm/bluescan
    def scan(self, bdaddr, addr_type, include_descriptor: bool):
        #print("[Debug] target_addr:", self.target_bdaddr)
        #print("[Debug] iface:", self.iface)
        #print("[Debug] addr_type:", self.addr_type)
        target = Peripheral(bdaddr, iface=self.devid, addrType=addr_type)
        #print("[Debug] target", target)

        services = target.getServices()
        print("Number of services: %s\n\n" % len(services))

        # Show service
        for service in services:
            characteristics = service.getCharacteristics()

            print(blue('Service'),
                  '(%s characteristics)' % len(characteristics))
            print(
                '\tHandle:", "\"attr handle\" by using gatttool -b <BD_ADDR> --primary'
            )
            print('\tType: (May be primary service 0x2800)')
            print('\tValue (Service UUID): ', blue(str(service.uuid)), end=' ')
            try:
                print(
                    '(' +
                    services_spec['0x' +
                                  ("%s" % service.uuid)[4:8].upper()]['Name'] +
                    ')', '\x1B[0m')
            except KeyError:
                print('(' + red('unknown') + ')', '\x1B[0m')
            print(
                '\tPermission: Read Only, No Authentication, No Authorization\n'
            )

            # Show characteristic
            for characteristic in characteristics:
                descriptors = []
                # 对每个 characteristic 都获取 descriptor 会很耗时
                # 有些设备会因此断开连接。于是这里提供了一个是否获取 descriptor 的选项
                if include_descriptor:
                    descriptors = characteristic.getDescriptors()

                try:
                    print(yellow('\tCharacteristic'),
                          '(%s descriptors)' % len(descriptors))
                    #print('-'*8)
                    print('\t\tHandle: %#06x' %
                          (characteristic.getHandle() - 1))
                    print('\t\tType: 0x2803 (tCharacteristic)')
                    print('\t\tValue:')
                    print('\t\t\tCharacteristic properties:',
                          green(characteristic.propertiesToString()))
                    print('\t\t\tCharacteristic value handle: %#06x' %
                          characteristic.getHandle())
                    print(
                        '\t\t\tCharacteristic UUID: ',
                        green(str(characteristic.uuid)),
                        end=' '
                    )  # This UUID is also the type field of characteristic value declaration attribute.
                    try:
                        print('(' + characteristics_spec['0x' + (
                            "%s" % characteristic.uuid)[4:8].upper()]['Name'] +
                              ')')
                    except KeyError:
                        print('(' + red('unknown') + ')')
                    print(
                        '\t\tPermission: Read Only, No Authentication, No Authorization'
                    )

                    if characteristic.supportsRead():
                        print(yellow('\tCharacteristic value'))
                        print('\t\tHandle:',
                              green('%#06x' % characteristic.getHandle()))
                        print('\t\tType:', characteristic.uuid)
                        print('\t\tValue:', green(str(characteristic.read())))
                        print(
                            '\t\tPermission: Higher layer profile or implementation-specific'
                        )
                except BTLEException as e:
                    print('        ' + str(e))

                # Show descriptor
                for descriptor in descriptors:
                    try:
                        print('\tDescriptor')
                        print('\t\tHandle:',
                              green('%#06x' % descriptor.handle))
                        print('\t\tType:', descriptor.uuid, end=' ')
                        try:
                            print('(' + descriptors_spec['0x' + (
                                "%s" % descriptor.uuid)[4:8].upper()]['Name'] +
                                  ')')
                        except KeyError:
                            print('(Unknown descriptor)')
                        print('\t\tValue:', descriptor.read())
                        print('\t\tPermissions:')
                    except BTLEException as e:
                        print('\t\t' + str(e))
                print()
            print()