LOADING

加载过慢请开启缓存 浏览器默认开启

BLE安全学习基础

协议栈基础介绍

一个BLE应用首先需要一个支持BLE射频的芯片,然后还需要提供一个与此芯片配套的BLE协议栈,最后基于协议栈开发自己的应用。BLE协议栈是连接芯片和应用的桥梁,是实现整个BLE应用的关键。BLE协议栈主要用来对你的应用数据进行层层封包,以生成一个满足BLE协议的空中数据包,也就是说,把应用数据包裹在一系列的帧头(header)和帧尾(tail)中。

蓝牙协议规定了两个层次的协议,分别为蓝牙核心协议(Bluetooth Core)和蓝牙应用层协议(Bluetooth Application)。蓝牙核心协议关注对蓝牙核心技术的描述和规范,它只提供基础的机制,并不关心如何使用这些机制;蓝牙应用层协议,是在蓝牙核心协议的基础上,根据具体的应用需求,百花齐放,定义出各种各样的策略,如FTP、文件传输、局域网等等。

蓝牙核心协议(Bluetooth Core)又包含BLE Controller和BLE Host两部分。这两部分在不同的蓝牙技术中(BR/EDR、AMP、LE),承担角色略有不同,但大致的功能是相同的。Controller负责定义RF、Baseband等偏硬件的规范,并在这之上抽象出用于通信的逻辑链路(Logical Link);Host负责在逻辑链路的基础上,进行更为友好的封装,这样就可以屏蔽掉蓝牙技术的细节,让Bluetooth Application更为方便的使用。

画板

BLE低功耗蓝牙核心协议层详解(Bluetooth Core)

**物理层(Physical Layer,简写 PHY):**PHY用来指定BLE所用的无线频段,调制解调方式和方法等。例如是1Mbps自适应跳频的GFSK射频,工作于免许可证的2.4GHz ISM(工业、科学与医疗)频段。 PHY层做得好不好,直接决定整个BLE芯片的功耗,灵敏度以及selectivity等射频指标。

链路层(Link Layer,简写 LL):LL是BLE协议栈的核心。LL要层要做的事情很多, 比如具体选择哪个射频通道进行通信,怎么识别空中数据包,具体在哪个时间点把数据包发送出去,怎么保证数据的完整性,ACK如何接收,如何进行重传,以及如何对链路进行管理和控制等等。LL层只负责把数据发出去或者收回来,对数据进行怎样的解析则交给上面的GAP或者GATT。

主机控制接口层(Host Controller Interface,简写 HCI):HCI是可选的,HCI主要用于2颗芯片实现BLE协议栈的场合,用来规范两者之间的通信协议和通信命令等。

**通用访问配置文件层(Generic access profile,简写GAP):**GAP是对LL层payload(有效数据包)如何进行解析的两种方式中的一种,而且只有简单的那一种,GAP简单的对LL的payload进行一些规范和定义,因此GAP能实现的功能极其有限。GAP目前主要用来进行广播,扫描和发起连接等。

逻辑链路控制及自适应协议层(Logical Link Control and Adaptation Protocol,简写 L2CAP):L2CAP对LL惊醒了一次简单封装,LL只关心传输的数据本身,L2CAP就是要区分是加密通道还是普通通道,同时还对连接间隔进行管理。

安全管理层(Security Manager,简写 SM):SM用来管理BLE连接的加密和安全。入和保证连接的安全性同时不影响用户的体验这些都是SMP要考虑的工作

属性协议层(Attribute protocol,简写 ATT):ATT层用来定义用户命令及命令操作的数据,比如读取某个数据或者写某个数据。BLE引用了attribute概念用来描述一条条的数据。attribute除了定义数据,同时定义该数据可以使用的ATT命令,因此这一层被称为ATT层

通用属性配置文件层(Generic Attribute profile,简写 GATT): GATT用来规范attribute中的数据内容并运用group(分组)的概念对attribute进行分类管理。没有GATT,BLE协议栈也能跑,但是互联互通就会出现问题

BLE协议栈如何完成发送任务

假设存在设备A和设备B, 设备A要把自己目前的电量状态83%(十六进制表示为0x53)发给设备B 。对于开发者来说这个过程越简单越好,最好是直接调用一个API就行, 比如send(0x53),实际上我们的BLE协议栈就是这样设计的,开发者只需调用send(0x53)就可以把数据发送出去了,其余的事情BLE协议栈帮你搞定。很多人会想,BLE协议栈是不是直接在物理层就把0x53发出去,就如下图所示:

但是这种方式实际是不可行的。首先它没有考虑使用哪个射频信道进行传输,不更改API的情况下我们只能对协议栈进行分层,为此引入LL层,开发者还是调用send(0x53),send(0x53)再调用send_LL(0x53,2402M) 。 这里还有一个问题,设备B怎么知道这个数据包是发给自己的还是其他人的,为此BLE引入access address概念,用来指明接收者身份,其中,0x8E89BED6这个access address比较特殊,它表示要发给周边所有设备,即广播。如果你要一对一的进行通信(BLE协议将其称为连接),即设备A的数据包只能设备B接收,同样设备B的数据包只能设备A接收,那么就必须生成一个独特的随机access address以标识设备A和设备B两者之间的连接。

广播方式

假设设备A为advertiser(广播者) , 设备B叫scanner或者observer(扫描者)。 广播状态下设备A的LL层API将变成send_LL(0x53,2402M, 0x8E89BED6) 。 由于设备B可以同时接收到很多设备的广播,因此数据包还必须包含设备A的device address(0xE1022AAB753B)以确认该广播包来自设备A,为此send_LL参数需要变成(0x53,2402M, 0x8E89BED6, 0xE1022AAB753B)。 LL层还要检查设备的完整性, 即数据在传输过程中有没有发生窜改,为此引入CRC24对数据包进行检验 (假设为0xB2C78E) 。同时为了调制解调电路工作更高效,每一个数据包的最前面会加上1个字节的preamble(前导帧),preamble一般为0x55或者0xAA。这样,整个空中包就变成(注:空中包用小端模式表示(小端模式低位字节排放在内存的低地址端,高位字节排放在内存的高地址端。)):

上面这个数据包还有如下问题:

  • 没有对数据包进行分类组织,设备B无法找到自己想要的数据0x53。为此我们需要在access address之后加入两个字段:LL header和长度字节。LL header用来表示数据包的LL类型,长度字节用来指明payload的长度
  • 设备B什么时候开启射频窗口以接收空中数据包?如上图case1所示,当设备A的数据包在空中传输的时候,设备B把接收窗口关闭,此时通信将失败;同样对case2来说,当设备A没有在空中发送数据包时,设备B把接收窗口打开,此时通信也将失败。只有case3的情况,通信才能成功,即设备A的数据包在空中传输时,设备B正好打开射频接收窗口,此时通信才能成功,换句话说,LL层还必须定义通信时序
  • 当设备B拿到数据0x53后,该如何解析这个数据呢?它到底表示湿度还是电量,还是别的意思?这个就是GAP层要做的工作。 GAP层引入了LTV(Length-Type-Value)结构来定义数据,比如020105,02-长度,01-类型(强制字段,表示广播flag,广播包必须包含该字段),05-值 。由于广播包最大只能为31个字节,它能定义的数据类型极其有限,像这里说的电量,GAP就没有定义,因此要通过广播方式把电量数据发出去,只能使用供应商自定义数据类型0xFF,即04FF590053,其中04表示长度,FF表示数据类型(自定义数据),0x0059是供应商ID(自定义数据中的强制字段),0x53就是我们的数据(设备双方约定0x53就是表示电量,而不是其他意思)。
  • 最终空中传输的数据包将变成:
  • AAD6BE898E600E3B75AB2A02E102010504FF5900538EC7B2
    • AA – 前导帧(preamble)
    • D6BE898E – 访问地址(access address)
    • 60 – LL帧头字段(LL header)
    • 0E – 有效数据包长度(payload length)
    • 3B75AB2A02E1 – 广播者设备地址(advertiser address)
    • 02010504FF5900**53 – **广播数据
    • 8EC7B2 – CRC24值

有了PHY,LL,和GAP就可以发送广播包了,但是还是会有几个限制

  • 1.无法进行一对一双向通信(广播是一对多通信,而且是单方向的)
  • 不支持组包和拆包,无法传输大数据
  • 通信不可靠且效率低下。广播信道不能太多否则导致扫描段效率低下。为此 BLE只使用37(2402MHz) /38(2426MHz) /39(2480MHz)三个信道进行广播和扫描,因此广播不支持跳频。由于广播是一对多的,所以广播也无法支持ACK。这些都使广播通信变得不可靠。
  • 扫描端功耗高。由于扫描端不知道设备端何时广播,也不知道设备端选用哪个频道进行广播,扫描端只能拉长扫描窗口时间,并同时对37/38/39三个通道进行扫描,这样功耗就会比较高。

而连接可以解决以上问题。

BLE连接方式

什么叫连接?像UART很容易理解,用线(rx和tx等)把设备A和设备B相连,就叫做连接。所谓设备A和设备B建立蓝牙连接就是指两个设备一对一同步成功,其具体包含一下几个方面

  1. 设备A和B对接下来使用的物理信道一致
  2. 设备A和设备B双方建立一个共同的时间锚点,也就是说把双方的时间原点变成同一个点
  3. 设备A和B两者时钟同步成功,即双方都知道对方什么时候发送数据包什么时候接收数据包
  4. 连接成功后,设备A和B通信流程如图所示

如图所示, 一旦设备A和设备B连接成功(此种情况下,我们把设备A称为Master或者Central,把设备B称为Slave或者Peripheral) ,设备A将周期性以CI(connection interval)为间隔向设备B发送数据包,而设备B也周期性地以CI为间隔打开射频接收窗口以接收设备A的数据包。 同时按照蓝牙spec要求,设备B收到设备A数据包150us后设备B切换发送状态把自己的数据发给设备A;设备A则切换到接收状态接收设备B发过来的数据。可以看到连接状态下设备A和B的射频发送和接收窗口都是周期性的有计划的开和关并且开的时间非常短从而大大降低设备功率

  • 对开发者来说,很简单,他只需要调用send(0x53)
  • GATT层定义数据的类型和分组,方便起见,我们用0x0013标识电量这种数据类型,这样GATT层把数据打包成130053(小端模式)
  • ATT层用来选择具体的通信命令,比如读写 比如读/写/notify/indicate等,这里选择notify命令0x1B,这样数据包变成了:1B130053
  • L2CAP用来指定connection interval(连接间隔),比如每10ms同步一次(CI不体现在数据包中),同时指定逻辑通道编号0004(表示ATT命令),最后把ATT数据长度0x0004加在包头,这样数据就变为:040004001B130053
  • LL层要做的工作很多,首先LL层需要指定用哪个物理信道进行传输(物理信道不体现在数据包中),然后再给此连接分配一个**Access address(0x50655DAB)**以标识此连接只为设备A 和设备B 直连服务,然后加上LL header和payload length字段,LL header标识此packet为数据packet,而不是control packet等,payload length为整个L2CAP字段的长度,最后加上CRC24字段,以保证整个packet的数据完整性,所以数据包最后变成:

o AAAB5D65501E08040004001B130053D550F6

o AA – 前导帧(preamble)

o 0x50655DAB – 访问地址(access address)

o 1E – LL帧头字段(LL header)

o 08 – 有效数据包长度(payload length)

o 04000400 – ATT数据长度,以及L2CAP通道编号

o 1B – notify command

o 0x0013 – 电量数据handle

o 0x53 – 真正要发送的电量数据

o 0xF650D5 – CRC24值

BLE工作流程

1.角色

BLE设备角色主要分为两种角色,主机(Master或Central)和从机(Peripheral),当主机和从机建立连接之后才能相互收发数据

  • 主机,主机可以发起对从机的扫描连接。例如手机,通常作为BLE的主机设备
  • 从机,从机只能广播并等待主机的连接。例如智能手环,是作为BLE的从机设备

另外还有观察者(Observer)和广播者(Broadcaster),这两种角色不常使用,但也十分有用,例如iBeacon,就可以使用广播者角色来做,只需要广播特定内容即可。

  • 观察者,观察者角色监听空中的广播事件,和主机唯一的区别是不能发起连接,只能持续扫描从机。
  • 广播者,广播者可以持续广播信息,和从机的唯一区别是不能被主机连接,只能广播数据

蓝牙协议栈没有限制设备的角色范围,同一个BLE设备,可以作为主机,也可以作为从机,我们称之为主从一体,主从一体的好处是,每个BLE设备都是对等的,可以发起连接,也可以被别人连接,更加实用。

2.广播

广播是指从机每经过一个时间间隔发送一次广播数据包,这个时间间隔称为广播间隔,这个广播动作叫做广播事件,只有当从机处于广播状态时,主机才能发现该从机。 在每个广播事件中,广播包会分别在37,38和39三个信道上依次广播,如下图所示。

广播时间间隔的范围是从20ms到10.24s,广播间隔影响建立连接的时间。广播间隔越大,连接的时间越长。

另外BLE链路层会在两个广播事件之间添加一个010ms的随机延时,保证多个设备广播时,不会一直碰撞广播。也就是说,设置100ms的广播间隔,实际上两次广播事件的时间间隔可能是100110ms之间的任意时间。

广播数据包最多能携带31个字节的数据,一般包含可读的设备名称,设备是否可连接等信息。

当主机收到从机广播的数据包后,它可以再发送获取更多数据包的请求,这个时候从机将广播扫描回应数据包,扫描回应数据包和广播包一样,可以携带31个字节的数据。

提示:蓝牙4.x,广播有效载荷最多是31个字节。而在蓝牙5.0中,通过添加额外的广播信道和新的广播PDU,将有效载荷增加到了255个字节

3.扫描

扫描是主机监听从机广播数据包和发送扫描请求的过程,主机通过扫描,可以获取到从机的广播包以及扫描回应数据包,主机可以对已扫描到的从机设备发起连接请求,从而连接从机设备并通信。 扫描动作有两个比较重要的时间参数:扫描窗口和扫描间隔,如果扫描窗口等于扫描间隔,那么主机将一直处于扫描状态之中,持续监听从机广播包。

  • 被动扫描,主机监听广播信道的数据,当接收到广播包时,协议栈将向上层(也就是应用层,用户可编程)传递广播包。
  • 主动扫描,主动扫描除了完成被动扫描的动作外,还会向从机发送一个扫描请求,从机收到该请求时,会再次发送一个称作扫描回应的广播包。

所以,主动扫描比被动扫描,可以多收到扫描回应数据包。

4.连接

在BLE连接中,使用跳频方案,两个设备在特定时间,特定频道上彼此发送和接收数据。这些设备稍后在新的通道(协议栈链路层处理通道切换)上通过这个约定的时间相遇。这次用于收发数据的相遇被称为连接事件。如果没有要发送或接收的应用数据则交换链路层数据来维护连接。两个连接事件之间的事件跨度称为连接间隔,是以1.25 ms为单位,范围从最小值7.5 ms到最大值4.0 s

4.1连接参数

Connection Interval连接间隔,两次连接事件之间的时间间隔称为连接间隔。1.25 ms为单位,范围从最小值7.5 ms到最大值4.0 s

Slave Latency从机延迟,如果从机没有要发送的数据,则可以跳过连接事件,继续保持睡眠节省电量。

Supervision Time-out监控超时,是两次成功连接事件之间的最长时间。如果在此时间内没有成功的连接事件,设备将终止连接并返回到未连接状态。该参数值以10 ms为单位,监控超时值可以从最小值10(100 ms)到3200(32.0 s)。超时必须大于有效的连接间隔。

4.2连接参数更新请求

连接参数由主机发起连接的时候提供,如果从机对连接参数有自己的要求,例如要求更低的功耗,或者更高的通信速率等,从机可以向主机发送连接参数更新请求。

从机可以在连接后的任何时候发起连接参数更新请求,但最好不要在主从建立连接后立刻发起,建议延迟5s左右再发送请求。

连接参数更新请求可以修改:Connection Interval连接间隔,Slave Latency从机延迟,Supervision Time-out监控超时。

4.3有效连接间隔

Effective Connection Interval有效连接间隔等于两个连接事件之间的时间跨度,假设从机跳过最大数量的连接事件,且允许从机延迟(如果从机延迟设置为0,则有效连接间隔等于实际连接间隔,)。

从机延迟表示可以跳过的最大事件数。该数字的范围可以从最小值0(意味着不能跳过连接事件)到最大值499。最大值不能使有效连接间隔(见下列公式)大于16秒。间隔可以使用以下公式计算:

Effective Connection Interval =****(Connection Interval) × **(*1 +[Slave Latency])*

Consider the following example**:**

  • Connection Interval**:** 80 (100 ms)
  • Slave Latency**:** 4
  • Effective Connection Interval**:(100 ms) × (1 + 4)=** 500 ms

当没有数据从从机发送到主机时,从机每500ms一个连接事件交互一次。

5.通信

通俗的说,我们将从机具有的数据或者属性特征,称之为Profile,Profile可翻译为:配置文件。

从机中添加Profile配置文件(定义和存储Profile),作为GATT的Server端,主机作为GATT的Client端

Profile包含一个或者多个Service,每个Servicer又包含一个或者多个的Characteristic。主机可以发现和获取从机的 Service和Characteristic,然后与之通信。Characteristic是主从通信的最小单元。

  • 主机可主动向从机Write写入或Read读取数据。
  • 从机可主动向主机Notify通知数据。

注意,这里引用了服务 Service 和 特征值 Characteristic 的概念。每个服务和特征值都有自己的唯一标识 UUID,标准UUID为128位,蓝牙协议栈中一般采用16位,也就是两个字节的UUID格式。

一个从机设备包括一个或者多个服务;一个服务中又可以包括一条或者多条特征值,每个特征值都有自己的属性 Property,属性的取值有:可读 Read可写 Write 以及 通知 Notify

  • 可读可写的字面意思容易理解,表示该特征值可以被主机读取和写入数据,
  • 而通知则表示从机可以主动向主机发送通知数据。这便是主从机之间两个典型的通信方式。

下图是一个典型的从机设备,该从机包含有一个Profile,两个个Service和五个Characteristic。我们先来介绍这些特征值的作用,然后介绍如何通过特征值通信。

服务0x180A

180A是蓝牙协议里标准的服务UUID,用来描述设备信息Device Information,可以通过该服务来提供从机设备的相关说明,例如硬件版本,软件版本,序列号之类的信息。这样主机就可以获得从机的设备信息。上图中我们添加了三个具体信息的特征值。

  • 特征值0x2A24,描述产品型号 Model Number String,例如某智能锁的产品型号为:“DSL-C07”。
  • 特征值0x2A25,描述产品序列号 Serial Number String,例如某智能锁的产品序列号为:“lkjl0016190502500269”
  • 特征值0x2A26,描述产品固件版本号 Firmaware Revision String,例如某智能锁的固件号为:“2.7.2.0”

上述特征值仅有Read属性,因此主机只能读,不能执行写操作。

服务0xFFF0

FFF0是我们自定义的服务UUID,它包含两个特征值,用来发送和接收数据。

  • 特征值0xFFF1,自定义的数据发送通道,具有Read和Write属性,主机可以通过该特征值,向从机发送数据,至于发送的数据最大长度,可以在Profile中配置。
  • 特征值0xFFF2,自定义的数据接收通道,具有Notify属性,从机可以通过该特征值,主动向主机发送数据。

假设主机写特征值的协议栈函数原型为 int GATT_WriteCharValue(uuid_t UUID, uint8 *pValue, uint8 len)

假设从机发送通知的协议栈函数原型为 int GATT_Notification(uuid_t UUID, uint8 *pValue, uint8 len)

那么主机向从机发送Hello,可以这样调用协议栈的函数:GATT_WriteCharValue(0xFFF1,”Hello”,5)

那么从机向主机发送1234,可以这样调用协议栈的函数:GATT_Notification(0xFFF2,”1234”,4)

6.主从机交互演示

6.1上电初始化

首先进行协议栈初始化和相关功能调用,如下图所示。

  • 主机设备,主机初始化时,需要设置设备类型,设置用于扫描的相关参数,初始化GATT等协议相关的参数。(下一章节详细介绍何为GATT)
  • 从机设备,从机初始化时,需要设置设备名称,广播相关参数,从机Profile等。从机一般会立即开启广播,也可以等待一个事件来触发广播,例如按键触发。

6.2主机扫描从机

按键按下,触发主机扫描从机,此时,主机显示屏打印Scanning正在扫描。此刻的从机仍然处于广播状态。

6.2发现从机

当主机扫描到从机时,可以返回已扫描到的从机相关信息,例如可以提取到下图中的从机设备名称,从机MAC地址,从机的RSSI信号值等数据。

因此,有些应用在从机的广播包或者扫描回应包中添加自定义字段,这样就可以被主机通过扫描的方式拿到数据。

6.3发送连接请求

当主机扫描到从机后,通过MAC地址向从机发送连接请求。低功耗蓝牙的连接速度非常快,100ms左右即可成功连接上。如果从机的广播比较大,则会影响连接的速度。

从机在未收到连接请求之前仍然处于自由的广播状态。

6.4成功连接

当从机收到连接请求后,双方成功建立连接,此时双方的状态均变为已连接状态。

然后主机可以调用协议栈提供的接口函数来获取从机的服务。

6.5获取从机服务

获取从机服务通常是在连接成功后就立即执行的,因为只有获取从机的服务后,才能与其通信。下图是主机向从机发送获取服务的请求。

此刻,从机处于已连接状态。响应服务获取请求是在底层自动完成,上层无需理会。

6.6成功获取服务

如下图所示,主机成功获取到从机的服务,例如获取到UUID为0xFFF0的Services,该Service有两个特征值,分别是具有读写属性的0xFFF1,以及具有通知属性的0xFFF2。

读写属性是指主机可以读写该特征值的内容。而通知属性是指从机可以通过该特征值向主机发送数据。

6.7主机向从机发送数据

主机通过特征值0xFFF1,主动向从机发送自定义数据Hello,当数据成功发送后,主机状态变为:数据已发送。从机将收到主机发来的数据,从机状态变为收到数据。

6.8从机向主机发送数据

从机可以通过Norify的方式主动向主机发送数据,例如下图,从机通过特征值0xFFF2发送了一条Notify通知,数据内容为:1234

GAP和GATT

蓝牙协议栈分为两类结构:控制器(Controller)和主机(Host)。每个类别都有子类别,这些子类别执行特定的角色。我们将要研究的两个子类别是 通用访问配置文件 (GAP)和 通用属性配置文件 (GATT)。

  • GAP是Generic Access Profile的缩写,中文含义是:通用访问配置文件。
  • GATT是Generic Attribute Profile的缩写,中文含义是:通用属性配置文件。

GAP和GATT区别

BLE(蓝牙低功耗)中的 GAP(Generic Access Profile)和 GATT(Generic Attribute Profile)是核心协议,分别负责设备连接管理和数据交互。

1. GAP(Generic Access Profile)

作用:管理设备的广播、发现、连接和安全。
核心功能

  • 设备角色定义
    • 外围设备(Peripheral):广播自身存在(如传感器、手环)。
    • 中央设备(Central):扫描并发起连接(如手机、平板)。
    • 广播者(Broadcaster):仅广播数据,不建立连接(如信标)。
    • 观察者(Observer):只接收广播,不连接(如扫描设备)。
  • 广播与发现
    • 外围设备通过广播数据包(包含设备名称、服务UUID等)宣告存在。
    • 中央设备扫描广播并选择设备连接。
  • 连接管理
    • 定义连接建立过程(如配对、加密)。
    • 控制连接参数(间隔、延迟等)。
  • 安全控制
    • 设置配对模式(如Just Works、Passkey Entry)。

2. GATT(Generic Attribute Profile)

作用:定义连接后的数据交互结构和协议。
核心功能

  • 数据组织结构
    • 数据以 属性(Attribute) 形式存储,结构为:
      • 服务(Service):功能集合(如心率服务)。
      • 特征(Characteristic):服务中的具体数据(如心率值)。
      • 描述符(Descriptor):特征的附加信息(如单位、权限)。
  • 角色定义
    • 服务端(Server):存储数据(如手环存储心率数据)。
    • 客户端(Client):读写数据(如手机读取心率)。
  • 操作协议
    • 客户端通过 UUID 访问服务/特征。
    • 支持读写、通知(Notify)、指示(Indicate)等操作。

GAP vs GATT 关键区别

特性 GAP GATT
阶段 连接前(广播、发现、配对) 连接后(数据传输)
核心任务 设备可见性和连接管理 数据组织与交互
数据结构 服务、特征、描述符的层级结构
典型操作 广播、扫描、配对 读写、通知、指示

协作流程示例:以开蓝牙门锁为例 手机是主机 门锁是从机

1. GAP 层:设备发现与连接

阶段 1:门锁广播自身存在

  • 门锁(Peripheral) 通过GAP角色持续广播数据包,包含以下信息:
    • 广播数据:设备名称(如 SmartLock-123)、服务UUID(如 0x1810 门锁服务)。
    • 连接参数:是否允许连接、广播间隔等。
    • 安全标志:是否需要配对(如MITM保护)。

阶段 2:手机扫描并发起连接

  • 手机(Central) 扫描周围的广播包,识别门锁的广播信息。
  • 用户通过APP选择门锁后,手机向门锁发起连接请求(CONNECT_REQ)。
  • GAP安全控制(可选):
    • 如果门锁要求配对,手机会弹出配对请求(如输入PIN码或确认Just Works)。
    • 配对成功后生成加密链路(LE Secure Connection)。

2. GATT 层:数据交互与开锁指令

阶段 3:发现门锁的GATT服务

  • 连接建立后,手机(GATT Client)查询门锁(GATT Server)的GATT数据库:
    1. 发现主服务:手机发送 Discover Primary Services 请求,获取门锁支持的服务列表(如电池服务、门锁控制服务)。
    2. 发现特征值:针对门锁控制服务(如UUID 0xA001),手机查询其包含的特征(Characteristics):
      • 开锁特征(UUID 0xB001,属性:Write)。
      • 状态特征(UUID 0xB002,属性:Notify,用于反馈锁状态)。

阶段 4:发送开锁指令

  • 手机向门锁的 开锁特征0xB001)写入指令:
    • Write Request:发送加密的开锁命令(如 0x01 表示开锁)。
    • 门锁响应
      • 若需授权,门锁可能通过GATT要求用户认证(如APP内二次确认)。
      • 门锁执行开锁动作,并通过 状态特征0xB002)发送Notify通知手机(如 0x01 表示已开锁)。
手机 (Central)                           门锁 (Peripheral)
     |                                       |
     | ←------- ADV Packet (GAP) ----------- |   // 门锁广播
     |                                       |
     | -- SCAN_REQ →                          |   // 手机扫描
     | ←-- SCAN_RSP (设备名称/UUID) -------- |
     |                                       |
     | -- CONNECT_REQ →                       |   // 发起连接
     | ←-- CONNECT_ACK ---------------------- |   // 连接建立
     |                                       |
     | -- Discover Services →                |   // GATT服务发现
     | ←-- 门锁服务UUID列表 ---------------- |
     |                                       |
     | -- Discover Characteristics →         |   // 发现开锁特征
     | ←-- 开锁特征UUID (Write) ------------ |
     |                                       |
     | -- Write Request (0x01) →             |   // 发送开锁指令
     | ←-- Write Response ----------------- |   // 门锁确认
     |                                       |
     | ←-- Notify (锁状态更新) ------------- |   // 可选的状态反馈

如何伪造主机(手机)与从机(门锁)进行交互?

前期信息侦察

  • 蓝牙协议版本
  • GAP 广播数据: 门锁广播什么信息?例如,设备名称、UUID 等。可以尝试用手机上的 NRFCONNECT 查看门锁的广播信息。
  • GATT 服务和特征: 门锁提供了哪些 GATT 服务?哪个服务和特征是用于控制开锁的?你需要知道这些服务的 UUID 和特征的 UUID,以及写入这个特征所需的数据格式(例如,特定的字节序列)。你可以使用支持 GATT 浏览的手机App(例如“nRF Connect for Mobile”、“LightBlue”)连接到门锁,查看它提供的服务和特征。
  • 配对和绑定: 门锁是否需要配对和绑定才能进行控制?如果需要,需要先完成配对过程。

所用工具

  • BLE嗅探/开发硬件
    • BLE开发板:如 CC2650、ESP32(支持主从模式)。
    • 嗅探工具:Ubertooth、nRF Sniffer(配合Wireshark抓包)。
    • 替代方案:树莓派(安装BlueZ)
  • 软件工具
    • BLE调试APP:nRF Connect、LightBlue(用于初步探测)。
    • 开发框架
      • Android:Android BLE API(Java/Kotlin)。
      • Linux:BlueZ库(gatttoolbluetoothctl)。
      • Pythonpybluezbleak库。