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,73 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Phase-0 UI hook PoC, built ON TOP of the russified image.
|
||||
|
||||
Injects a custom draw-router at 0x08029000 (free flash, after the russification
|
||||
cave@0x08028860 + font@0x08028900). Redirects ONLY the draw dispatch bl at
|
||||
0x080207E6 to the router, which:
|
||||
- tail-calls the stock draw dispatcher 0x0801E1BC (screen renders normally),
|
||||
- then, if g_screen==0 (home/standby), paints a custom "МОД" marker via the
|
||||
stock draw_string SDK (also exercising our CP1251 Cyrillic cave).
|
||||
Key dispatch is left 100% stock. One 4-byte code patch; fully recoverable.
|
||||
"""
|
||||
import struct
|
||||
from keystone import Ks, KS_ARCH_ARM, KS_MODE_THUMB
|
||||
|
||||
BASE = 0x08002800
|
||||
ROUTER = 0x08029000
|
||||
MARKER = 0x08029040
|
||||
DRAW_BL = 0x080207E6 # bl 0x0801E1BC in ui_tick_normal
|
||||
STOCK_DRAW= 0x0801E1BC
|
||||
DRAW_STR = 0x08008A50
|
||||
G_SCREEN = 0x200008B3
|
||||
ROOT = "C:/Users/vikto/Documents/Claude/rt-4d"
|
||||
|
||||
def main():
|
||||
img = bytearray(open(f"{ROOT}/stock-fw/rt4d_ru_full.bin", "rb").read())
|
||||
if len(img) < (MARKER+8-BASE):
|
||||
img += b"\xff" * ((MARKER+8-BASE) - len(img))
|
||||
def w(va, b): img[va-BASE:va-BASE+len(b)] = b
|
||||
ks = Ks(KS_ARCH_ARM, KS_MODE_THUMB)
|
||||
|
||||
router = f"""
|
||||
push {{r4, lr}}
|
||||
movw r4, #{STOCK_DRAW+1 & 0xFFFF}
|
||||
movt r4, #{(STOCK_DRAW+1) >> 16}
|
||||
blx r4 // stock draw dispatch (renders current screen)
|
||||
movw r4, #{G_SCREEN & 0xFFFF}
|
||||
movt r4, #{G_SCREEN >> 16}
|
||||
ldrb r4, [r4]
|
||||
cmp r4, #0
|
||||
bne done // only decorate the home screen
|
||||
sub sp, #8
|
||||
movs r0, #0
|
||||
str r0, [sp] // mode = 0 (arg5 -> [sp+0x28] inside draw_string)
|
||||
movs r0, #0 // page (top)
|
||||
movs r1, #104 // x
|
||||
movw r2, #{MARKER & 0xFFFF}
|
||||
movt r2, #{MARKER >> 16}
|
||||
movs r3, #3 // len
|
||||
movw r4, #{DRAW_STR+1 & 0xFFFF}
|
||||
movt r4, #{(DRAW_STR+1) >> 16}
|
||||
blx r4 // draw_string(0,104,marker,3,0)
|
||||
add sp, #8
|
||||
done:
|
||||
pop {{r4, pc}}
|
||||
"""
|
||||
code = bytes(ks.asm(router, ROUTER)[0])
|
||||
assert len(code) <= (MARKER-ROUTER), f"router too big: {len(code)}"
|
||||
w(ROUTER, code)
|
||||
w(MARKER, "МОД".encode("cp1251") + b"\x00")
|
||||
|
||||
# redirect the draw dispatch bl -> router
|
||||
old = bytes(img[DRAW_BL-BASE:DRAW_BL-BASE+4])
|
||||
new = bytes(ks.asm(f"bl #{ROUTER}", DRAW_BL)[0]); assert len(new) == 4
|
||||
w(DRAW_BL, new)
|
||||
|
||||
out = f"{ROOT}/stock-fw/rt4d_ui_poc.bin"
|
||||
open(out, "wb").write(img)
|
||||
print(f"router {len(code)}B @0x{ROUTER:08X} | marker МОД @0x{MARKER:08X}")
|
||||
print(f"draw bl @0x{DRAW_BL:08X}: {old.hex()} -> {new.hex()}")
|
||||
print(f"image {len(img)}B -> {out}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Ссылка в новой задаче
Block a user