chwdt/vanmoof-tools

GitHub: chwdt/vanmoof-tools

一套针对 VanMoof S3/X3 智能自行车的逆向工程工具集,支持固件解包打包、区域限制破解、密钥提取及底层硬件调试。

Stars: 33 | Forks: 4

# vanmoof-tools 用于支持 VanMoof S3/X3 逆向工程工作的工具 ## 已知固件镜像: - mainware.bin (MCU: ST STM32F413VGT6) - bleware.bin (MCU: TI CC2642R1F) - motorware.bin (MCU: TI TMS320F28054F) - shifterware.bin (MCU: MindMotion MM32F031F6U6) - batteryware.bin (MCU: ST STM32L072CZT6) - bmsboot.bin (MCU: 参见 batteryware.bin) - muco-boot.bin (MCU: 参见 mainware.bin) - bleboot.bin (MCU: 参见 bleware.bin) - shifterboot.bin (MCU: 参见 shifterware.bin) ## 关于固件镜像的一些观察: 自行车的大多数组件都包含分离的 boot loader 和固件镜像,Bluetooth 固件可能与该方案不同。 boot loader 以典型的 ARM vector table 开始,长度为 20Kb (0x5000 字节)。 boot loader 二进制文件的最后 8 个字节包含: - 4 字节版本信息,编码为 ASCII 字符 - 4 字节 CRC32。 CRC 使用 STM32 CRC 算法计算,覆盖整个 boot loader 数据,但不包含最后 4 个字节。 固件镜像以魔数 0xaa55aa55 开始,后跟以下头部项: - 4 字节版本信息 - 4 字节 CRC32 - 4 字节长度 - 12 字节日期(ASCII) - 12 字节时间(ASCII) 所有 4 字节值均采用小端编码。 CRC 使用 STM32 CRC 算法计算,覆盖整个镜像数据,此时头部的 CRC 和长度字段均设置为 0xffffffff。 ## 设置 / 安装 你可以使用 Raspberry Pi、你积灰的旧 Linux 机器,或者像 WSL 和 Linux 机器(Ubuntu 或 Debian 均可)这样时髦的新东西。 遗憾的是 macos 似乎不起作用。 ``` apt update apt install build-essential gcc-arm-none-eabi binutils-arm-none-eabi make ``` ## unpack 用法:`unpack ` 此工具提取 VanMoof 更新文件(也称为 PACK 文件)的内容。一个 PACK 文件以包含魔数“PACK”的头部开始,后跟指向目录结构的偏移量和目录结构的长度。目录结构(位于文件末尾)包含一个或多个条目,每个条目包含文件名、偏移量和数据长度。有关这些结构的详细信息,请参阅 pack.h。 如果当前目录中存在 PACK 文件中包含的文件,该工具将覆盖该文件。请在一个单独的目录中运行此工具,以确保不会丢失任何数据。 ## pack 用法:`pack [ ...]` 此工具将一个或多个固件文件打包成 VanMoof 更新文件,也称为 PACK 文件。这是 `unpack` 命令的逆操作。 ## crc32 用法:`crc32 ` 此工具计算并验证 boot loader 和固件镜像的 CRC。 ## patch 用法:`patch [-v] [-f ] [-m ] ` 此工具修补现代 VanMoof mainware 文件,以便在启动期间不会将 OFFROAD 区域重置为 US 区域。功率辅助级别可以再次配置为 5。当使用车把循环切换功率辅助级别时,如果区域为 OFFROAD,自行车也将循环切换到功率级别 5。 命令行上给定的文件将被覆盖为文件的修补版本,因此在使用该工具之前,请备份你的 mainware。 ### 选项: - `-v`:详细输出 - `-f `:指定不同的版本,格式:`..` - `-m `:更改默认自行车型号,格式:`,,` 目前该工具仅适用于 mainware 版本 1.9.3。 ## ble-patch 用法:`ble-patch ` 此工具修补 VanMoof bleware 文件,将命令 `rtos-statistics` 替换为命令 `dump`。在 bledebug 控制台内使用 `dump keys` 将显示存储的密钥。这些密钥是两个在工厂自行车调试期间使用的出厂默认密钥、你的 API 密钥以及 VanMoof 制造商密钥。后者用于加密固件镜像(当向 APP 发送更新时)。 你可以通过创建包含此 bleware 的 pack 并在 bledebug 控制台内使用命令 `pack-upload` 来更新自行车上已修补的 bleware。你需要使用 ymodem 发送创建的 pack。 输出如下所示: ``` > dump keys Key 0x00: UKEY 52XXXXXXXXXXXXXXXXXXXXXXXXXXXX2f 00000001 000003fe CRC 81XXXX92 Key 0x01: UKEY 98XXXXXXXXXXXXXXXXXXXXXXXXXXXX02 00000002 000001f4 CRC 72XXXX94 Key 0x7c: M-ID 00000000000000000000000000000000 00000008 00000000 CRC 7062da7e Key 0x7d: UKEY 5f5f5f5f5f4f574e45525f5045524d53 00000000 ffffffff CRC 4f25ee68 Key 0x7e: MKEY 710b2ea0dc8568b7b5e5ec0b8a39dae9 00000000 00000000 CRC a69429b6 Key 0x7f: MKEY 46383841XXXXXXXXXXXXXXXX4d4f4f46 00000000 ffffffff CRC 4aXXXX7e ``` 密钥 0x7d 和 0x7f 似乎是工厂调试密钥,转换为 ASCII 后内容为: ``` Key 0x7d: UKEY _____OWNER_PERMS 00000000 ffffffff CRC 4f25ee68 Key 0x7f: MKEY F88AXXXXXXXXMOOF 00000000 ffffffff CRC 4aXXXX7e ^- Bike MAC Address ``` 这也可以转储内存(即 ROM、内部 FLASH 或外部 FLASH): ``` > dump mem 10000000 40000 10000000 00 20 00 11 b1 19 00 10 bf 20 00 10 c1 20 00 10 . ...... . ... .. 10000010 c3 20 00 10 c3 20 00 10 c3 20 00 10 00 00 00 00 . ... .. . ...... ... > dump extflash 5afa0 20 0005afa0 5f 5f 5f 5f 5f 4f 57 4e 45 52 5f 50 45 52 4d 53 _____OWN ER_PERMS 0005afb0 00 00 00 00 ff ff ff ff 55 4b 45 59 68 ee 25 4f ........ UKEYh.%O ``` 有一个特殊命令显示 `CCFG_TI_OPTIONS` 和 `CCFG_TAP_DAP_*` 的值,此命令将修补 BLE 芯片的 boot loader 以启用 BLE 芯片的 JTAG 调试端口,以便进一步调试。第一次调用该命令时,它将输出如下值: ``` > dump ccfg CCFG_TI_OPTIONS: 0xffffff00 CCFG_TAP_DAP_0: 0xff000000 CCFG_TAP_DAP_1: 0xff000000 JTAGCFG: 0x00000000 ``` 当发现这些值时,闪存的最后一个扇区(包括 CCFG)在修补 CCFG 值和版本字符串的同时,从 0x56000 向下复制到 0x46000,然后将该扇区复制回 0x56000。经过 `reset` 后,这些新的 CCFG 值生效,JTAG 端口即被启用: ``` > dump ccfg CCFG_TI_OPTIONS: 0xffffffc5 CCFG_TAP_DAP_0: 0xffc5c5c5 CCFG_TAP_DAP_1: 0xffc5c5c5 JTAGCFG: 0x00000003 ``` 一旦存在这些 CCFG 值,boot loader 就不会再被触碰。 ## patch-dump 此工具像上面的 `patch` 一样修补现代 VanMoof mainware,但添加了一个将 FLASH 或内存转储到控制台的功能。此功能被修补到 `help` 命令中,并将 FLASH 或内存输出为 hexdump。用法为 `help `。 hexdump 可以使用 `dump2bin.sh` 脚本转换为二进制。 旧版本会将整个 FLASH 输出为 S-Records,源代码仍在 repo 中提供,如果你想使用此功能,请编辑 Makefile。 将终端输出捕获到日志文件中,并将 S-Records 裁剪到文件 `vanmoof.srec` 中。要将此转储转换为自行车内部使用的不同二进制文件,请使用这些 shell 命令: ``` objcopy -I srec -O binary vanmoof.srec vanmoof.bin dd if=vanmoof.bin of=muco-boot.bin bs=4096 count=8 dd if=vanmoof.bin of=vanmoof-config-a.bin bs=4096 skip=8 count=4 dd if=vanmoof.bin of=vanmoof-config-b.bin bs=4096 skip=12 count=4 dd if=vanmoof.bin of=shifterware.bin bs=4096 skip=16 count=16 dd if=vanmoof.bin of=mainware.bin bs=4096 skip=32 count=64 dd if=vanmoof.bin of=shadowware.bin bs=4096 skip=96 count=64 dd if=vanmoof.bin of=motorware.bin bs=4096 skip=160 count=32 dd if=vanmoof.bin of=batteryware.bin bs=4096 skip=192 count=32 dd if=vanmoof.bin of=bmsboot.bin bs=4096 skip=224 count=32 ``` ## 智能控制器内部闪存中的偏移量: ``` 0x08000000: stm32 boot loader 0x08008000: bike config A 0x0800c000: bike config B 0x08010000: shifterware image 0x08020000: mainware image 0x08060000: shadow image 0x080a0000: motorware image 0x080c0000: batteryware image 0x080e0000: bmsboot image ``` ## 智能控制器内部 SRAM 中的偏移量: ``` 0x20000a00: Bike state/config from FLASH at 0x8008000 or 0x800c000, 0xc0 bytes + 0x0f4: Sound bitmask [1] low + 0x0f8: Sound bitmask [1] medium + 0x0fc: Sound bitmask [1] high + 0x100: Backup code + 0x102: Lux low + 0x105: Volume low + 0x106: Volume medium + 0x107: Volume high + 0x108: Shift mode: AUTO/MANUAL + 0x109: Region + 0x10a: Unit system + 0x10b: Wheel motor type + 0x10c: Light mode + 0x10e: Shift up EU (3 x uint16_t) + 0x114: Shift up US (3 x uint16_t) + 0x11a: Shift up JP (3 x uint16_t) + 0x120: Shift up OFFROAD (3 x uint16_t) + 0x126: Shift down EU (3 x uint16_t) + 0x12c: Shift down US (3 x uint16_t) + 0x132: Shift down JP (3 x uint16_t) + 0x138: Shift down OFFROAD (3 x uint16_t) + 0x140: Mainware version + 0x144: Region lock + 0x145: Model: Bit0: 0=ES3, 1=ES4; Bit1: 1=E-Shifter, Bit2: 1=Display + 0x146: Custom soc + 0x147: HW revision + 0x1c0: CRC32 over FLASH data Motor support settings (from mainware): + 0x2c6: Motor percent power level 0 + 0x2c8: Motor speed limit power level 0 + 0x2ca: Motor percent power level 1 + 0x2cc: Motor speed limit power level 1 + 0x2ce: Motor percent power level 2 + 0x2d0: Motor speed limit power level 2 + 0x2d2: Motor percent power level 3 + 0x2d4: Motor speed limit power level 3 + 0x2d6: Motor percent power level 4 + 0x2d8: Motor speed limit power level 4 + 0x2d6: Motor percent power level 5 + 0x2d8: Motor speed limit power level 5 from EEPROM, 0x3c bytes + 0x310: Alarm state + 0x311: Play lock sound + 0x312: Remote locked + 0x313: Logging APP/Serial + 0x314: Shipping + 0x315: Cached BMS soc + 0x316: Power level + Boost + 0x317: Alarm enable/disable + 0x318: Horn file index + 0x31c: Odometer: km * 10 + 0x320: Timestamp bell button + 0x324: Timestamp boost button + 0x328: Timestamp GSM check + 0x32c: Firmware update order (6 bytes) + 0x332: BMS soc override + 0x333: BLE sleep request + 0x334: Shifter retries + 0x336: Shifter firmware version + 0x338: Shifter total shifts + 0x33c: GSM tracking heartbeat + 0x340: Kicklock state + 0x341: Battery state + 0x342: BMS firmware version + 0x344: Wake counter + 0x348: CRC32 over EEPROM data Bike state + 0x34c: BLE debug flag + 0x34d: GSM debug flag + 0x34e: Shift debug flag + 0x34f: BMS debug flag + 0x358: Loop count actual + 0x35c: Loop count min + 0x360: Loop count max + 0x364: Motor error + 0x366: Motor speed + 0x368: Motor I + 0x36a: Motor m_tmp + 0x36c: Motor d_tmp + 0x36e: Motor wlsp + 0x370: Motor Ubat + 0x372: Motor Pdsp + 0x374: Motor Pdtrg + 0x376: Motor io + 0x388: Motor firmware version + 0x38c: BLE firmware version + 0x390: BLE MAC address (6 bytes) + 0x396: BMS ESN (18 bytes) + 0x3a8: Debug password (16 bytes) + 0x3ba: Lipo version + 0x3c0: Error flags (2 x uint32_t) + 0x3cc: Speed 1 + 0x3ce: Speed 2 + 0x3d1: Power level (init from 0x316 & 0x7f) + 0x3d2: Power level (copy, init from 0x316 & 0x7f) + 0x3d3: Ride change + 0x3e0: Lipo state + 0x3e4: Powerbank soc + 0x3e6: Powerbank serial number (4 bytes) + 0x3ea: Powerbank serial version (3 bytes) + 0x3ed: Powerbank soh + 0x3ee: Powerbank noc + 0x3f1: Powerbank present + 0x3f8: GSM type pointer Battery state + 0x402: Type + 0x406: Error flags + 0x408: Temperature (°C/100) + 0x40a: Voltage (mV) + 0x40c: State of charge (%) + 0x40e: Current (mA) + 0x412: Discharging flag + 0x414: Testmode flag + 0x416: HW version + 0x418: SW version + 0x41a: Serial number (14 bytes) + 0x428: Manufacture date (3 bytes) + 0x42c: cap_nominal + 0x42e: cap_full + 0x430: cap_remain + 0x432: health + 0x434: cycle_count + 0x438: cell_voltage (10 x mV) + 0x44c: tp1 + 0x44e: tp2 + 0x450: mos_tmp + 0x454: u_max + 0x456: u_min + 0x45a: Boot loader version + 0x462: fsr + 0x490: dotp + 0x492: dutp + 0x494: cotp + 0x496: cutp + 0x498: docp1 + 0x49a: docp2 + 0x49c: cocp1 + 0x49e: cocp2 + 0x4a0: ovp1 + 0x4a2: ovp2 + 0x4a4: uvp1 + 0x4a6: uvp2 + 0x4a8: pdocp + 0x4aa: pdscp + 0x4ac: motp + 0xac scp ``` `[1]` [位掩码](vanmoof_sx3_sound_bitmask.md) ## BLE 控制器内部 ROM 中的偏移量: ``` 10000000: TI ROM boot loader 10007000: TI ROM ble5stack 1002b400: TI ROM tirtos7 50001000: FCFG1 500012e8: FCFG1::MAC_BLE_0 500012ec: FCFG1::MAC_BLE_1 50003000: CCFG (mirrored from FLASH 56000) ``` ## BLE 控制器内部 FLASH 中的偏移量: ``` 00000000: bleware.bin 00056000: boot loader 00057f38: boot loader version: "BVERApr 23 2020" 00057f48: boot loader version: "14:10:12" 00057fa8: CCFG (Customer configuration) Mirrored at CCFG 50004fa8 00057fec: CCFG::IMAGE_VALID_CONF -> 56000 (boot loader entry) ``` ## BLE 控制器内部 SRAM 中的偏移量: ``` 2000a3dc: Memory location of UKEY, when used in BLE protocol (1.4.1) 2000a3fc: Memory location of MKEY, when used in BLE protocol (1.4.1) 2000cec8: Memory location of UKEY, when used in BLE protocol (2.4.1) 2000cee8: Memory location of MKEY, when used in BLE protocol (2.4.1) ``` ## update.py 一个简单的 cheasy 更新工具,用于将用 `pack` 打包的固件发送到自行车。运行此工具需要 [pymoof](https://github.com/quantsini/pymoof)。 在使用该工具之前,你需要插入自行车的 API 密钥和制造商密钥。 用作通过 BLE 进行固件更新的参考。 ## read_logs.py 一个简单的 cheasy 工具,用于通过 BLE 从自行车读取内部调试日志。运行此工具需要 [pymoof](https://github.com/quantsini/pymoof)。 在使用该工具之前,你需要插入自行车的 API 密钥。 用作如何通过 BLE 读取日志的参考。 ## 内部通信 主 MCU 通过以下方式与其他 MCU 通信: | UART | TX | RX | 功能 | 协议 | 备注 | | :-- | :-- | :-- | :-- | :-- | :-- | | USART1 | PA9 | PA10 | 替代调试 | console | 可通过调试头 TC1 访问? | | USART2 | PA2 | PA3 | GSM uBlox G350 | AT commands | 在 `gsmdebug` 模式下透传 | | USART3 | PD8 | PD9 | Shifter MCU | [Modbus](https://en.wikipedia.org/wiki/Modbus) || | UART4 | PA0 | PA1 | Battery MCU | [Modbus](https://en.wikipedia.org/wiki/Modbus) || | UART5 | PB13 | PB12 | BLE MCU control | SSP | [SLIP](https://en.wikipedia.org/wiki/Serial_Line_Internet_Protocol) 编码包 | | USART6 | PC6 | PC7 | Motor MCU | SSP | [SLIP](https://en.wikipedia.org/wiki/Serial_Line_Internet_Protocol) 编码包 | | UART7 | PE8 | PE7 | Main MCU debug | console | 尾灯后面的端口 | | UART8 | PE1 | PE0 | BLE MCU debug | console | 在 `bledebug` 模式下透传 | [SLIP](https://en.wikipedia.org/wiki/Serial_Line_Internet_Protocol) 编码的数据包包含一个字节的发送者地址、一个命令字节、一个序列字节、一个表示偏移量或功能码的小端 16 位字、一个 16 位数据长度字、数据和一个 16 位 CRC,该 CRC 与 [Modbus](https://en.wikipedia.org/wiki/Modbus) CRC 相同。 命令字节对于 READ 为 06,对于 WRITE 为 07,对于 ACK 数据包为 05。CRC 是在没有 C80 成帧字符的数据包上计算的。 ``` C0 01 06 56 1A 01 33 F8 C0 MCU -> BLE READ req 56: 0x011a C0 02 05 56 53 6E C0 BLE -> MCU ACK 56 C0 02 07 79 1A 01 06 00 F8 8A 5E XX XX XX YY YY C0 BLE -> MCU WRITE req 79: 0x011a: 0x0006 bytes: 0xF8 8A 5E XX XX XX C0 01 05 79 E2 B2 C0 MCU -> BLE ACK 79 ``` MCU 在同一个数据包处理程序中处理来自 BLE 和 Motor MCU 的两个数据包流,因此 BLE 和 Motor 的偏移量/功能码必须是互不重叠的 (disjunct)。 ## BLE 服务 `6acc5505-e631-4069-944d-b8ca7598ad50` 蓝牙服务 `@5505` 包含后台消息,这些消息用于在自行车上配置 UKEY 或 MKEY,例如用于自行车共享或车间访问。这些消息使用自行车的 MKEY 加密。消息前缀是一个两个字节的随机数 (nonce)、字节 `0x01` 和一个偏移量字节。这 4 个字节未加密。消息紧随其后的是 n * 16 字节的 MKEY 加密数据。 | Nonce | Const 1 | Offset | Encrypted backoffice message | | :-- | :-- | :-- | :-- | | a12d | 01 | 00 | acc3d0f327c70f5a4755185bcb27c40df508b19df62e7551127abe79c9c822326adef001d97d51b45f8c58a7d2cc0cc0 | 解密后的消息构建如下(格式 1): | M-ID | Cmd | Len | UKEY data | Index | Perms | Modbus CRC | Padding | | :-- | :-- | :-- | :-- | :-- | :-- | :-- | :-- | | 00000008 | 0001 | 18 | 98d29703b832207ed7c67b34edfadc02 | 00000002 | 000001f4 | 6845 | 0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f | 消息格式 2: | M-ID | Cmd | Len | Index | Modbus CRC | Padding | | :-- | :-- | :-- | :-- | :-- | :-- | | 00000004 | 0003 | 04 | 00000002 | 2577 | 0505050505 | 消息格式 3: | M-ID | Cmd | Len | State | Modbus CRC | Padding | | :-- | :-- | :-- | :-- | :-- | :-- | | 00000007 | 0005 | 01 | 00 | 5ae4 | 0808080808080808 | 消息格式 4: | M-ID | Cmd | Len | Modbus CRC | Padding | | :-- | :-- | :-- | :-- | :-- | | 00000005 | 0006 | 00 | 6c18 | 090909090909090909 | 消息格式 5: | M-ID | Cmd | Len | UKEY data | Index | Perms | ... | UKEY data | Index | Perms | Modbus CRC | Padding | | :-- | :-- | :-- | :-- | :-- | :-- | :-- | :-- | :-- | :-- | :-- | :-- | | 00000008 | 0001 | 48 | 98d29703b832207ed7c67b34edfadc02 | 00000002 | 000001f4 | ... | cb27c40df508b19df62e7551127abe79 | 00000004 | 000001f4 | xxxx | 07070707070707 | 消息格式 6: | M-ID | Cmd | Len | Unknown1 | Unknown2 | Modbus CRC | Padding | | :-- | :-- | :-- | :-- | :-- | :-- | :-- | | 00000004 | 0008 | 02+n | xxxx | yy .. yy (n bytes) | zzzz | .. | Cmd 值有: | Cmd | Message (format) | | :-- | :-- | | 0001 | Update UKEY (1) | | 0002 | Update MKEY (1) | | 0003 | Erase key by index (2) | | 0004 | Nothing (always succeed) | | 0005 | Set Module State `@5562` (3) | | 0006 | Erase all keys (4) | | 0007 | Update multiple keys (5) | | 0008 | Unknown, read keys? (6) | | 0009 | Unknown, FMNA related | | 000a | Unknown, FMNA related | ## 调试控制台 调试控制台上的 `Login:` 提示符知道两个密码,一个是固件中硬编码的固定密码 `vEVjGF!paYsM2EBV8SoDT8*T0eB&#T6xevaoxCaO`,另一个密码包含自行车 MAC 地址的最后三个字节,后跟单词 "DeBug",由 `printf("%02X%02X%02XDeBug", MAC[3], MAC[4], MAC[5])` 输出。 调试控制台有一个 `help` 命令。通过分别使用命令 `bledebug` 和 `gsmdebug`,也可以从调试端口访问 BLE 芯片和 GSM 调制解调器。 ``` Login: *********** Welcome to ES3 help Available commands: help This tekst reboot reboot CPU login Login shell logout Logout shell ver Software version distance Manual set dst gear set gear region Region 0..3 model model blereset hard reset BLE bledebug redirect uart8 show Parameters motorupdate Update F2806 CPU vollow Audio volume volmid Audio volume volhigh Audio volume speed override speed loop main loop time shipping Shipping mode factory-shipping Factory shipping mode (ignores BMS) logprn Print log logclr Clear log 6 logapp 1/ 0 powerchange 1/ 0 factory Load factory defaults battery Show battery batware Battery update batboot BatteryBL update batreset Battery reset shiftware Battery update shifterstatus Show shifter shiftdebug Show Modbus shiftresetcounter Reset shift counter motorstatus gsminfo Info from Ublox gsmstart start GSM function gsmdebug redirect uart2 bmsdebug Show Modbus sound sample,volume,times adc read adc bwritereg Modbus Bat write register bwritedata Modbus Bat write data breadreg Modbus Bat read register swritereg Modbus Shift write register swritedata Modbus Shift write data sreadreg Modbus Shift read register stc read lipo monitor stcreset setoad test setgear save muco shifter soc overrule soc customsoc sound soc hwrev hardware revision error set errorcode ver ES3.0 Main 1.09.03 (10:30:52 Apr 30 2025) ES3 boot 1.9 Motorware S.0.00.22 BMSWare BL:007 FW:1.17 RSOC:100 Cycles:42 HW:3.10 ESN:XXXXXXXXXXXXXX Shifterware 0.237 stored: 0.237 BLEWare 1.4.01 GSMWare 08.90 CMD_BLE_MAC F8:8A:5E:XX:XX:XX ``` BLE 控制台也有一个 `help` 命令,可以使用命令 `exit` 返回 MCU 控制台。 ``` Login: *********** Welcome to ES3 bledebug Connect to UART8 > help The following commands are available: firmware-update - update a new image of firmware to the external flash extflash-verify - verify the current flashchip log-count - get log-count statistic log-dump - print blocks starting at address log-flush - flush all log-entries log-inject - Create fake-logs audio-play - play audio bound to the specified index audio-stop - stop playing the current audio file audio-dump - dump all audio files in external memory audio-upload - upload audio binary using Y-Modem at the address linked to the specified index audio-volume-set-all - set audio level of all audio-clips (0-3) pack-upload - upload a PACK file by Y-Modem pack-list - list the contents of a PACK file pack-delete - delete a PACK file pack-process - process pack files in external flash memory ble-info - dump current BLE connection info / statistics ble-disconnect - force a disconnect of all connected devices ble-erase-all-bonds - erase all bonds shutdown - shutdown the system rtos-statistics - dump memory stats every 500ms rtos-nvm-compact - Compact the non-volatile storage dump - dump keys/memory/extflash info/ver - show basic firmware info exit - exit from shell help - show all monitor commands > info BLE MAC Address: "f8:8a:5e:xx:xx:xx" Device name ................ : ES3-F88A5EXXXXXX Firmware version ........... : 1.04.01 Compile date / time ........ : May 12 2025 / 09:03:35 BIM firmware version ....... : 1.00.00 BIM compile date / time .... : Apr 23 2020 / 14:10:12 reset type ................. : pin reset systick .................... : -117259002 > exit ``` GSM 控制台使用扩展的 ublox [AT](https://en.wikipedia.org/wiki/Hayes_AT_command_set) 命令。可以使用序列 `[14~` 退出。 ``` Login: *********** Welcome to ES3 gsmdebug Modem powering on.. ATI SARA-G350-02S-01 OK AT+UGSRV? +UGSRV: "ublox1.vanmoof.com","ublox1.vanmoof.com","PBNjh0V46Eev8CcfS4LPJg",14,4,1,65,0,15 OK AT+UPSDA=0,3 OK AT+UPSND=0,8 +UPSND: 0,8,1 OK AT+ULOCIND=1 OK AT+ULOC=2,2,1,180,1,10 OK +UULOCIND: 0,0 +UULOCIND: 1,0 +UULOCIND: 2,0 +UULOCIND: 3,0 +UULOC: 16/05/2025,08:27:54.000,,,0,601,0,0,0,2,0,0,0 ``` ## 想法 我发现发送大于 256 字节的固件更新包时控制器会崩溃,因此可能有机会利用这一点作为 exploit 通过蓝牙读出 MKEY。我们需要 MKEY 才能: - 解码从 Vanmoof 收到的更新包 - 向自行车发送我们自己的更新包(修补了诸如 offroad 等功能) ## 外部资源 - [线束](https://www.moofrepair.nl/wiring-harness/) - [调试控制台](https://www.reddit.com/r/vanmoofbicycle/comments/17744l7/comment/k4z0wyi/?utm_source=share&utm_medium=web3x&utm_name=web3xcss&utm_term=1&utm_content=share_button) - [硬件信息](https://github.com/ciborg971/VanmoofX3RE/tree/master/OG) - [硬件信息](https://github.com/dtngx/VMBattery) - [pymoof](https://github.com/quantsini/pymoof) ## 特别感谢! - [Tobias](https://github.com/Knight1) - [Quinten](https://github.com/quintenadema) - [Max](https://github.com/MPeek1995) ## 趣闻 VanMoof 使用的魔数以前曾被其他人使用过,这在使用 unix `file` 命令时会产生一些有趣的输出: ``` $ file packfile.bin packfile.bin: Quake I or II world or extension, 340 entries $ file mainware.bin mainware.bin: BIOS (ia32) ROM Ext. (85*512) ```
标签:Cutter, Linux工具, Raspberry Pi, STM32, TI CC2642, VanMoof, 二进制分析, 云安全运维, 云资产清单, 内存执行, 固件分析, 固件解包, 客户端加密, 嵌入式安全, 物联网, 电动自行车, 硬件黑客, 端口探测, 蓝牙低功耗, 逆向工具, 逆向工程