当前位置: 首页 > article >正文

对智能手表进行逆向工程

 视频教程在我主页简介或专栏里 

目录: 

初步观察

PCB 的逆向工程

引入 Ghidra

重新编程智能手表

 

前段时间,我收到一批具备地理定位功能的智能手表,这些手表在试用期结束后被搁置。我决心为它们找到新的用途,于是开始了我的智能手表逆向工程之旅!

在本文中,我将分享智能手表逆向工程的过程,首先展示一些关于手表外观和电路的初步观察,然后详细讲述如何重新编程智能手表,最后说明如何修补固件以实现其重新利用。

初步观察

这些手表以最基本的配置交付,包装内仅附有一页关于如何充电和使用的说明。每个盒子内包含一个充电器和一块手表。没有提供 README 文件、官方网站或开发者门户。手表本身仅在表面配备了一个电容传感器,用于开启屏幕,用户可通过屏幕查看心率、一些调试信息以及不同表盘样式下的时间。

 

调试信息为识别手表提供了有用的线索。我注意到,不同相同型号的手表上显示的调试界面中,IP 地址是相同的。我的初步猜测是,这个 IP 地址指的是这些手表所连接的服务器的地址。

 

这款手表具有 IP67 级防水性能,也就是说,它是防水的。因此,使用我有限的工具,在不破坏手表的情况下几乎无法进入内部。本着探索的精神,我拿了一把钳子对其中一块手表进行了拆解,试图弄清楚内部构造。这并不容易,但经过一个小时的小心撬动和切割,我终于成功拆除了手表的外壳。

 

 

内部是一块单一的 PCB 板以及一个锂聚合物电池(LIPO)。机壳内嵌有两个天线,通过 u.FL 连接器与电路板连接。

PCB 的逆向工程

这款智能手表的核心是一个支持蓝牙的 nRF52832 芯片,同时还有两个主要的集成电路:支持 WiFi 的 ESP8285 和来自 SIMCOM 的蜂窝通信芯片。一开始我对 WiFi 微控制器的存在感到疑惑,因为手表没有任何支持 WiFi 功能的明显迹象。然而,我后来发现它被用于城市环境中的定位辅助。由于 GPS 在城市环境中的精度通常较差,手表可以通过结合 WiFi 接入点(AP)、蜂窝数据和历史 GPS 数据来近似确定位置。

从布局上看,nRF52832 是设备的主控芯片,并使用 WiFi 芯片扫描本地的 WiFi 接入点(AP)。nRF52832 还通过 UART 与 SIMCOM 设备通信,并发出命令以接入移动网络。基于这一发现,我将精力集中在寻找 nRF52832 上的任何 UART 或暴露的编程引脚上,因为这些引脚通常用于与微控制器进行交互。

 

在这种情况下,电路板上暴露了相当多的 UART 和编程引脚。我发现一个非常有趣的迹象是,PCB 右侧的圆形金色触点除了用于为手表电池充电外,还与 nRF52832 芯片上的 SWDIO 和 SWCLK 引脚相连。SWDIO 和 SWCLK 是 JTAG 编程引脚,通常用于对芯片进行编程。此外,在手表前盖的底部有弹簧加载的电接触探针(pogo pin),当手表关闭时,这些探针会与这些触点接触。

这些 pogo pin 与手表正面铜镀层触点相连,这意味着主芯片的编程引脚暴露在设备表面。暴露编程引脚并不常见,因为通常设备的固件会在工厂中被写入 PCB,并随后通过 WiFi 或蓝牙进行更新。一般来说,没有必要暴露编程引脚。然而,这个特点在后续操作中非常有用,因为这意味着我不需要打开手表就可以访问固件。而如果必须打开手表,我的重用计划几乎就没有意义了——正如我之前尝试打开手表时所表现的那样:这可不是一件能很快重新组装好的事情。

更有趣的是,在充电适配器上,与手表正面 SWCLK 和 SWDIO 接触点相连的 pogo pin 竟然连接到了 microUSB 接口上的 D+ 和 D- 引脚。D+ 和 D- 引脚通常用于数据传输。这意味着我甚至不需要制作定制的编程平台来重新编程手表:只需要将一个 microUSB 电缆剪开,暴露出编程引脚,然后将其连接到充电器上的手表即可。非常棒。

 

 

通过充电器将手表连接到我的 JLink 调试器后,我首先注意到手表正在通过 JLink RTT 查看器输出调试信息。成功了!虽然能够观察到调试输出非常有用,但由于 RTT 模块没有配置输入,因此无法向手表发送命令。不过,这些输出验证了我之前关于手表内部连接方式的假设是正确的。

 

在通过 JLink 尝试发送命令进行一些探索性操作后,我决定查看固件。通过连接 JLink,我能够使用 nrfjprog 工具并结合 --readcode 和 --readram 参数来转储固件。

 

固件没有启用读写保护,因此我成功获取了完整的固件转储。此时,我有两个选择来重新利用这款手表:1)可以完全重新编程,通过向设备中刷入新的固件实现,或者 2)对固件中的 IP 地址和端口进行补丁修改,使手表将数据发送到我控制的服务器。由于重新编程手表可能是一个庞大的工程,我决定尝试对手表进行补丁修改。

引入 Ghidra

为了在 Ghidra 中正确映射函数和变量,我需要转储 RAM 和闪存。这是一个来自 Cortex M0+ 设备的裸机代码,我必须将固件反编译为 ARM 小端格式,Ghidra 成功生成了半可读的伪代码。

 

此时我的目标是调查 IP 地址的位置,我推测它存储在代码中的某处。手表通过蜂窝网络将数据发送到一个服务器,该服务器的地址显示在手表的调试界面上。如果我能够更新这个 IP 地址,就可以将手表发送的数据重定向到我控制的服务器。

然而,我最初尝试查找与手表界面上显示的 IP 地址相符的硬编码字符串未成功。

接下来,我尝试查找 RTT 查看器中调试输出中出现的最接近的字符串。在这种情况下,字符串是 AT+CIPOPEN=0,这是从 nRF52832 发送到 SIMCOM 模块的串行命令,指示其打开与指定为参数的 IP 地址的连接。通过找到这个字符串,因为它使用了手表必须连接的服务器的 IP 地址,我就可以定位存储服务器 IP 地址的内存位置。

 

我更成功地找到了一个格式化字符串。这个匹配项的字符串模式与 IP 地址的格式相符。它在一个看起来非常像 sprintf 函数的函数中被调用。

 

sprintf 函数中调用的字符串引用,调用了另外四个变量。

sprintf 函数引用了一个存储在 DAT_20000887 的数组,DAT_20000887 对应于 nRF52832 数据手册中的数据 RAM 区域,如下图所示的内存映射所示。

 

进入内存中的 RAM 位置,我发现它在两个函数中被写入。只有第一个位置是有趣的,因为它存储了硬编码的 IP 地址。第二个位置则允许稍后通过无线更新 IP 地址。

跳到第一个函数,我在内存中找到了这些硬编码变量的十六进制值,它们作为主函数的一部分被写入数组,这些变量对应了我在手表上观察到的 IP 地址。

 

这些内存位置是固件中需要修补的六个字节的数据,用于 IP 地址和端口。

 

出现的一个小问题是,原始端口号是38899,它以两个字节保存:0x0c 和 0x68。编译后的程序使用了一个 movn 指令,该指令对硬编码的值应用布尔“非”操作,然后再将其放入 RAM 中。从技术上讲,这个指令可以被修补,以去掉 not 操作,但由于我想减少更改字节的数量,因此我在将所需的端口号转换为相应的十六进制值时,添加了一个额外的操作。

重新编程智能手表

有了这些知识后,我能够编写一个简单的脚本,修补固件,替换为任何我想要的 IP 地址和端口。该脚本还更新了每行修补后的校验和,以确保固件与预期格式匹配。修补完成后,我使用 Nordic Semiconductor 的 Programmer 工具程序将固件闪存到手表上。

 

 

我很高兴地说,这个方法成功了!通过更新固件以与服务器通信,我们能够从手机获取数据并进行处理。

 

一个有趣的收获是,编程接口暴露在USB端口上,这在其他智能手表中并没有见过。固件没有任何读写保护也很不常见,因为大多数其他物联网设备在投入生产后会强制执行固件保护,以防止固件被轻易克隆。

 视频教程在我主页简介或专栏里

申明:本账号所分享内容仅用于网络安全技术讨论,切勿用于违法途径,所有渗透都需获取授权,违者后果自行承担,与本号及作者无关

 


http://www.kler.cn/a/470762.html

相关文章:

  • asio中strand用于串行执行task
  • touch详讲
  • Three.js 基础概念:构建3D世界的核心要素
  • thinkphp通过html生成pdf
  • 自动驾驶相关知识学习笔记
  • Python连接和操作Elasticsearch详细指南
  • 数据结构:二叉搜索树详解
  • 搭建SSL邮件服务器
  • 2024年最新外包干了10个月,技术退步明显,程序人生
  • 基于云效 Windows 构建环境和 Nuget 制品仓库进行 .Net 应用开发
  • 在 Windows 上安装 NodeJS
  • linux下vfio显卡透传
  • Flink系统知识讲解之:如何识别反压的源头
  • flask-admin 非自定义modelview下扩展默认视图(base.html)
  • 20241230 AI智能体-用例学习(LlamaIndex/Ollama)
  • 【每日学点鸿蒙知识】Hap 安装失败、ArkTS 与C++ 数组转换、渐变遮罩效果等
  • 从源码编译Qt5
  • RWKV 语言模型
  • 2025年的加密软件市场如何?
  • 原型模式详解与实践
  • 【动态规划篇】穿越算法迷雾:约瑟夫环问题的奇幻密码
  • el-date-picker 不响应change事件的解决办法
  • 【每日学点鸿蒙知识】字体大小,镜像语言间距、禁止分屏、Router与Navigation
  • 【Python系列】使用 `psycopg2` 连接 PostgreSQL 数据库
  • 一文理解区块链
  • 【老白学 Java】保存 / 恢复对象状态