对智能手表进行逆向工程

文化   2024-12-26 12:00   新加坡  

扫码领资料

获网安教程


Track安全社区投稿~  

赢千元稿费!还有保底奖励~(https://bbs.zkaq.cn)

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

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

初步观察

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

img

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

img

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

img
img

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

PCB 的逆向工程

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

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

img

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

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

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

img
img

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

img

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

img

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

引入 Ghidra

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

img

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

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

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

img

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

img

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

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

img

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

img

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

img

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

img

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

重新编程智能手表

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

img
img

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

img

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

原文:https://medium.com/csg-govtech/reverse-engineering-a-smartwatch-a7cec52b29c8

声明:⽂中所涉及的技术、思路和⼯具仅供以安全为⽬的的学习交流使⽤,任何⼈不得将其⽤于⾮法⽤途以及盈利等⽬的,否则后果⾃⾏承担。所有渗透都需获取授权

如果你是一个网络安全爱好者,欢迎加入我的知识星球:zk安全知识星球,我们一起进步一起学习。星球不定期会分享一些前沿漏洞,每周安全面试经验、SRC实战纪实等文章分享,微信识别二维码,即可加入。


白帽子左一
零基础也能学渗透!关注我,跟我一启开启渗透测试工程师成长计划.专注分享网络安全知识技能.
 最新文章