File size: 5,350 Bytes
5dedc3d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
#!/usr/bin/env python3
"""Recover chat modes, dead-chat decisions and bounded delivery/echo calls."""
import itertools
import json
from pathlib import Path
from analyze_auth_announcements import recover_table
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 policy_allows(policy,mode,gametype,sub,spec,dead,target_spec,target_dead,bypass=0):
    """Independent readable interpretation checked against instruction traces."""
    if bypass:return True
    if policy==1:
        if spec and not target_spec and gametype!=9:return False
        return not(sub or spec or dead) or target_spec or target_dead or mode==1 or gametype==9
    if policy==2:return not spec or target_spec or gametype==9
    return not(sub or spec or dead) or target_spec or target_dead or gametype==9


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)
    reg=json.loads(Path('docs/research/game-cvars.json').read_text())
    if reg['sha256']!=q['sha256']:raise ValueError('registry provenance mismatch')
    deadchat=next(r for r in reg['registry']['rows'] if r['name']=='g_deadchat')
    if deadchat['mirror_address']+12!=34067996:raise ValueError('deadchat identity changed')
    table=recover_table(data,h,ins,29376,0,4,187381,187911)
    targets={r['value']:r['target_instruction'] for r in table['rows']}
    memory={r['vm_address']:r['target_instruction'] for r in table['rows']}
    switches=[{'mode':m,'target':targets.get(m,187423),
               'trace':trace_slice(ins,187403,targets.get(m,187423),memory,{436:m})} for m in range(-1,6)]
    policies=[]
    for policy,mode,gt,flags in itertools.product([0,1,2,3],[0,1],[0,9],itertools.product([0,1],repeat=5)):
        sub,spec,dead,ts,td=flags
        accepted=bool(policy_allows(policy,mode,gt,*flags))
        t=trace_slice(ins,187058,187154 if accepted else 187379,
                      {34999652:0,34067996:policy,34090788:gt},{56:sub,44:spec,60:dead,64:ts,68:td,124:mode})
        policies.append({'policy':policy,'mode':mode,'gametype':gt,'flags':list(flags),'accepted':accepted,
                         'instructions':t['trace']})
    bypass=trace_slice(ins,187058,187154,{34999652:1},{})
    sender,recipient,sr,rr=34091368+2*880,34091368+3*880,0x30000,0x40000
    derived=[]
    for sub,st,sd,sover,rt,rd,rover in [(0,1,0,0,1,0,0),(1,1,0,0,1,0,0),(0,3,0,0,3,0,0),
                (0,1,3,0,1,3,0),(0,1,0,1,4,0,1)]:
        t=trace_slice(ins,186920,187058,{sender+520:sr,recipient+520:rr,sr+3740:sub,sr+3096:st,
                 sr+4:sd,sr+4324:sover,rr+3096:rt,rr+4:rd,rr+4324:rover},{116:sender,120:recipient})
        derived.append({'raw_fields':[sub,st,sd,sover,rt,rd,rover],'trace':t})
    formats=[]
    for mode,team,sub,spec,dead,self_target in [(0,1,0,0,0,False),(1,2,1,1,1,False),
                (0,0,0,1,1,False),(2,1,0,0,0,False),(2,1,0,0,0,True),(3,2,0,0,0,False),(4,2,0,0,0,False)]:
        target=sender if self_target else recipient
        t=trace_slice(ins,187154,187379,{sender+520:sr,sr+3096:team},
             {116:sender,120:target,124:mode,128:51,132:0x50000,136:0x60000,56:sub,44:spec,60:dead})
        formats.append({'mode':mode,'sender_team':team,'flags':[sub,spec,dead],'same_object':self_target,
                        'trace':t})
    echoes=[]
    for same,flags in [(True,0),(False,0),(False,8)]:
        t=trace_slice(ins,187712,187909,{sender+424:flags},
                    {428:sender,432:sender if same else recipient,436:2,260:51,192:0})
        echoes.append({'same_object':same,'sender_flags_raw':flags,'trace':t})
    fanouts=[]
    for count,clean in [(0,0),(3,0),(3,1)]:
        t=trace_slice(ins,187834,187909,{34992524:count},{428:sender,436:0,260:51,192:clean},limit=1000)
        fanouts.append({'count':count,'clean_flag':clean,'trace':t})
    addresses=[77798,77792,77785,77777,77776,77768,77765,77762,77725,77722,77696,77653,77619,77589,
               77828,77805,77728]
    output={'source':q['source'],'sha256':q['sha256'],'deadchat_registry':deadchat,'mode_table':table,
            'mode_switch_traces':switches,'deadchat_policy_traces':policies,'bypass_trace':bypass,
            'derived_flag_traces':derived,'format_argument_traces':formats,'echo_traces':echoes,'fanout_traces':fanouts,
            'strings':{str(a):vm_string(data,h,a) for a in addresses},
            'functions':{str(e):partition_function(ins,e,data,h) for e in [186435,186721,187381]},
            'limitations':'Static qagame and bounded synthetic slices, not complete QVM/game execution. Calls '
            'are recorded with zero placeholder returns. Format arguments/pointers are evidence, not formatted '
            'commands. Field identities are provisional except supplied strings/cvar mappings. Earlier recipient '
            'gates are excluded from the policy matrix; global lifetime, text expansion, reliable queues and '
            'rendered/platform conformance remain open.'}
    write_json(Path('docs/research/chat-delivery.json'),output)
    print(f'Recovered {len(policies)} deadchat policy paths, mode/format and echo/fanout evidence')


if __name__=='__main__':main()