Files
qianbian/docs/firmware-analysis.md

21 KiB
Raw Permalink Blame History

firmware-PP_da14585_4.2_CH.img 逆向分析报告

目标文件:app/firmware-PP_da14585_4.2_CH.img,72228 字节 平台:Dialog DA14585(ARM Cortex-M0,仅 Thumb),SysRAM 96KB @ 0x07FC0000–0x07FD8000 工具:analysis/firmware/fw_parse.py(头解析+CRC)、analysis/firmware/disasm.py(capstone 线性扫描)、analysis/firmware/find_cmds.py(命令立即数扫描)、analysis/firmware/fw.asm(全量反汇编,32098 指令) 地址约定:文件偏移 = 映射地址 - 0x07FC0000 + 0x40(映射地址 = 文件偏移 - 0x40 + 0x07FC0000)

0. 结论速览

问题 结论
固件是否可控 完全可控。BLE 命令处理无任何鉴权/加密门槛,全部命令(图像、刷新、模式、时间)连接即可用;激活只是云端生意,固件侧不锁功能
如何实现 OTA 固件内置完整 SPOTA 协议栈(自定义任务 0xFC,MEM_DEV/GPIO_MAP/MEM_INFO/PATCH_DATA 四消息),接收方校验 70 51+AA 头后写入 SPI Flash 0x38000 备bank,可直接复用本镜像格式做 OTA
命令解析在哪 EPD 通道分发 @ 0x07FCBC64(handle 2/7/0xB);RXTX 命令分发器 @ 0x07FCBDE4(0xDD–0xEF 跳表 @ 0x07FCBEEA + 0x14/0x15/0x23/0x88/0x99/0xCC/0xFA/0xFB/0xFF 直比链)
墨水屏驱动 SSD1683 兼容(主路径,cmd 0x01 传 0x2B 0x01=300 行、0x44/0x45 设 50×300、0x24/0x26 双平面)+ 备选 UC8151/IL0373 兼容 路径(state[0x1c] 切换);波形用驱动 IC 内部 OTP LUT,固件无 LUT 表
激活机制 本地弱哈希,可离线算出。激活码 = 6 字节,code[i] = rol2((MAC[i]<<1 & 0xFF) ^ 0xEF) % 101,MAC 即设备 BD 地址(BLE 广播可见 / EFEF 应答的 14 字符设备 ID 可完整还原)

1. 镜像格式(任务1)

1.1 头结构(64 字节,Dialog SUOTA/multi-image 格式)

偏移 字段 值 验证
0x00 magic 70 51('pQ',LE 0x5170 = IMAGE_VALID) ✓
0x02 signature AA 01(OTA 接收方校验首字节==0xAA,见 0x07FCB4F2 处 cmp r0,#0xaa) ✓
0x04 code_size E4 19 01 00 = 0x119E4 = 72164 = 文件长 72228 - 64 ✓ 精确匹配
0x08 CRC32 10 4D 89 6C = 0x6C894D10 ✓ = 标准 zlib CRC32(poly 0xEDB88320,init/xorout 0xFFFFFFFF)over 数据区 72164 字节(fw_parse.py 实测 match=True;BZIP2/MPEG-2/POSIX 变体均不匹配)
0x0C–0x3F reserved 0xFF,仅 0x20 处一字节为 0x00 ✓

1.2 镜像布局图

文件偏移      映射地址         内容
0x000000      -               64B 镜像头('pQ' + len + CRC32)
0x000040      0x07FC0000      向量表:SP=0x07FD2B58, Reset=0x07FC0525, SysTick=0x07FC522B,
                              IRQ0=0x07FC221D, IRQ1=0x07FCA975(BLE), IRQ2=0x07F0271D(ROM), ...
0x0000C0~     0x07FC0080~     代码(Thumb)+ 内嵌字库/模板数据
  ~0x00C800   ~0x07FCC800     点阵字库区(大量 16px 字形位图,如 f0x00de30 起)
  ~0x00F900   ~0x07FCF8C0     GATT 描述符/UUID 表/消息handler表/DIS 属性表
0x010000~     0x07FD0000~     初始化数据区:DIS 字符串、22 个祝福词、adv 数据模板、TLV 记录
0x0119E4      0x07FD19E4      代码区结束(= code_size)
-             0x07FD19E8      BSS:全局状态结构体 state(激活码/设备ID/时间/显示参数)
-             0x07FD2B58      初始栈顶

SPI Flash 布局(由固件内常量推得,芯片 ≥ 512KB):

Flash 偏移 用途 证据
0x00000 主固件 bank(boot ROM 加载到 SysRAM) 标准 DA14585 boot
0x2E000–0x35FFF 显示帧缓存(8×4KB sector 擦除后顺序写,整图双平面 30000B) cmd 03 处理 0x07FCBD0C:movs r0,#0x17; lsls r5,r0,#0xd=0x2E000,循环 8 次 bl 0x07FCAB74(sector 擦除),写函数 0x07FCAE4C
0x38000 OTA 备 bank:+0x00 产品头(校验 70 52 'pR'),+0x40 镜像头(校验 70 51+AA) OTA 接收 0x07FCB4AA:bl 0x07FC5AC4 读 0xC 字节后 cmp #0x70/cmp #0x52;0x07FCB4F8 cmp #0x70/cmp #0x51、0x07FCB4F2 cmp #0xaa
0x3F0EF+sum(MAC[0:3]) / 0x3F1DE+sum(MAC[0:6]) 激活码写入槽(6B×2,地址由 MAC 求和混淆) 0x07FC7C18:ldr r1,=0x0003F0EF(literal @0x07FC7C58);0x07FC7C28 adds r1,#0xef;存于 state[0x3C]/state[0x40]

2. GATT 表(任务3)

2.1 UUID 出现位置(均小端存储)

UUID 文件偏移 映射地址 说明
EPD Service 13187b10-…-83d3217d9a38 0x00FF0C 0x07FCFECC 128-bit 原始 16 字节
EPD Char 4b646063-…-e65356ea82fe 0x00F972 0x07FCF932 128-bit,被 0x07FCFD7C 处描述符引用
RXTX Service 0x1F10 0x00FF28(16B 项起于 0x00FF20) 0x07FCFEE8 以 128-bit 蓝牙基 UUID 形式 FB 34 9B 5F 80 00 00 80 00 10 00 00 10 1F 00 00
RXTX Char 0x1F1F 0x00F98E(项起于 0x00F982) 0x07FCF94E 同上形式
第三 Service 0x221F 0x00FF38(项起于 0x00FF30) 0x07FCFEF8 web 端声明但未用——疑似 SUOTA 通道
Char 0x331F 0x00F99E(项起于 0x00F992) 0x07FCF95E 0x1F10/0x221F 服务下的另一特征
DIS 属性表(0x2800/0x2803 + 0x2A29/24/25/27/26/23/2A/50) 0x00FF3C 起 0x07FCFEFC 起 12 字节/项 {uuid32, perm, aux},被 0x07FC7094 处注册代码引用
GAP/BAS 表(0x2A00/0x2A01/0x2A19 电量 + 0x2902 CCC) 0x00FBB0 起 0x07FCFB70 起 BASS 任务消息 0x2400/0x2402 @0x07FCFBC4

EPD svc UUID 被 0x07FCFD64 引用、EPD char UUID 被 0x07FCFD7C 引用(GATT DB 描述符簇 0x07FCFD54–0x07FCFE68,三个服务各一簇)。

SPOTA/SUOTA UUID(0xFEF6–0xFEFB)在镜像中不存在(搜 f6fe/f7fe/…/fbfe 仅命中 BL 指令编码,无相邻簇),但:

  • 广播数据模板含完整 16-bit 服务列表 0x180A(DIS)+0xFEF5(SPOTA):0x07FD094A 05 03 0a 18 f5 fe(证据:文件 0x01098A)
  • SUOTA 功能以自定义任务 0xFC + 自定义 service(疑似 0x221F)实现,见 §5

2.2 应用消息 handler 表(ke_msg_handler {u32 id, u32 func})

  • GAPM 表 @ 0x07FCFE68:0x0C13→0x07FC7EE5、0x0C15→0x07FC80C1、0x0C17→0x07FC7C6D、0x0C00→0x07FC7D19…
  • 显示/应用任务 0xFD 表:0xFD06→0x07FC6B9D、0xFD03→0x07FC6C1D、0xFD08→0x07FC6B25、0xFD0E→0x07FC6591、0xFD05→0x07FC6C41(@0x07FCFE88 起)
  • GATTC 表 @ 0x07FCFB00:0x0E08→0x07FC79F1、0x0E13→0x07FC7619、0x0E15→0x07FC7529、0x0E17→0x07FC7939、0x0E19→0x07FC7921、0x0D15→0x07FC7A51、0x0D21/0x0D22→0x07FC7C69/0x07FC7C65
  • SUOTA 任务 0xFC 表 @ 0x07FCFB50:FC00→0x07FCB6F9、FC01→0x07FCAEED、FC02→0x07FCB6B9、FC03→0x07FCB3F1(文件 0x00FB90–0x00FBAF)

3. 命令解析(任务4)

3.1 写入口

GATT 写总入口 0x07FCBC64(4 个 BL 调用方:0x07FC58B6/0x07FC757E/0x07FC7784/0x07FC7AB8,均为 GAP/GATT 事件包装)。按消息 id(0xFD04/0xFD0D/0xFD0A,literal @0x07FCBDB8–0x07FCBDC0)分流;0xFD0A 按 handle 分流:

handle 去向 证据
2 EPD 数据通道(0xAA/03/04/01) 0x07FCBC84 cmp r0,#2
7 RXTX 命令分发器 0x07FCBDE4 0x07FCBC80 cmp r0,#7
0x0B 同上(第二命令特征,疑 0x331F) 0x07FCBC7C cmp r0,#0xb

写参数结构:[r4,#2]=handle,[r4,#4]=len,[r4,#6]=opcode,[r4,#7..]=payload。

3.2 EPD 通道(图像数据)

@ 0x07FCBC94:ldrb r0,[r4,#6] 后依次比 0xAA / 3 / 4 / 1:

opcode 处理 证据
03 整图:首包擦除 Flash 0x2E000 起 8 sector,随后按 state[0x2A] 累计偏移经 0x07FCAE4C 顺序写 Flash(忽略包内 offset 与平面字节),长度=len-4 0x07FCBD0C–0x07FCBDB6
04 日历小图:按包内 BE offset 写 RAM:[7]==0xFF→0x07FD4B18+off(无边界检查!);[7]==0x00→0x07FD0A0A+off(边界 0xAA9);数据=r4+0xA,len-4 0x07FCBD3C–0x07FCBD80;literal @0x07FCBDC8/0x07FCBDD8/0x07FCBDDC
01 整图结束:state 清零 + bl 0x07FC6E98(Flash 落盘/刷屏准备) 0x07FCBCA2–0x07FCBCAE
AA 小图结束:置标志 + bl 0x07FCA880(0) 触发刷新编排 0x07FCBD82–0x07FCBD8E
00 忽略(web 的 clearScreen 第一步是固件侧 no-op) 0x07FCBC9A 链无匹配落 0x07FCBD02

3.3 RXTX 命令分发器 0x07FCBDE4(文件 0x00BDA4)

前置:opcode 0–4 且 len≥0x1F → 数据写(拷贝 (op&7)×32 字节到 0x07FD17BD,op 记入 0x07FD09D0);opcode 5–8 且 len≥0x1F → 写 0x07FD183D。这覆盖 web 的 04{128B} 倒计时前缀位图(op 4→128B ✓)。 随后 subs r1,#0xdd; cmp r1,#0x12; bls → 跳表 @ 0x07FCBEEA(19 项,target=0x07FCBEEE+entry×2,表体文件 0x00BF2C):

opcode target 语义(与 web 对照)
DD 0x07FCBF12 设时间:LE 4 字节 unix → state[0x78],并换算;只用前 4 字节(web 的年月日周字节被忽略)✓
E1 0x07FCBF78 模式:[7]==0→图模式(0x07FCBF8C,state[2]=0+刷新);==1→日历(0x07FCC10A,循环/可指定,state[0x14]=0);==2→时钟(0x07FCC12E,state[0x14]=1)✓
E2 0x07FCBF64 提交:查显示状态后 → 0x07FCC0D0 → bl 0x07FCA880(1) 刷新 ✓
E3 0x07FCC0D0 反色 → bl 0x07FCA880(0) ✓
E4 0x07FCBF98 时钟字体 state[0x25] 0/1 循环 ✓
E5 0x07FCBF58 旋转 180°:state[0x11] 翻转 ✓
E6 0x07FCBF70 LUT/VCOM 校准字节 → 显示参数结构 0x07FD09D0+6,然后刷新。平面写函数 0x07FC8648 @0x07FC86EA 读该字节并按 0x10 分界(<0x10 红平面 / ≥0x10 黑平面)——与 web 文档"01–0f 设红、10–f0 设黑"精确一致 ✓
EF 0x07FCBFAA 激活/取设备 ID,见 §4
DE–E0, E7–EE 0x07FCC0D6 空操作(含 web 在用的 E9 轮播间隔、EA 槽位——本固件忽略)✗差异

跳表外直比链(0x07FCBE54–0x07FCBE88):

opcode target 语义
14 0x07FCC004 12/24h:state[0x23] 翻转 ✓
15 0x07FCC0A0 时钟颜色:state[0x19]^=1 ✓
23 0x07FCC058 三色/黑白:state[0x18]=[7]&1;并写参数[6]=0x0C/0x80 ✓
88 0x07FCC092 置标志位 0x8000(web 未用)
99 0x07FCC068 日历倒计时文字:len≥0x1F 时按 [7]×0x48 拷贝 72 字节/字符 到 0x07FD18BD 基缓冲,[7]+1 记字符数 ✓(与 web 990{j}{72B} 一致)
CC 0x07FCBFEE 参数[5]:>0xE0 或 ≤0x47 时钳到 0x48(web 未用)
FA 0x07FCC04A 关闭倒计时:state[0x24]=1,参数[2]=2 ✓
FB 0x07FCC010 休眠时段:BCD 解析 [7]=开关、[8]=HH、[9]=MM → state[0x13]/参数+3/+4 ✓
FF 0x07FCBE8A len==6 时:FF 00→0x07FCC152 时钟倒计时日期(BCD 年×100+月+日 → 结构+0x10/14/18,state[0xD]=1);FF FF→0x07FCBEA0 日历倒计时日期(→ +0x1C/20/24)✓

web 有而固件无:E9/EA(no-op)、ASCII WIFI_SSID:...(固件无此字符串、无解析路径,直接忽略)——本固件为纯 BLE 版,WiFi/天气属其他 SKU 或云端能力。

4. 激活验证逻辑(任务6)——可离线绕过

4.1 EF 处理路径(0x07FCBFAA)

[r4,#7]==0xEF 且 len==2  →  "EFEF":bl 0x07FCA22C 生成设备ID,
                             循环 r5=0x14..0x21 把 14 字节经 ke_msg 发回(notify 应答)✓ 与 web "14B 设备ID"一致
否则                     →  比较循环 @0x07FCC0AA:r4[7..12](收的 6 字节) vs state[0x44..0x49]
  全部相等 → 0x07FCC0DE:state+0x4A(6B)写 Flash[state[0x40]]、state+0x44(6B)写 Flash[state[0x3C]]
             (写函数 0x07FCAE4C,与图像写 Flash 同一函数,证实为 SPI Flash 写)
  不等     → 0x07FCC0D6 直接返回(无任何惩罚/锁定)

4.2 比较目标 state[0x44] 的来源 = MAC 哈希(关键发现)

启动初始化函数 0x07FC23D0(被 0x07FC7C30/0x07FC877E 调用)尾部 0x07FC24C8–0x07FC24F4,对 i=0..5 循环:

t        = ((MAC[i]<<1) & 0xFF) ^ 0xEF        ; ldrb→lsls#1→eors ~0x10→uxtb
code1[i] = ((t<<6)+(t>>2)) & 0xFF  % 101      ; = rol2(t) % 0x65,经 __aeabi_uidivmod(0x07F1DFB8)
→ 存入 state[0x44+i]
  • MAC = state[0x4A..0x4F] = 设备 BD 地址,由工厂函数 0x07FC7B94 经 NVDS/TLV 读取(0x07FCA2DC,tag 1 = Dialog NVDS BD_ADDRESS;缺省记录 @0x07FD04BA:14 00 06 00 70 ca ea 80 d0 07…)
  • 设备 ID(EFEF 应答)生成 @ 0x07FCA22C:snprintf(state+0x14, "%02X"*7 @0x07FCA298, |MAC4-0x99|, |MAC5-0x99|, |MAC3-0x99|, |MAC2-0x99|, |MAC1-0x99|, |MAC0-0x99|, flags);flags=state[0x10] = 各 MAC 字节 ≥0x9A 的位掩码(0x07FC23D4–0x07FC23F4 计算)——14 个十六进制字符 + 掩码可无损还原 6 字节 MAC
  • state[0x3C]/[0x40](激活码 Flash 写地址)= 0x3F0EF + MAC[0]+MAC[1]+MAC[2] 与 0x3F1DE + sum(MAC[0..5])(0x07FC7C0C–0x07FC7C2C,常数 literal @0x07FC7C58 = 0x0003F0EF)——按 MAC 求和混淆存放
  • 全镜像不存在从 Flash 读回激活码的代码(Flash 读函数 0x07FC5AC4/0x07FC5A2C 仅 OTA 路径调用);0x07FC4CDC 每次刷新都会把这两个槽清零并按 RAM 码非零置 state[0xE]/[0xF](显示合成开关,非门锁)

4.3 绕过结论

  1. 激活码是纯本地函数:code[i] = rol2(((MAC[i]<<1)&0xFF)^0xEF) % 101(i=0..5),无需厂商服务器。
  2. MAC 获取:BLE 广播地址直接可见;或发 EFEF 收 14 字符 ID 按上式反解。
  3. 固件侧 EF 成功/失败均不门禁任何后续命令(03/04 图传、E1/E2 刷新等在未激活状态同样解析)——激活仅是厂商云端商业模式,本地使用可直接无视;如需让屏幕不再显示激活页,发送一次正确 EF 即可(或直接 patch §8 所述字节)。

5. OTA / SUOTA(任务3+可行性)

证据链:

  1. 任务 0xFC 四消息(表 @0x07FCFB50):FC00=MEM_DEV(0x07FCB6F8)、FC01=GPIO_MAP(0x07FCAEED)、FC02=MEM_INFO(0x07FCB6B8)、FC03=PATCH_DATA(0x07FCB3F0)——与 Dialog SPOTA 语义一一对应。
  2. 写转发器 0x07FC8340:按服务内 handle 偏移([r4,#6]=起始 handle,偏移 2–13 跳表 @0x07FC8392,12 项=6 特征×2)把特征写打包成 0xFC00–0xFC03 消息(0x07FC83CC:movs r0,#0x3f;lsls r0,#0xa=0xFC00;literal 池 @0x07FC8520–0x07FC8528 = FC02/FC03/FC01)。6 特征 = SPOTA 标准集(mem_dev/gpio_map/mem_info/patch_len/patch_data/serv_status)。
  3. 接收写盘 0x07FCB3F0:state[0x1C] 状态机(0x10–0x13);0x200 字节块缓冲(0x07FCB424 lsls r1,#9);XOR 校验和累计(0x07FCB448–0x07FCB458,存 state[0x24]);收满后校验缓冲头 70 51(0x07FCB486–0x07FCB492)→ 写 Flash;并回读 0x38000 校验产品头 70 52(0x07FCB4BC/0x07FCB4C4)与镜像头 70 51 AA(0x07FCB4F2–0x07FCB502)。
  4. 广播数据声明 SPOTA 0xFEF5(0x07FD094A)。

OTA 实施建议:按本镜像格式(64B 'pQ' 头 + zlib CRC32)打包 → 连接后走 SUOTA 服务(web 端声明但未用的 0x221F,待实机确认句柄;可先 btgatttool 枚举含 6 特征的服务)→ MEM_DEV 写 SPI flash 基址、PATCH_DATA 分块(块内无需应用层 ACK,结束由接收方校验头+长度+XOR)→ 完成后设备复位,boot ROM 按产品头切换 bank。风险:bank 切换依赖 boot ROM 读 0x38000 产品头,首次实机前建议先用一份仅改版本字符串的镜像验证。

6. 墨水屏驱动(任务5)

低层原语:发命令 0x07FC3646(CS/DC=cmd)、发数据 0x07FC33D0、SPI 读 0x07FC31B4、GPIO 配置 0x07FC3658(P0/P1 基 0x50003000,literal @0x07FC3694)、SPI1 基 0x50001200(literal @0x07FC32B8 等)、延时 0x07FCB8EC。

6.1 驱动 IC 识别 —— 双面板支持,state[0x1C] 选择

主路径 state[0x1C]==0:SSD1683 兼容(面板初始化 0x07FC3440,证据 @0x07FC34C8–0x07FC3562):

12            ; SWRESET,延时 200ms(0x07FC34CE bl 0x07FC3154, r0=0xC8)
74 / 54       ; 模拟块控制
7E / 3B       ; 数字块控制
2B / 04 63    ; VCOM/ACVCOM
0C / 8B 9C 96 0F ; Booster soft start(GDEY042 系列特征序列)
11 / 01       ; data entry mode
44 / 00 31    ; RAM X: 0–49 → 50 字节 = 400 列 ✓
45 / 2C 01 00 00 ; RAM Y: start 0x012C=300, end 0(反向寻址) ✓ 300 行
3C / 01       ; border
22 / B1, 20   ; 装载温度+主激活
4E / 00, 4F / 2C 01 ; RAM 计数器

另有 0x07FC3344 发 01 / 2B 01 / (1-state[0x20]) = Driver Output Control,mux 0x012B=299 → 300 行(400×300 三色 4.2" 实锤)。温度读取 @0x07FC32BC:18/80、22/B1、20、1B 读 2 字节 >>4 带符号(bit 0x800)→ state[0x28]。

备选路径 state[0x1C]!=0:UC8151/IL0373 兼容(0x07FC3476 起):

01 / 03 00 26 26 (0F|03)   ; Power Setting(VGH/VSH/VSL/VDHR)
06 / 17 17 17              ; Booster Soft Start
50 / (97|51) 60            ; VCOM & Data Interval
22 / 04, 延时 200

面板类型 state[0x1C] 由 TLV 记录(tag 0x40–0x44,读取器 0x07FCA2DC 跳表 @0x07FCA2F4)配置。

6.2 刷新编排 0x07FCA880

读温度→选波形参数(0x07FC3440)→ 平面写 0x07FC8648 两次:(0x24|0x10, 0) 与 (0x26|0x13, 2)——0x24/0x26 = SSD168x 写黑/红 RAM;0x10/0x13 = UC8151 写 RAM1/RAM2,按面板标志 state[0x1E]/[0x1F] 选择 → ADC 读电池(0x07FC6374,state[0x2C]=百分比)→ 计数 state[0x2B]。

6.3 LUT

固件内无 LUT 表:全程未发 0x32(Write LUT),波形用驱动 IC 内部 OTP LUT;E6 命令仅存校准字节到 0x07FD09D0+6,平面写时按 <0x10/≥0x10 分红/黑平面生效(0x07FC86EA)。两段"LUT 候选"(0x07FD06F8/0x07FD187D)实为清零/0xFF 填充的间隙区,非 LUT。

7. 字符串交叉引用(任务7)

字符串 位置 引用点 用途
TEW MI YAO: 0x07FC2508 (f0x002548) adr @0x07FC2414 开机/未激活屏第一行标题(经 0x07FCC1C4 snprintf 到显存,随 0x07FC23D0 绘制)
H:mspppclock.tech 0x07FC251C adr @0x07FC244A 激活屏:厂商主机名(仅显示用,固件无联网代码)
V:PP_da14585_4.2 0x07FC2530 adr @0x07FC2464 激活屏:固件版本
WX:2549294317 0x07FC2544 adr @0x07FC247C 激活屏:微信联系方式
MAC:%02X%02X… 0x07FC2554 adr @0x07FC24A0 激活屏:显示 BD 地址
%02X%02X%02X%02X%02X%02X%02X 0x07FCA298 adr @0x07FCA286 设备 ID(14 hex)格式串,0x07FCA22C
%d %02d / %d %02d %02d / %s %s 等 0x07FC2D88/90/58/60 adr @0x07FC2D1E/22/C4/C8 时钟/日历屏文本排版
Happiness…Motive(22 词) 0x07FD034C–0x07FD04B8 指针表 @0x07FC9708 日历模式每日一词
DA14585 / PP_da14585_4.2 / 1.0.0.0-LE / Dialog Semi 0x07FD02C4/0x07FD08B9/0x07FD08D0/0x07FD08F6 DIS 表 DIS 0x2A24/0x2A26/0x2A27/0x2A29 值
NRF-XXXXXX 0x07FD0956 0x07FCA210、0x07FCBC4C 广播名模板(X 由 MAC 填充;web 端 namePrefix:'NRF-' ✓)
0123456789abcdef/ABCDEF 0x07FCC638/0x07FCC64C hex 工具 通用

Sun/Mon/Tues/Wednes/Thurs/Fri/Satu(0x07FD0482 起,定长 8B)与 中华人民共和国(0x07FD0920,UTF-8)为日历显示素材。

8. 固件修改/重打包建议

  1. 重打包:改完代码区后用 fw_parse.py 同算法重算 zlib CRC32 写回头 0x08,长度不变则无需改 0x04;经 §5 SUOTA 通道或 UART boot 烧录。
  2. 免激活 patch:将 0x07FCC0AA 比较循环的首分支 beq(0x07FCC0BC 处 beq #0x7fcc0ac 的 fall-through b #0x7fcc0d6)改为直接跳成功分支,或把 EF 处理改成总写 Flash——但更简单的做法仍是按 §4.3 公式算码发送。
  3. 去激活开机屏:0x07FC23D0 的 r0 判分支(0x07FC23F6 cmp r0,#0; beq)强制走 0x07FC24C4 即可跳过 TEW MI YAO/MAC/WX 屏。
  4. RAM 无边界写注意:cmd 04 的 0xFF 平面分支(0x07FCBD48)无长度检查,自研上位机时不要越界(会踩 0x07FD4B18 之后的 BSS)。
  5. 手柄速查:EPD 数据 handle 2;命令 handle 7 与 0x0B(同一解析器);SUOTA 服务=含 6 特征(12 句柄)的服务(枚举确认)。
  6. 排产注意:固件忽略 E9/EA/WIFI 命令——自研上位机不必实现;倒计时文字位图经 opcode 0–8 数据通道(len≥0x1F)而非 0x99 之外的格式。

附:关键地址速查

名称 映射地址 文件偏移
镜像头 - 0x000000
Reset handler 0x07FC0525 0x0004E5
GATT 写总入口 0x07FCBC64 0x00BC24
RXTX 命令分发器 0x07FCBDE4 0x00BDA4
0xDD–0xEF 跳表 0x07FCBEEA(表体) 0x00BF2C
EF 激活处理 0x07FCBFAA 0x00BF6A
激活码 keygen(boot) 0x07FC24C8 0x002488
设备 ID 生成 0x07FCA22C 0x00A1EC
SUOTA PATCH_DATA 接收 0x07FCB3F0 0x00B3B0
SUOTA 写转发器 0x07FC8340 0x008300
面板初始化(SSD1683/UC8151) 0x07FC3440 0x003400
刷新编排 0x07FCA880 0x00A840
平面写(0x24/0x26/0x10/0x13) 0x07FC8648 0x008608
Flash 写(页) 0x07FCAE4C 0x00AE0C
Flash 读 0x07FC5AC4 / 0x07FC5A2C 0x005A84 / 0x0059EC
Flash sector 擦除 0x07FC58E0 / 0x07FCAE8C 0x0058A0 / 0x00AE4C
全局状态 state 0x07FD19E8(BSS) -
显示参数结构(E6 字节 +6) 0x07FD09D0 0x010990
cmd04 RAM 缓冲 0xFF/0x00 0x07FD4B18 / 0x07FD0A0A -
文字位图缓冲(op0–8/99) 0x07FD17BD / 0x07FD183D / 0x07FD18BD -