Blog

Blog

PHODAL

我是如何Hack一个机器人的?

在Hack Day这样的伟大节日里,还是应该做一点Hack的事。很久没有干过这么刺激的事,想想也觉得有点小激动。

Blabla,当然这个Robot可能没有你想的那么高端,Hack的目的只是为了控制这个机器人。而这个所谓的机器的主要功能都集中在客户端上,我们可以在手机上通过BLE(蓝牙低功耗)来控制这个机器人。

所以,我们的目的其实很简单——自己写APP来控制这个机器人。而APP的主要功能都是通过蓝牙控制来实现的,而蓝牙协议的第一步就是连接。在最开始的时候我想的连接方式是PIN码 + AT指令,结果发现我完全错了,BLE实际上更简单。

因此,我觉得有PIN码的存在,所以第一步就是抓包。

蓝牙通讯抓包一

为了做到这一步,我们需要一个大名鼎鼎的“WireShark”。不过,我们是要拿这个软件来分析日志。

第一步,我们需要在开发者选项中启用日志分析。在开发者选项中有一个功能, [Enable Bluetooth HCI snoop log/启用蓝牙 HCI 信息收集日志]。如下图所示:

Enable HCI Log

第二步,我们我们就可以打开应用,做一些正常的操作,然后这些操作就会存储到一个日志文件里。而这个日志文件只能用WireShark打开。

第三步,就是用WireShark打开这个日志。从日志中找寻手机发往机器人的指令,发现里面都看不懂。

WireShark Bluetooth Log

接着想起来,似乎可以反编译他们的代码。

反编译代码

开始尝试反编译代码,发现步骤也挺简单的:

  1. 用apktool反编译apk
  2. 用dex2jar将dex转为jar
  3. 用jd-gui查看反编译后的软件,并导出
  4. 查看代码

虽说原理很简单,但是实践起来就坑了。先反编译了最新的APK,然后发现这个APK被360加固了。。接着开始回溯这个软件的版本,360加固出得比这个软件晚,那么我应该可以找到这个软件的早期版本。

而事实是,我在国内都找不到这个APK的早期版本,只好拿包名去搜索,然后中奖了——找到了一个早期的版本,并且反编译成功了。

接着,我全局搜索PIN码等等的东西都没有结果,我的思路错了。。。

最后,我看到了代码里的:

Log.i("robotControl", "forward left 30");

既然,他可以打日志,那我应该是可以查看日志的。

日志记录

于是,我找到了Android的logcat命令,然后凑了一条指令出来。

adb -d logcat  com.example:D *:D > debug.log

运行软件,分析日志。从大量的数据里找到:

D/BluetoothAdapterService(23908452)(16911): getState() - mAdapterProperties: com.android.bluetooth.btservice.AdapterProperties@1e554c00
D/BluetoothAdapter(17239): 448307125: getState(). Returning 12
D/BtGatt.GattService(16911): registerClient() - UUID=037decf9-4d7e-49d8-9f82-85202eea480f

看着日志,看着日志。突然有一个瞬间,我意识到BLE是不需要PIN码的。我只需要找到对应的UUID,以及对应的Service就可以了。

现在,我可以写自己的应用了。

编写自己的APP

这一次,在网上简单地找了一个Cordova BLE的示例。(后面才发现这个坑挖得太深,以至于掉了进去。Cordova对WebSocket的支持不好,不过这和这个主题没有啥关系。。)

分析设备

按代码的逻辑,我们可以在连接上设备的时候查看设备的服务——并根据具体的服务及txCharacteristic,来做对应的发送数据。而依据write数据的代码,我们需要两个东西一个是设备的UUID,一个Characteristic。一个蓝牙4.0的终端可以包含多个Service,一个Service可以包含多个Characteristic。

如,我们要发送和接收数据都需要有对应的Characteristic。蓝牙技术联盟似乎定义了一些GATT(Generic Attribute Profile ),如下是一个设备的缩略数据:

{
    "name": "Battery Demo",
    "services": [
        "1800"
    ],
    "characteristics": [
        {
            "service": "1800",
            "characteristic": "2a00",
            "properties": [
                "Read"
            ]
        }
    ]
}

如这个设备,提供了一个代码为1800的服务。这个服务里包含了一个characteristic为2a00的属性,我们只需要通过1800这个Service UUID,以及characteristic 2a00就可以读取这个设备的Device Name——这个是蓝牙技术联盟定义的Characteristics。

而这时,就找到了UUID为fff0,TX Characteristic为fff1。

控制机器人

所以我们的设备信息便如下所示:

var robotInfo = {
    serviceUUID: "0000fff0-0000-1000-8000-00805f9b34fb",
    txCharacteristic: "0000fff2-0000-1000-8000-00805f9b34fb", // transmit is from the phone's perspective
    rxCharacteristic: "0000fff1-0000-1000-8000-00805f9b34fb"  // receive is from the phone's perspective
};

接着,继续看之前的反编译代码,发现他是这么控制的。

  1. 左转指令X2
  2. 右转指令X3
  3. 前进指令X1
  4. 后退指令X4

当然,他还有更多的指令,只是我不需要那么多。。。然后我找到了一个名为nipplejs的库,来当游戏手柄。

小结

现在,我们已经可以控制这个机器人了。

关于我

Github: @phodal     微博:@phodal     知乎:@phodal    

微信公众号(Phodal)

围观我的Github Idea墙, 也许,你会遇到心仪的项目

QQ技术交流群: 321689806

新书《前端架构:从入门到微前端》

《前端架构:从入门到微前端》是一本围绕前端架构的实施手册,从基础的架构规范,到如何设计前端架构,再到采用微前端架构拆分复杂的前端应用。本书通过系统地介绍前端架构世界的方方面面,来帮助前端工程师更好地进行系统设计。

前端架构包含以下五部分内容:

  • 设计:讲述了架构设计的模式,以及设计和制定前端工作流。
  • 基础:通过深入构建系统、单页面应用原理、前端知识体系等,来构建出完整的前端应用架构体系。
  • 实施:通过与代码结构的方式,介绍如何在企业级应用中实施组件化架构、设计系统和前后端分离架构。
  • 微前端:引入6种微前端的概念,以及如何划分、设计微前端应用,并展示了如何实现这6种微前端架构。
  • 演进:提出更新、迁移、重构、重写、重新架构等架构演进方式,来帮助开发人员更好地设计演进式架构。
comment

Feeds

RSS / Atom

最近文章

关于作者

Phodal Huang

Developer, Consultant, Writer, Designer

ThoughtWorks 高级咨询师

工程师 / 咨询师 / 作家 / 设计学徒

开源深度爱好者

出版有《前端架构:从入门到微前端》、《自己动手设计物联网》、《全栈应用开发:精益实践》

联系我: h@phodal.com

微信公众号: 与我沟通

标签