#!/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()