Files
rt-4d/research/deep4.py
T
viktorиClaude Opus 4.8 ae36c3b729 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>
2026-07-08 15:47:22 +09:00

52 строки
2.3 KiB
Python

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()
# 0x126000 decode as call-log. Fields observed:
# b0=00, b1=type(1=priv/grp,2=?), b2=01, b3=00, b4-5=?, b6-9=dmr_id LE, b10-13=counter LE,
# b14-19 = YY MM DD HH MM SS, rest 0
print("### 0x126000 decoded call-log entries ###")
for i in range(16):
o=0x126000+i*32
r=data[o:o+32]
if r[14]==0 and all(b==0 for b in r[:14]): break
b1=r[1]; b4=struct.unpack('<H',r[4:6])[0]
dmr=struct.unpack('<I',r[6:10])[0]
cnt=struct.unpack('<I',r[10:14])[0]
date=f"20{r[14]:02d}-{r[15]:02d}-{r[16]:02d} {r[17]:02d}:{r[18]:02d}:{r[19]:02d}"
print(f" #{i:2d} type={b1} b4={b4:04x} dmr_id={dmr}(0x{dmr:x}) seq={cnt} {date}")
# region schedules is at 0xC6000. call_log at 0x88000 region. 0x126000 is unrelated location.
# Occupancy said call_log used @0x092000 (that was actually contacts-looking / All Call).
# Let's see total valid + gap pattern
print("\ntotal 32-byte records with a nonzero timestamp year 0x19:")
n=sum(1 for i in range(20480//32) if data[0x126000+i*32+14]==0x19)
print(n)
# Confirm the 0x100000 bitmap: render 1bpp. It has 5-row-tall column data (values <=0x1f then 0x3c,0x38 etc)
print("\n### 0x100000 bitmap render (bytes as vertical 8px columns, LSB=top) ###")
seg=data[0x100000:0x100000+0x300]
# print 8 rows
for row in range(8):
line=''
for col in range(0x190,0x2f8):
b=data[0x100000+col]
line+='#' if (b>>row)&1 else ' '
print(line.rstrip())
# 0x03E000 twin: what is at 0x01E000 exactly and how does it relate to zones?
print("\n### 0x01E000 (inside zones region) full ###")
def hd(off,n):
out=[]
for i in range(0,n,16):
c=data[off+i:off+i+16]
h=' '.join(f'{b:02x}' for b in c)
a=''.join(chr(b) if 32<=b<127 else '.' for b in c)
out.append(f'{off+i:08x} {h:<47} {a}')
return '\n'.join(out)
print(hd(0x01e000,48))
# Is 0x01E000 the tail of the last zone slot? zones start 0x01C000, 512B each. 0x01E000 = slot 16.
print(f"0x01E000 is zone slot #{(0x01E000-0x01C000)//512}")
# The DTCN A/B marker in beta is at page+0xFF8. 0x01dffc had ff ff ff ff before DMRhub.
# So 0x01E000 likely a settings/identity page, twinned at 0x03E000.