File size: 6,836 Bytes
d82f2c0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
#!/usr/bin/env python3
"""Bounded native raw-bit round trips, supplied-tree receive and transmit requests."""
import copy
import gzip
import itertools
import json
from pathlib import Path
from analyze_bsp_references import global_address,trace_fields
from analyze_collision_composition import evaluate,get_word,put_word
from analyze_engine_control import control_flow
from analyze_qvm import write_json
from analyze_vm_extensions import native_functions,verified


def run(g,m,regs,start=None,stops=None):
    return evaluate(g,start or g['instructions'][0]['address'],stops or [x['address'] for x in g['instructions'] if x['opcode']=='retq'],m,regs,limit=10000,capture_registers=True)


def signed(v):return v-(1<<32) if v&(1<<31) else v


def main():
    out={'native':{},'limitations':'Paired Linux ELF64 synthetic instruction evaluation only. Original processes and native callees never execute. Trees, symbol-table pointers and memory supplied; no real adaptive tree/codebook initialization or packet codec. Huff_offsetTransmit PUSH omitted and send stopped before CALL; its body retained only as static evidence. Null/negative/malformed fixtures do not establish legal runtime reachability, memory safety or ABI/all-platform conformance.'}
    data,cursor,output,tree,table=0x10000,0x20000,0x30000,0x40000,0x50000
    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());verified((Path('.cache/UrbanTerror43')/r['source']['path']).read_bytes(),r['source']['sha256'])
        a=r['artifacts']['disassembly.txt'];fs=native_functions(verified(gzip.open(a['path'],'rb').read(),a['uncompressed_sha256']).decode());graphs={n:control_flow(fs[n]) for n in ['Huff_putBit','Huff_getBit','Huff_offsetReceive','Huff_offsetTransmit','send']}
        put,get,receive= [graphs[n] for n in ['Huff_putBit','Huff_getBit','Huff_offsetReceive']]
        bloc=global_address(next(x for x in put['instructions'] if '(%rip)' in x['operands']))
        put_probes=[]
        for initial,value,sentinel in itertools.product(list(range(8))+[8,15,0xffffffff,0x7fffffff],[0,1,2,255],[0,0xa5,255]):
            addr=data+(signed(initial)>>3);m={addr-1:0x7b,addr:sentinel,addr+1:0x7b};put_word(m,cursor,initial)
            t=run(put,m,{'%rdi':value,'%rsi':data,'%rdx':cursor})
            put_probes.append({'initial_bit':initial,'value':value,'sentinel':sentinel,'target_byte':t['memory'][addr],'final_cursor':get_word(t['memory'],cursor),'global_cursor':get_word(t['memory'],bloc),'canaries':[t['memory'][addr-1],t['memory'][addr+1]],**trace_fields(t,False)})
        roundtrips=[]
        for start,pattern in itertools.product(range(8),[[0]*16,[1]*16,[i%2 for i in range(16)],[(i+1)%2 for i in range(16)]]):
            m={data+i:0 for i in range(-1,5)};m[data-1]=m[data+4]=0x7b;put_word(m,cursor,start);trace=[]
            for bit in pattern:
                t=run(put,m,{'%rdi':bit,'%rsi':data,'%rdx':cursor});m=t['memory'];trace+=t['trace']
            encoded=[m[data+i] for i in range(4)];put_word(m,cursor,start);decoded=[]
            for _ in pattern:
                t=run(get,m,{'%rdi':data,'%rsi':cursor});m=t['memory'];decoded.append(t['registers']['rax']);trace+=t['trace']
            roundtrips.append({'start_bit':start,'input_bits':pattern,'encoded_bytes':encoded,'decoded_bits':decoded,'final_cursor':get_word(m,cursor),'global_cursor':get_word(m,bloc),'canaries':[m[data-1],m[data+4]],**trace_fields({'trace':trace},False)})
        receives=[]
        for shape,initial,byte in itertools.product(['depth1','depth2','depth3','null-left','null-right','null-root','leaf0','leaf255','leaf256','leaf258','leafminus1'],[0,7,8,-1],[0,255,0x96,0x81]):
            m={data+i:byte for i in range(-8,8)};put_word(m,cursor,initial);put_word(m,output,0xa5a5a5a5);put_word(m,bloc,0xa5a5a5a5)
            nodes=[]
            if shape.startswith('depth'):
                depth=int(shape[-1]);count=(1<<(depth+1))-1
                for i in range(count):
                    addr=tree+64*i;internal=i<(1<<depth)-1;symbol=257 if internal else 40+i
                    left=tree+64*(2*i+1) if internal else 0;right=tree+64*(2*i+2) if internal else 0
                    put_word(m,addr,left,8);put_word(m,addr+8,right,8);put_word(m,addr+52,symbol);nodes.append([addr,left,right,symbol])
                root=tree
            elif shape.startswith('null-'):
                root=0 if shape=='null-root' else tree
                put_word(m,tree,0 if shape=='null-left' else tree+64,8);put_word(m,tree+8,0 if shape=='null-right' else tree+64,8);put_word(m,tree+52,257)
                put_word(m,tree+64+52,77);nodes=[[tree,get_word(m,tree,8),get_word(m,tree+8,8),257],[tree+64,0,0,77]]
            else:
                root=tree;symbol=-1 if shape=='leafminus1' else int(shape[4:]);put_word(m,tree+52,symbol);nodes=[[tree,0,0,symbol&0xffffffff]]
            t=run(receive,m,{'%rdi':root,'%rsi':output,'%rdx':data,'%rcx':cursor})
            receives.append({'shape':shape,'initial_bit':initial,'backing_byte':byte,'root':root,'nodes':nodes,'symbol_word':get_word(t['memory'],output),'final_cursor':get_word(t['memory'],cursor),'global_cursor':get_word(t['memory'],bloc),**trace_fields(t,False)})
        transmit=copy.deepcopy(graphs['Huff_offsetTransmit']);omitted=[]
        for x in transmit['instructions']:
            if x['opcode']=='pushq':omitted.append(x['address']);x['opcode']='nop';x['operands']=''
        send_call=next(x['address'] for x in transmit['instructions'] if x['opcode']=='callq');end=next(x['address'] for x in transmit['instructions'] if x['opcode']=='popq');probes=[]
        for symbol,parent,initial in itertools.product([-1,0,1,255,256,257],[0,tree+64],[0,7,0xffffffff]):
            m={};put_word(m,cursor,initial);put_word(m,table+32+8*symbol,tree,8);put_word(m,tree+16,parent,8)
            t=run(transmit,m,{'%rdi':table,'%rsi':symbol&0xffffffff,'%rdx':data,'%rcx':cursor},stops=[send_call,end])
            probes.append({'symbol_index':symbol,'parent_pointer':parent,'initial_bit':initial,'requests_send':t['stop']==send_call,'send_arguments':[t['registers'][k] for k in ['rdi','rsi','rdx']] if parent else None,'final_cursor':get_word(t['memory'],cursor),'global_cursor':get_word(t['memory'],bloc),**trace_fields(t,True)})
        out['native'][label]={'source':r['source'],'disassembly_sha256':a['uncompressed_sha256'],'graphs':graphs,'bit_global_address':bloc,'put_probes':put_probes,'roundtrips':roundtrips,'receive_probes':receives,'transmit_probes':probes,'transmit_omitted_push_addresses':omitted}
    write_json(Path('docs/research/huffman-helpers.json'),out)
    print('Recovered 288 bit-write probes, 64 raw round trips, 352 tree receive and 72 transmit-boundary probes')


if __name__=='__main__':main()