#!/usr/bin/env python3 """Static references and bounded synthetic-memory traces for deferred auth drops.""" import gzip import json import math import struct from pathlib import Path from analyze_qvm import decode, write_json from analyze_vm_extensions import verified, native_functions from analyze_auth_drop import ascii_literal from analyze_native_dispatch import recover def signed32(value): value &= 0xffffffff return value-0x100000000 if value & 0x80000000 else value def trace_slice(instructions, start, stop, memory, locals_map, limit=256, byte_memory=None, capture_stack=False, halt_on_leave=False, stop_targets=(), call_results=None, resume_at=None, local_base=0x40000000, skip_initial_stop=False, coherent_memory=False): """Evaluate only a selected straight/bounded slice against synthetic memory. Record calls rather than entering callees. Reject unknown reads/opcodes and control flow outside the selected slice. This is not a QVM runtime. """ if any(not start <= target <= stop for target in stop_targets): raise ValueError('stop target outside bounded slice') from qvm_byte_memory_support import read_bytes,read_byte,write_bytes stack, args, calls, trace, byte_writes = [], {}, [], [], [] memory = dict(memory) bytes_map = {} if coherent_memory and byte_memory is None else None if byte_memory is None else dict(byte_memory) for offset, value in locals_map.items(): memory[local_base+offset] = value pc = start if resume_at is None else resume_at if not start <= pc <= stop: raise ValueError('resume outside bounded slice') while pc != stop and (pc not in stop_targets or skip_initial_stop and not trace): if not start <= pc < stop or len(trace) >= limit: raise ValueError('slice control flow escaped bound') ins = instructions[pc] op, value = ins['opcode'], ins['operand'] trace.append(pc) pc += 1 if op == 'CONST': stack.append(value) elif op == 'LOCAL': stack.append(local_base+value) elif op == 'LOAD4': address = stack.pop() if coherent_memory: stack.append(signed32(int.from_bytes(read_bytes(memory,bytes_map,address,4),'little'))) else: if address not in memory:raise ValueError('unknown synthetic memory read') stack.append(memory[address]) elif op == 'LOAD1': address = stack.pop() if coherent_memory:stack.append(read_byte(memory,bytes_map,address)) else: if bytes_map is None or address not in bytes_map:raise ValueError('unknown synthetic byte read') stack.append(bytes_map[address] & 255) elif op == 'SEX8': value = stack.pop() & 255 stack.append(value-256 if value & 128 else value) elif op == 'NEGI': stack.append(signed32(-stack.pop())) elif op == 'STORE4': value, address = stack.pop(), stack.pop() if coherent_memory: write_bytes(memory,bytes_map,{address+j:(value>>(8*j))&255 for j in range(4)}) else:memory[address] = signed32(value) if bytes_map is not None and not coherent_memory: for byte in range(4): bytes_map[address+byte] = (value >> (8*byte)) & 255 elif op == 'STORE1': value, address = stack.pop(), stack.pop() byte_writes.append({'address': address, 'value': value & 255}) if coherent_memory:write_bytes(memory,bytes_map,{address:value&255}) elif bytes_map is not None:bytes_map[address] = value & 255 elif op in ('ADD', 'SUB', 'MULI'): right, left = stack.pop(), stack.pop() stack.append(signed32(left+right if op == 'ADD' else left-right if op == 'SUB' else left*right)) elif op in ('LSH', 'RSHI', 'RSHU'): right, left = stack.pop(), stack.pop() if not 0 <= right < 32: raise ValueError('shift outside bounded evaluator domain') shifted = left << right if op == 'LSH' else signed32(left) >> right if op == 'RSHI' else (left & 0xffffffff) >> right stack.append(signed32(shifted)) elif op in ('BAND', 'BOR', 'BXOR'): right, left = stack.pop(), stack.pop() stack.append(signed32(left & right if op == 'BAND' else left | right if op == 'BOR' else left ^ right)) elif op in ('MULF', 'ADDF', 'SUBF', 'DIVF'): right, left = stack.pop(), stack.pop() a, b = [struct.unpack('> (8*offset)) & 255 byte_writes.append({'address': address+offset, 'value': bytes_map[address+offset]}) elif op == 'LOAD2': address = stack.pop() if bytes_map is None or any(address+offset not in bytes_map for offset in range(2)): raise ValueError('unknown synthetic halfword read') stack.append(bytes_map[address] | (bytes_map[address+1] << 8)) elif op == 'SEX16': value = stack.pop() & 65535 stack.append(value-65536 if value & 32768 else value) elif op in ('EQF', 'NEF', 'LTF', 'LEF', 'GTF', 'GEF'): right, left = [struct.unpack('right, 'GEF':left>=right}[op] if condition: pc = value elif op == 'CVIF': value = signed32(stack.pop()) stack.append(signed32(struct.unpack('> (8*byte)) & 255 elif op in ('DIVI', 'MODI'): right, left = signed32(stack.pop()), signed32(stack.pop()) if right == 0 or (left == -(2**31) and right == -1): raise ValueError('division outside bounded evaluator domain') quotient = abs(left) // abs(right) quotient = -quotient if (left < 0) != (right < 0) else quotient stack.append(quotient if op == 'DIVI' else left - quotient*right) elif op in ('LTU', 'LEU', 'GTU', 'GEU'): right, left = stack.pop() & 0xffffffff, stack.pop() & 0xffffffff if {'LTU':leftright,'GEU':left>=right}[op]: pc = value elif op in ('EQ', 'NE', 'LTI', 'LEI', 'GTI', 'GEI'): right, left = signed32(stack.pop()), signed32(stack.pop()) condition = {'EQ': left == right, 'NE': left != right, 'LTI': left < right, 'LEI': left <= right, 'GTI': left > right, 'GEI': left >= right}[op] if condition: pc = value elif op == 'ARG': args[value] = stack.pop() elif op == 'CALL': calls.append({'instruction': ins['index'], 'target': stack.pop(), 'args': dict(args)}) args = {} stack.append(0 if call_results is None else call_results.get(ins['index'], 0)) # explicit supplied result or default placeholder elif op == 'POP': stack.pop() elif op == 'JUMP': pc = stack.pop() elif op == 'LEAVE' and halt_on_leave: break # bounded helper return boundary; no real VM frame is unwound else: raise ValueError(f'unsupported slice opcode {op}') result = {'trace': trace, 'calls': calls, 'memory': memory, 'byte_writes': byte_writes} if bytes_map is not None: result['byte_memory'] = bytes_map if capture_stack: result['stack'] = stack if stop_targets: result['stop'] = pc return result def partition_function(instructions, entry, data, header): if instructions[entry]['opcode'] != 'ENTER': raise ValueError('expected function entry') end = next(i for i in range(entry+1, len(instructions)) if instructions[i]['opcode'] == 'ENTER') body = instructions[entry:end] literals = [] for i in body: if i['opcode'] == 'CONST' and instructions[i['index']+1]['opcode'] == 'ARG' and 0 <= i['operand'] < header['data_length']+header['literal_length']: value = ascii_literal(data, header['data_offset']+i['operand'], header['data_offset']+header['data_length']+header['literal_length']) if value: literals.append({'instruction': i['index'], 'vm_address': i['operand'], 'text': value}) return {'entry': entry, 'linear_end_exclusive': end, 'instructions': body, 'literal_argument_candidates': literals} def main(): report = json.loads(Path('docs/research/qvm/qagame.json').read_text()) data = verified(Path(report['source']['member']['output']).read_bytes(), report['sha256']) header, instructions = decode(data) entries = [2319, 5096, 69338, 15186, 165818, 173979, 174399] functions = {str(e): partition_function(instructions, e, data, header) for e in entries} refs = [] for i in instructions: if i['opcode'] == 'CONST' and i['operand'] == 3588: entry = next(j for j in range(i['index'], -1, -1) if instructions[j]['opcode'] == 'ENTER') refs.append({'instruction': i['index'], 'containing_entry': entry, 'window': instructions[max(entry, i['index']-4):i['index']+9]}) callers = {str(e): [i['index'] for i in instructions if i['opcode'] == 'CALL' and i['index'] and instructions[i['index']-1]['opcode'] == 'CONST' and instructions[i['index']-1]['operand'] == e] for e in entries} synthetic = [] record = 0x10000 for state, pending, now in [(2, 1000, 1100), (2, 1000, 1101), (1, 1000, 1101), (2, 0, 1101), (2, 1, 102), (2, 0x7ffffff0, -0x7fffff80)]: model = trace_slice(instructions, 15878, 15922, {record+468: state, record+3588: pending, 34992532: now}, {32: record, 28: 3}) synthetic.append({'state': state, 'pending': pending, 'now': now, 'signed_elapsed': signed32(now-pending), 'trace': model['trace'], 'calls': model['calls']}) native = {} for label in ('linux--Quake3-UrT-Ded.x86_64', 'linux--Quake3-UrT.x86_64'): r = json.loads(Path(f'docs/research/native/{label}.json').read_text()) original = verified((Path('.cache/UrbanTerror43')/r['source']['path']).read_bytes(), r['source']['sha256']) artifact = r['artifacts']['disassembly.txt'] text = verified(gzip.open(artifact['path'], 'rb').read(), artifact['uncompressed_sha256']).decode() dispatch = recover(original, text, 'SV_GameSystemCalls') native[label] = {'source': r['source'], 'disassembly_sha256': artifact['uncompressed_sha256'], 'strncpy_case': next(c for c in dispatch['cases'] if 102 in c['numbers_sharing_target']), 'error_case': next(c for c in dispatch['cases'] if 1 in c['numbers_sharing_target']), 'error_function': native_functions(text)['Com_Error']} write_json(Path('docs/research/deferred-auth.json'), {'source': report['source'], 'sha256': report['sha256'], 'functions': functions, 'direct_call_candidates': callers, 'field_constant_references': refs, 'synthetic_slice_traces': synthetic, 'native': native, 'limitations': 'Constant-offset references do not cover aliases or dynamically computed offsets. ' 'Synthetic-memory traces evaluate selected QVM instructions without entering callees; ' 'these are static boundary checks, not real gameplay/time/network fixtures or a full QVM runtime.'}) print('Recovered eight field references, copy/error helpers and deferred timing boundary traces') if __name__ == '__main__': main()