feat(ppclock): protocol.py 协议编解码 23 测试全绿(BCD语义经JS证据校正)

This commit is contained in:
agent committed 2026-07-24 10:43:33 +00:00
1 parent 190182fb2e
commit 6f5b0c60be
11 files changed
+32843

No files matched your search

+55
View File
@@ -0,0 +1,55 @@
#!/usr/bin/env python3
"""Scan firmware for command-dispatch CMP-immediate and branch-switch patterns."""
from capstone import Cs, CS_ARCH_ARM, CS_MODE_THUMB, CS_MODE_LITTLE_ENDIAN
import struct, collections
IMG = "app/firmware-PP_da14585_4.2_CH.img"
BASE = 0x07FC0000
HDR = 0x40
CODE_END = 0x119e4 # code region size
CMDS = {0xdd:"time", 0xe2:"commit", 0x03:"img_blk_full", 0x04:"img_blk_small",
0x01:"refresh", 0xAA:"refresh_small", 0xEF:"activate", 0xE6:"lut_cal",
0xFB:"sleep_time", 0xEA:"slot", 0xFA:"countdown_off", 0xE1:"mode",
0xE3:"invert", 0xE4:"font", 0xE5:"rotate", 0x23:"bw_3color", 0x14:"12_24h",
0x15:"clk_color", 0x99:"cal_text", 0x00:"refresh_step1", 0xE9:"carousel"}
def main():
data = open(IMG, "rb").read()[HDR:HDR+CODE_END]
md = Cs(CS_ARCH_ARM, CS_MODE_THUMB | CS_MODE_LITTLE_ENDIAN)
# collect all instructions via same sweep
insns = []
off = 0
while off < len(data):
chunk = data[off:off+0x2000]
addr = BASE + off
consumed = 0
for ins in md.disasm(chunk, addr):
if ins.address < addr + consumed:
continue
gap = ins.address - (addr + consumed)
if gap:
consumed += (gap // 2) * 2
insns.append(ins)
consumed = ins.address + ins.size - addr
off += consumed if consumed else 2
# CMP Rn, #imm with imm in CMDS
hits = collections.defaultdict(list)
for ins in insns:
if ins.mnemonic == "cmp":
parts = ins.op_str.split(",")
if len(parts) == 2 and parts[1].strip().startswith("#"):
try:
v = int(parts[1].strip()[1:], 0)
except ValueError:
continue
if v in CMDS:
hits[v].append((ins.address, ins.op_str))
for v in sorted(hits):
print(f"--- CMP #0x{v:02x} ({CMDS[v]}): {len(hits[v])} hits ---")
for a, ops in hits[v]:
print(f" 0x{a:08x}: cmp {ops}")
if __name__ == "__main__":
main()