最近,我发现自己就“物理网络和Web蓝牙 ”进行了大量的讨论。为了演示这些技术的一些功能,我想为我的演示找到一款价格合理的设备 - 最好低于10美元 - 这样我的观众就可以轻松获得演示设备并自行尝试。
通过搜索互联网,我以10美元以下的价格从中国购买了一些消费“智能灯泡”,因此我订购了两种来玩。智能灯泡包括一个RGB LED,因此它们可以改变颜色,当然它们也是通过蓝牙控制的!正如你可以从这种产品期望的那样,没有任何文档 - 只是链接下载Android应用程序。由于我想展示如何通过Web蓝牙控制它们,因此我决定尝试对协议进行反向工程。
为什么要花时间对协议进行逆向工程?
首先,这种方式更有趣。它还使您能够将其与诸如天气服务(灯泡根据天气变化颜色),您的startup的自动化版本(代码被破坏时灯泡为红色)或快速闪烁随机颜色等任何内容结合起来(我的观众真的很喜欢这最后的用途)。
一旦你控制了灯泡,可能性仅受限于你的想象力:你可以用你的声音控制它(使用语音识别),用手机的加速度计控制它,当你接到电话时闪烁灯泡,或者甚至通过全天改变色温来调节睡眠周期,以获得类似日出/夕阳光的效果,以帮助调节全天的身体褪黑激素水平。而这些只是适合我餐巾背面的想法!
为了完成这个项目,你不需要知道有关蓝牙的一切,但需要一些基本概念才能实现。
如果您想了解更多关于蓝牙低功耗(又名BLE)的信息,我很乐意为您指出正确的方向,或者写一篇文章解释BLE的更多技术方面 - 在评论中回复我!
蓝牙低功耗101(或者100)
在低功耗蓝牙中,设备可以执行两种角色之一。设备可以是“中央(Central)”(本例中为手机),也可以是“外设”(分别为灯泡)。
蓝牙设备具有对应于设备的一种功能的服务(services) 。例如,您的智能手表可能会公开一项服务以报告设备的电池电量,然后另一台设备测量您的心率。每项服务都暴露称为特性(characteristics)的变量/属性。这些特征代表了服务的一个参数,可以读取,写入或者两者兼有。
例如,在上述电池服务中,它将具有电池电量特性,这是一个只读值,包含0到100之间的1字节值,报告设备中剩余电池的百分比。
温度服务可以具有一个温度特性,以及另一个湿度特性,两者都是只读的。智能灯泡服务可以具有一个特性用于开/关(写入0将其关闭,1开启)以及用于亮度(0至100左右)的另一特性,其可以是只写或可读可写。
外设周期性地宣告他们拥有的服务(通常每秒约一次)。中心(例如您的手机)可以看到这些广告,并且可以与周围的任何外围设备建立连接,并对其服务提供的特征进行读取/写入。
每种服务和特性都由唯一的16位或128位数字标识,如ff05
(16位)或00000000–0000–1000–8000–00805F9B34FB
(128位)。 16位预留用于标准服务和特性,例如前面提到的电池电量服务,并由Bluetooth SIG Group定义。尽管如此,许多消费设备喜欢将它们用于自己的目的。
逆向工程灯泡:灯泡1
逆向工程第一个灯泡,一个智能LED灯E27 RGBW 5W灯泡 ,很容易。简而言之 - 我打开NRF Connect ,扫描,发现灯泡,尝试一些值,并得到我想要的。
连接到灯泡后,我对设备暴露的不同特征进行随机写入,最终它改变了颜色。经过一些试验和错误之后,我发现协议非常简单。您只需要将4个字节写入Service ffb0
/ Characteristics ffb2
,格式如下: BB GG RR WW
(蓝色,绿色,红色和白色级别),对应灯泡的内部LED。
我甚至没有得到这个灯泡的应用程序,并且从来没有-我只是通过直接用nRF Connect控制它,后来写了一个小的Node.js应用程序,以使用noble控制它。
逆向工程灯泡:灯泡2
第二个灯泡,一个魔术蓝UU E27灯泡 ,更有趣。使用与nRF Connect相同的技术,我立即发现唯一可写的特征(在服务ffe5
中的特征号ffe9
),但给它发送值,它没有任何效果。我决定尝试另一种方法 - 使用随灯泡提供的官方Android应用程序,然后记录所有通信信息,找出命令,然后将它们自己发送到灯泡来控制它。
首先,我安装了此灯泡的官方应用程序 ,确保蓝牙已启用,并打开应用程序以确保可以与灯泡配对并通过应用程序控制它。
Android 4.4(和更新版本)可以选择记录进出设备的所有蓝牙数据包。我使用此功能来记录应用程序和灯泡之间的消息。如果你想亲自尝试一下,启用起来非常简单:
- 首先,如果您尚未这样做,则需要在Android中启用开发人员模式 。
- 接下来,转到设置,然后打开“开发人员选项”并打开“启用Bluetooth HCI snoop日志”。这将开始记录通过您的设备的所有蓝牙流量。
一旦我的记录机制全部建立起来,我就打开了“Magic Blue”应用程序,并向灯泡发送了一些命令以多次改变它的颜色)。为了完成该过程的第一部分,我将蓝牙通信记录从我的Android设备复制到了我的PC。
您可以在/sdcard/btsnoop_hci.log
找到录制文件。您可以使用“文件管理器”应用程序找到该文件并通过Google Drive或Email共享该文件,也可以使用USB电缆将Android设备连接到PC,然后在根文件夹中找到btsnoop_hci.log
文件。
如果您的计算机上安装了Android SDK,则还可以使用USB电缆连接它并使用以下命令复制日志:
adb pull /sdcard/btsnoop_hci.log
注意:在某些设备中, btsnoop_hci.log
是以不同的路径创建的,例如/sdcard/Android/data/btsnoop_hci.log
。
我使用Wireshark打开蓝牙日志。Wireshark是一款免费工具,可让您分析网络流量。如果您想要自己逆向工程灯泡,请注意,您可能需要将文件重命名为btsnoop_hci.pcap,Wireshark才能识别它。
最初,有大量的数据包,其中一些可能与蓝牙无关。我使用“过滤器”选项(见上图)选择“写入特征值(Write Characteristic Value)”命令。我使用这个过滤器:
btatt.opcode.method==0x12
(或者,您也可以通过设备地址进行过滤,以查看与特定设备的所有通信。以下是使用MagicBlue灯泡地址过滤的示例:
bluetooth.addr==f7:34:5b:f8:cc:ef
有时候通过这种方式可以更容易地找到你要找的东西。)
看着其中一个写命令,我发现这个有效载荷:
有效载荷为56 ff 08 5a 00 f0 aa
。
我使用上面提到的nRF Connect应用程序将此值发送到服务ffe5
的特性ffe9
(如果您还记得,这是唯一可写的),并且瞧 - led变成了粉红色紫色。
通过试验其他一些组合,我找出了协议的格式。我发现实际上有两种格式,一种用于控制RGB LED,另一种用于控制暖白色LED(看起来像不能同时开启):
56 RR GG BB 00 f0 aa
第一个字节始终为56
,然后是红色,绿色和蓝色值的三个字节,然后是值为00 f0 aa
另外三个字节。
对于白色LED,格式是:
56 00 00 00 WW 0f aa
第一个字节仍然是56
,然后接下来的三个字节是00(或者任何你想要的,真的,因为设备将不给予他们注意),然后是一个指定白色LED亮度的值,以及另外两个字节的值0f aa
。
最后,灯泡还包含一些奇特的模式,例如两种颜色之间的渐变。这些由不同的命令激活:
bb II SS 44
II是照明模式(lighting mode)的索引( 25
和38
之间的值有效)且SS是速度(数值越低意味着颜色变化越快),每个单位大约为200毫秒(所以数值5
会每秒触发一次变化)。
例如,模式编号25
改变所有彩虹色和白色之间的淡入淡出。要在每两种颜色之间延迟约1秒来激活它,请发送以下命令:
bb 25 05 44
关于安全的一个词
正如你在上面看到的,这两款智能灯泡都没有安全机制。这意味着范围内的每个人都可以连接并控制它们。虽然第二个灯泡至少需要对协议进行逆向工程,但第一个灯泡甚至不需要付出很多努力。我希望一些高端智能灯泡的设计考虑到安全性,尽管从Google的“蓝牙智能灯泡安全性”来看,似乎没有人真正解决这些问题(例如,我只能找到一个提到智能灯泡的安全审查)。
所以只要知道,尽管这些灯泡作为装饰,玩具或艺术项目的一部分是很好的,但在阅读本文后,您可能不得不容忍邻居在家中突然改变灯泡的灯光。
故事的道德:我不会将它们用于任何关键的事情。
结论:我们已经破解了灯泡......现在为了更多的乐趣!
所以现在我们通过对协议进行逆向工程来破解灯泡,我们可以自信地改变我们邻居的智能灯泡的颜色(我在开玩笑:我不会宽恕或推荐这个......我只是说我们可以 )。
如果您有兴趣使用我使用的智能灯泡,您可以在这里 (第一个)和这里(第二个)获取它们。我邀请你自己试验灯泡,看看你可以用它们做些什么干净的事情(如果遇到任何麻烦或发现任何超酷的东西,请随时在评论中告诉我)。
在我的下一篇文章中 ,我将讨论Web蓝牙,并演示如何通过网页控制灯泡。所以如果你让拿到了自己的灯泡,你会准备好跟着我来:)
更新(2017年2月):我拆开灯泡并逆向工程了它的固件。
有兴趣了解灯泡的内部工作原理?查看后续的帖子 ,我从灯泡中提取固件并对其进行逆向工程,或阅读我如何让灯泡在没有电源的情况下运行 。