Download scripts/analyze_chat_expansion.py from nmarshall/urt-rs: direct link, hf CLI and curl.
- Browser
- Download file 5.42 kB
-
https://huggingface.co/nmarshall/urt-rs/resolve/main/scripts/analyze_chat_expansion.py
- Command line
-
hf download hf://nmarshall/urt-rs/scripts/analyze_chat_expansion.py
-
curl -L -o analyze_chat_expansion.py https://huggingface.co/nmarshall/urt-rs/resolve/main/scripts/analyze_chat_expansion.py
5.42 kB
| #!/usr/bin/env python3 | |
| """Recover bounded radio parser states, key comparisons and substitution branches.""" | |
| import json | |
| 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 | |
| BASE=0x40000000 | |
| def compare(ins,left,right,bound=99999): | |
| a,b=0x10000,0x20000 | |
| memory={a+i:v for i,v in enumerate(left+b'\0')} | |
| memory.update({b+i:v for i,v in enumerate(right+b'\0')}) | |
| return trace_slice(ins,69387,69525,{}, {48:a,52:b,56:bound}, | |
| byte_memory=memory,limit=4096,capture_stack=True,halt_on_leave=True) | |
| def main(): | |
| q=json.loads(Path('docs/research/qvm/qagame.json').read_text()) | |
| data=verified(Path(q['source']['member']['output']).read_bytes(),q['sha256']);h,ins=decode(data) | |
| functions={str(e):partition_function(ins,e,data,h) for e in [69386,185212,186435]} | |
| keys=[] | |
| for i in range(185212,186435): | |
| if ins[i]['opcode']=='CONST' and ins[i]['operand']==69386 and ins[i+1]['opcode']=='CALL': | |
| literal=ins[i-5] | |
| if literal['opcode']!='CONST' or ins[i-4]['opcode']!='ARG' or ins[i-4]['operand']!=12: | |
| raise ValueError('key comparison pattern changed') | |
| keys.append({'key':vm_string(data,h,literal['operand']),'address':literal['operand'], | |
| 'compare_call':i+1,'bound':ins[i-3]['operand'],'window':ins[i-11:i+8]}) | |
| comparisons=[] | |
| for k in keys: | |
| key=k['key'].encode('ascii') | |
| for candidate in [key,key.upper(),key[:-1],key+b'x']: | |
| t=compare(ins,candidate,key) | |
| comparisons.append({'key':k['key'],'candidate':candidate.decode('ascii'),'trace':t}) | |
| # Per-character slices: no copy/append/lookup callee is entered. | |
| chars=[] | |
| for marker,key,ch in [(0,'',ord('x')),(0,'',36),(36,'foo',35),(35,'',ord('a')), | |
| (36,'h',ord('P')),(36,'foo',ord('1')),(36,'foo',32), | |
| (36,'foo',255),(0,'',0)]: | |
| bm={BASE+32:ch,BASE+182:marker} | |
| bm.update({BASE+183+i:v for i,v in enumerate(key.encode()+b'\0')}) | |
| t=trace_slice(ins,186481,186676,{}, {28:0,336:len(key),376:0x50000,380:0x60000},byte_memory=bm) | |
| chars.append({'pending_marker':marker,'pending_key':key,'byte':ch,'trace':t}) | |
| lookup_results=[] | |
| for result in [0,0x70000]: | |
| t=trace_slice(ins,186609,186676,{}, {340:result,380:0x60000},byte_memory={BASE+182:36}) | |
| lookup_results.append({'supplied_lookup_return':result,'trace':t}) | |
| tails=[] | |
| for marker in [0,35,36]: | |
| t=trace_slice(ins,186693,186719,{}, {380:0x60000},byte_memory={BASE+182:marker}) | |
| tails.append({'pending_marker':marker,'trace':t}) | |
| lengths=[] | |
| for length in [149,150,151]: | |
| t=trace_slice(ins,186449,186719,{}, {344:length,380:0x60000}, | |
| byte_memory={BASE+182:0},limit=256) | |
| lengths.append({'supplied_source_length':length,'trace':t}) | |
| entity,record=0x10000,0x20000 | |
| health=[] | |
| for value in [-1,0,24,25,49,50,74,75,100]: | |
| for state,override in [(0,0),(3,0),(4,0),(0,1)]: | |
| t=trace_slice(ins,185237,186431,{entity+684:value,entity+520:record, | |
| record+4:state,record+4324:override},{1144:entity}) | |
| health.append({'raw_health':value,'raw_state':state,'override':override,'trace':t}) | |
| hp=[] | |
| for state,override in [(0,0),(3,0),(4,0),(0,1)]: | |
| t=trace_slice(ins,185350,186431,{entity+684:42,entity+520:record,record+4:state, | |
| record+4324:override},{1144:entity}) | |
| hp.append({'raw_state':state,'override':override,'trace':t}) | |
| side_effects=[] | |
| for pointer,now in [(0,1000),(0x30000,1000),(0x30000,2147483640)]: | |
| t=trace_slice(ins,185987,186031,{entity+520:record,record+6168:pointer,34992532:now}, | |
| {1144:entity},byte_memory={},capture_stack=True,halt_on_leave=True) | |
| side_effects.append({'object_pointer':pointer,'now':now,'trace':t}) | |
| addresses=[77862,77857,77850,77847,78120,78109,78095,78087,78079,78074,78068, | |
| 78066,78037,78014,78009,78000,77991,77972,77959,77936] | |
| addresses.extend(k['address'] for k in keys) | |
| strings={str(a):vm_string(data,h,a) for a in addresses} | |
| out={'source':q['source'],'sha256':q['sha256'],'functions':functions,'keys':keys, | |
| 'comparison_traces':comparisons,'character_traces':chars,'lookup_result_traces':lookup_results, | |
| 'pending_tail_traces':tails,'source_length_traces':lengths,'health_traces':health,'hp_traces':hp, | |
| 'momo_traces':side_effects,'strings':strings, | |
| 'limitations':'Static partitions and bounded synthetic instruction slices. No original process or full ' | |
| 'QVM executes. CALLs return zero placeholders; source lengths and isolated lookup returns are supplied ' | |
| 'inputs, not executed callees. No composed parser output or formatting/copy/append execution. ' | |
| 'Timer, weapon, location, leader and crosshair bodies are retained but not fully evaluated; field ' | |
| 'identities, ownership, marker lifetime and original runtime/platform behavior remain open.'} | |
| write_json(Path('docs/research/chat-expansion.json'),out) | |
| print(f'Recovered {len(keys)} substitution keys, parser state and health/momo slices') | |
| if __name__=='__main__':main() | |