RT-4D: реверс прошивки, русификация, кастомный UI, флешеры
- Полный RE стока V3.25 (Cortex-M4F) + FM100B: карта памяти, протокол, codeplug, UI-архитектура - Русификация: свой CP1251-шрифт + патч рендера, перевод меню и надписей, ребренд Ru-4D V3.25 - Блюпринт переделки UI + C-тулчейн (clang thumbv7em), доказан инъекцией - Готовые флешеры: WebSerial .html и Windows .exe со вшитой прошивкой - Дамп SPI рации, стоковая прошивка, инструменты сборки Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Этот коммит содержится в:
@@ -0,0 +1,45 @@
|
||||
import struct, sys, io
|
||||
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')
|
||||
DUMP = r"C:/Users/vikto/Documents/Claude/rt-4d/radio-spi-dump.bin"
|
||||
data = open(DUMP, "rb").read()
|
||||
CT_BASE = 0x05C000; ZN_BASE=0x01C000
|
||||
def hx(b): return " ".join(f"{x:02X}" for x in b)
|
||||
def parse_bcd(bcd):
|
||||
if all(b==0xFF for b in bcd): return 0
|
||||
r=0
|
||||
for bv in reversed(bcd):
|
||||
hi=(bv>>4)&0xF; lo=bv&0xF
|
||||
if hi==0xF: hi=0
|
||||
if lo==0xF: lo=0
|
||||
r=r*100+hi*10+lo
|
||||
return r
|
||||
|
||||
# Scan contacts region for any non-FF records
|
||||
print("CONTACTS scan (non-0xFF b0):")
|
||||
cnt=0
|
||||
for i in range(2048):
|
||||
off = CT_BASE + i*32
|
||||
d = data[off:off+32]
|
||||
if all(b==0xFF for b in d): continue
|
||||
name = bytes(b for b in d[0x10:0x20] if b!=0xFF).decode('gbk','ignore').strip()
|
||||
dmr = parse_bcd(d[0x02:0x06])
|
||||
print(f"ct{i} @0x{off:06X} b0={d[0]:02X} type(b1)={d[1]} dmr(BCD@2)={dmr} name={name!r}")
|
||||
print(" raw:", hx(d))
|
||||
cnt+=1
|
||||
if cnt>=8: break
|
||||
print("total non-FF contact records:", sum(1 for i in range(2048) if not all(b==0xFF for b in data[CT_BASE+i*32:CT_BASE+i*32+32])))
|
||||
|
||||
print("\nZONES:")
|
||||
for i in range(256):
|
||||
off=ZN_BASE+i*512
|
||||
d=data[off:off+512]
|
||||
if d[0]==0xFF: continue
|
||||
name=bytes(b for b in d[0x04:0x14] if b!=0xFF).decode('gbk','ignore')
|
||||
count=d[0]|(d[1]<<8)
|
||||
print(f"zone{i} @0x{off:06X} count={count} curA={d[2]} curB={d[3]} name={name!r}")
|
||||
print(" head:", hx(d[0:0x14]))
|
||||
chans=[d[0x14+k*2]|(d[0x15+k*2]<<8) for k in range(min(count,30))]
|
||||
print(" chans:", chans)
|
||||
print(" scan@0x1A4:", hx(d[0x1A4:0x1A4+25]))
|
||||
# dump any nonzero bytes between end of chan list and scan
|
||||
print(" 0x194-0x1A4:", hx(d[0x194:0x1A4]))
|
||||
Ссылка в новой задаче
Block a user