#!/usr/bin/env python3 """Scope signed .54 low opcode 0x53 logging before caller-string validation. Synthetic SVC/PCB/caller window only. No card request or cross-process claim. Signed SYS_DRV init/dispatch/logging string copy run; MMIO/log-drain effects are not hardware evidence. """ from __future__ import annotations import sys from pathlib import Path from unicorn import UC_HOOK_CODE, UC_PROT_NONE from unicorn.arm_const import UC_ARM_REG_R1 sys.path.insert(0, str(Path(__file__).resolve().parents[1])) from pspemu import sysdrv_env # noqa: E402 from pspemu.component import Fault # noqa: E402 SIGNED = Path(__file__).resolve().parents[2] / 'psp_out/elf/sys_drv_0.49.0.54_18bd9d26.elf' ENTRY = 0xE087E4 BASE, END = 0x400000, 0x800000 LOG_FLAG, LOG_LEVEL, BACKEND_FLAG = 0xE264E0, 0xE264E4, 0xE269CC STRING_HELPER, FORMATTER, DRAIN = 0xE2232C, 0xE01A34, 0xE21D44 LOG_BUFFER = 0xEB5FB0 def main() -> None: sd = sysdrv_env.make() assert Path(sd.image_path).read_bytes() == SIGNED.read_bytes() rv, fault, _ = sysdrv_env.run_init(sd) assert rv == 0 and fault is None and sysdrv_env.init_flag(sd) == 1, (rv, fault) flags = (sd.read(LOG_FLAG, 1)[0], sd.rd32(LOG_LEVEL), sd.read(BACKEND_FLAG, 1)[0]) print('signed init logging (frontend, level, backend)=', flags, flush=True) assert flags[0] == 1 and flags[2] == 1, 'both modeled init log gates required' sd.uc.mem_map(BASE, 0x3000) regs = sd.uc.mem_regions() if not any(lo <= END-4 <= hi for lo, hi, _ in regs): sd.uc.mem_map(END-0x1000, 0x1000) if any(lo <= END <= hi for lo, hi, _ in sd.uc.mem_regions()): sd.uc.mem_protect(END, 0x1000, UC_PROT_NONE) def svc_window(comp, n): out = comp.uc.reg_read(UC_ARM_REG_R1) for i, v in enumerate((BASE, END, 0, 0)): comp.wr32(out + 4*i, v) return 0 sd.svc.register(0xB5, svc_window) req, cfg = sd.alloc(0x100), sd.alloc(0x400) sd.write(cfg, b'\x00' * 0x400) src, edge = BASE+0x1000, END-4 sd.write(src, b'J' * 40) sd.write(edge, b'K' * 4) seen, fmt, before_drain = [], [], [] sd.uc.hook_add(UC_HOOK_CODE, lambda uc, ea, size, data: seen.append(ea), begin=STRING_HELPER, end=STRING_HELPER+1) sd.uc.hook_add(UC_HOOK_CODE, lambda uc, ea, size, data: fmt.append(ea), begin=FORMATTER, end=FORMATTER+1) sd.uc.hook_add(UC_HOOK_CODE, lambda uc, ea, size, data: before_drain.append(bytes( uc.mem_read(LOG_BUFFER+16, 39))), begin=DRAIN, end=DRAIN+1) def request(ptr: int, declared: int) -> int: sd.write(req, b'\x00' * 0x100) for i, word in ((0, 0x53), (2, ptr), (3, declared), (14, 16), (sysdrv_env.REQ_CONFIG_DWORD, cfg)): sd.wr32(req + i*4, word) return sd.run_function(ENTRY, (req, 2, 0, 0), count=3_000_000, timeout=4_000_000) r = request(src, 4) assert r == 0 and len(seen) == len(fmt) == 1 assert before_drain == [b'J' * 39], before_drain print('mapped non-NUL input: declared4, signed logger copied 39 bytes ' 'before later NUL check; return', hex(r), flush=True) n, m, d = len(seen), len(fmt), len(before_drain) denied = request(edge, 40) assert denied == 0xFFFF000F and (len(seen),len(fmt),len(before_drain)) == (n,m,d) print('synthetic edge declared40 rejected before logger',hex(denied),flush=True) try: request(edge, 4) except Fault as exc: assert exc.addr == END, (exc, sd.faults) assert (len(seen),len(fmt),len(before_drain)) == (n+1,m+1,d) print('synthetic edge declared4: signed logger fault at',hex(exc.addr), 'before later NUL check and log drain',flush=True) else: raise AssertionError('short-declared synthetic edge unexpectedly completed') if __name__ == '__main__': main()