#!/usr/bin/env python3 """Full-resolution dword sweep of the LOAD_TA command structure. The named fields (app address/length, cmd_buf address/length) were fuzzed in passes 86-88 and 104-105, but the command region was never swept dword by dword the way the INVOKE structure was in pass 108. Any dword that changes the outcome is a field the loader reads. Control: the unmodified descriptor loads 0x0. Each mutation is applied to a fresh descriptor with the known-good fields written afterwards, so a hit means that dword specifically matters. """ import glob, struct, sys, time sys.path.insert(0,'/root/psp/hw') from tinygrad import Device import tinygrad.runtime.autogen.am.am as am from ring_wrap import install adev=Device["AMD"].iface.dev_impl; psp=adev.psp submit=install(psp,adev) base=open(glob.glob('/root/psp/contall/ta_42-0-0-6_1c874c3c*')[0],'rb').read() def alloc(n): pa=adev.mm.palloc(n,align=0x1000,zero=True,boot=False); return pa,adev.paddr2mc(pa) ap_,amc=alloc(0x80000); cp,cmc=alloc(0x8000) n=(len(base)+3)&~3 adev.vram.view(ap_,n)[:]=base+b'\x00'*(n-len(base)); adev.gmc.flush_hdp() def go(mut=None): c=am.struct_psp_gfx_cmd_resp(cmd_id=am.GFX_CMD_ID_LOAD_TA) raw=memoryview(c).cast('B') if mut is not None: struct.pack_into('>32; t.app_len=len(base) t.cmd_buf_phy_addr_lo,t.cmd_buf_phy_addr_hi=cmc&0xFFFFFFFF,cmc>>32; t.cmd_buf_len=0x4000 t0=time.time() sid=None try: r=submit(c); st=r.resp.status&0xFFFFFFFF; sid=r.resp.session_id except Exception as e: try: st=int(str(e).strip().split()[-1])&0xFFFFFFFF except Exception: st=-1 dt=time.time()-t0 if st==0 and sid is not None: # free the session or the wall (0xb) masks everything u=am.struct_psp_gfx_cmd_resp(cmd_id=am.GFX_CMD_ID_UNLOAD_TA) u.cmd.cmd_unload_ta.session_id=sid try: submit(u) except Exception: pass return st, dt b,_=go() print('CONTROL unmodified load -> %#x'%b, flush=True) hits=[] for off in range(16, 16+784, 4): st,dt=go((off,0xFFFFFFFF)) if dt>5: print('STALL at dword %#x'%off, flush=True); break if st!=b: hits.append((hex(off),hex(st))) print('dwords that change the LOAD_TA outcome: %s'%(hits if hits else 'NONE across all 196'), flush=True)