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,75 @@
|
||||
import struct, collections
|
||||
|
||||
DUMP = r"C:/Users/vikto/Documents/Claude/rt-4d/radio-spi-dump.bin"
|
||||
with open(DUMP,'rb') as f:
|
||||
data = f.read()
|
||||
assert len(data)==4194304
|
||||
|
||||
def hexdump(off, n=256, base=None):
|
||||
if base is None: base=off
|
||||
out=[]
|
||||
for i in range(0,n,16):
|
||||
chunk=data[off+i:off+i+16]
|
||||
if not chunk: break
|
||||
hexs=' '.join(f'{b:02x}' for b in chunk)
|
||||
asc=''.join(chr(b) if 32<=b<127 else '.' for b in chunk)
|
||||
out.append(f'{base+i:08x} {hexs:<47} {asc}')
|
||||
return '\n'.join(out)
|
||||
|
||||
def stats(off, size):
|
||||
seg=data[off:off+size]
|
||||
c=collections.Counter(seg)
|
||||
ff=c.get(0xff,0); zz=c.get(0x00,0)
|
||||
return f'size={size} ff={ff}({100*ff/size:.1f}%) 00={zz}({100*zz/size:.1f}%) distinct={len(c)}'
|
||||
|
||||
def find_ascii_runs(off, size, minlen=4):
|
||||
seg=data[off:off+size]
|
||||
runs=[]; cur=b''; start=0
|
||||
for i,b in enumerate(seg):
|
||||
if 32<=b<127:
|
||||
if not cur: start=i
|
||||
cur+=bytes([b])
|
||||
else:
|
||||
if len(cur)>=minlen: runs.append((off+start, cur))
|
||||
cur=b''
|
||||
if len(cur)>=minlen: runs.append((off+start,cur))
|
||||
return runs
|
||||
|
||||
def detect_period(off, size, maxp=1024):
|
||||
"""Find best repeating period by autocorrelation-ish match on a window."""
|
||||
seg=data[off:off+min(size,4096)]
|
||||
best=[]
|
||||
for p in range(2,maxp):
|
||||
if p>=len(seg): break
|
||||
match=sum(1 for i in range(len(seg)-p) if seg[i]==seg[i+p])
|
||||
best.append((match/(len(seg)-p), p))
|
||||
best.sort(reverse=True)
|
||||
return best[:6]
|
||||
|
||||
def compare_region(a_off, b_off, size):
|
||||
same=sum(1 for i in range(size) if data[a_off+i]==data[b_off+i])
|
||||
return same, size, 100*same/size
|
||||
|
||||
regions = [
|
||||
("0x010000", 0x010000, 0x1000),
|
||||
("0x03E000", 0x03E000, 0x1000),
|
||||
("0x0D0000", 0x0D0000, 0x6000),
|
||||
("0x100000", 0x100000, 0x1000),
|
||||
("0x126000", 0x126000, 0x5000),
|
||||
("0x14C000", 0x14C000, 0xB000),
|
||||
("0x164000", 0x164000, 0x32000),
|
||||
("0x325000", 0x325000, 0x1000),
|
||||
]
|
||||
|
||||
for name,off,size in regions:
|
||||
print("="*100)
|
||||
print(f"REGION {name} {stats(off,size)}")
|
||||
print("-- head --")
|
||||
print(hexdump(off,256))
|
||||
print("-- period (top ratios) --")
|
||||
print(detect_period(off,size))
|
||||
runs=find_ascii_runs(off,min(size,0x8000),4)
|
||||
print(f"-- ascii runs (first 20 of {len(runs)}) --")
|
||||
for r in runs[:20]:
|
||||
print(f' {r[0]:08x}: {r[1][:60]!r}')
|
||||
print()
|
||||
Ссылка в новой задаче
Block a user