#!/usr/bin/env python3 """Recover leader scan, cached location formatting and location-list registration.""" import json import struct from pathlib import Path from analyze_deferred_auth import partition_function, trace_slice from analyze_game_cvars import vm_string from analyze_qvm import decode,write_json from analyze_vm_extensions import verified def main(): q=json.loads(Path('docs/research/qvm/qagame.json').read_text()) d=verified(Path(q['source']['member']['output']).read_bytes(),q['sha256']);h,ins=decode(d) leader=[] cases=[(0,[]),(-1,[]),(3,[(0,1,1),(1,2,1),(2,1,1)]), (3,[(1,1,1),(2,1,1),(2,1,1)]),(3,[(2,1,0),(2,1,0),(2,2,1)]), (3,[(1,1,-1),(0,1,1),(2,1,1)])] for count,records in cases: memory={34992496:0x10000,34992524:count} for i,(state,team,flag) in enumerate(records): a=0x10000+i*6336 memory.update({a+468:state,a+3096:team,a+3124:flag}) t=trace_slice(ins,169398,169460,memory,{20:1},halt_on_leave=True,capture_stack=True,limit=1024) leader.append({'count':count,'record_state_team_flag':records,'requested_team':1,'trace':t}) leader_format=[] for slot in [-1,0,2]: memory={} if slot==-1 else {34091888+slot*880:0x50000} t=trace_slice(ins,185947,186431,memory,{76:slot}) leader_format.append({'supplied_leader_return':slot,'trace':t}) cache=[] obj,location=0x10000,0x20000 for pointer,now,expiry in [(0,1000,0),(location,999,1000),(location,1000,1000), (location,1001,1000),(location,-2147483640,2147483640)]: m={obj+848:pointer,34992532:now} if pointer:m[pointer+596]=expiry t=trace_slice(ins,268249,268279,m,{4236:obj},halt_on_leave=True,capture_stack=True) cache.append({'pointer':pointer,'now':now,'expiry':expiry,'trace':t}) format_traces=[] for result in [0,location]: t=trace_slice(ins,268649,268676,{} if not result else {location+592:0x60000}, {24:result,44:0x70000,48:150},halt_on_leave=True,capture_stack=True) format_traces.append({'supplied_lookup_return':result,'trace':t}) lists=[] for guarded,count,fields in [(1,3,[]),(0,0,[]), (0,3,[(1,8489281),(0,8489281),(1,0)]), (0,3,[(1,8489281),(1,8489281),(1,8489281)])]: m={34999636:guarded,34992508:count} for i,(name_present,raw_tag) in enumerate(fields): obj=34091368+i*880 m.update({obj+536:0x80000 if name_present else 0,obj+540:raw_tag, obj+524:0x90000+i*64,obj+592:0xa0000+i*64}) t=trace_slice(ins,264977,265088,m,{36:34091368},limit=2048) lists.append({'guard':guarded,'count':count,'name_present_raw_tag':fields,'trace':t}) references={} for value in [169397,268248,268637,34999640]: references[str(value)]=[] for j,x in enumerate(ins): if x['opcode']=='CONST' and x['operand']==value: entry=next(k for k in range(j,-1,-1) if ins[k]['opcode']=='ENTER') references[str(value)].append({'instruction':j,'containing_entry':entry, 'window':ins[max(entry,j-4):j+7]}) abi=json.loads(Path('docs/research/qvm/qagame.abi-candidates.json').read_text()) if abi['sha256']!=q['sha256']:raise ValueError('ABI provenance changed') services=[r for r in abi['syscalls'] if r['number'] in [18,26,32]] extent=[] for address in [31128,31132,31136]: if address+4>h['data_length']:raise ValueError('box extent outside initialized data') offset=h['data_offset']+address extent.append({'vm_address':address,'raw_bits':struct.unpack_from('