"""Civilization's actual metadata classifier and authored-key bindings, offline only."""
import hashlib, importlib.util, json, struct
from pathlib import Path
spec=importlib.util.spec_from_file_location('audit',Path(__file__).with_name('Audit-GalaxyClientCompatibility.py'))
audit=importlib.util.module_from_spec(spec);spec.loader.exec_module(audit)
old=audit.Image(Path('artifacts/ship-model-reference/client-copy/EliteDangerous64.exe'))
new=audit.Image(Path('D:/SteamLibrary/steamapps/common/Elite Dangerous/Products/elite-dangerous-odyssey-64/EliteDangerous64.exe'))
hashes=('6891f70a021fa9f3a0e00458c284f48d1226e68ae7fc02ad48081aed47857e93','ed5a8f8cd10f9a80d3bda5badd7ba1d4fcfc15996c8c7e018852cb170e264b63')
assert tuple(hashlib.sha256(x.raw).hexdigest() for x in (old,new))==hashes
functions=[];refs=[]
init=old.function(0x1414B26);assert init
for before in [0x3AD1F00,0x3B26A00,0x3B135C0,init[0]]:
fn=old.function(before);assert fn and fn[0]==before
row=audit.match(old,new,before,fn[1]-before);assert row['status']=='unique',row
row['oldRva']=hex(before);functions.append(row)
refs+=audit.references(old,new,before,int(row['newRva'],16),row['length'])
globals_={}
for before in [0x5E7C508,0x5E7C510,0x5E7C518,0x5E7C520,0x5E7C540,0x5E7C550,0x5E7C558,0x5F05E6C,0x5E9D640]:
matches={r[1] for r in refs if r[0]==before};assert len(matches)==1,(hex(before),matches)
globals_[hex(before)]=hex(matches.pop())
names={};pending=None;returned=None
for instruction in old.instructions(0x1414AFB,0x180):
if instruction.mnemonic=='lea' and instruction.op_str.startswith('r8, [rip + '):
target=instruction.address+instruction.size+instruction.operands[1].mem.disp-old.base
pending=old.data(target,64).split(b'\0')[0].decode('ascii')
if instruction.mnemonic=='call' and instruction.operands[0].imm-old.base==0x140FB40:returned=pending
if instruction.mnemonic=='mov' and instruction.op_str.startswith('qword ptr [rip + '):
target=instruction.address+instruction.size+instruction.operands[0].mem.disp-old.base
names[hex(target)]=returned
expected_names={'0x5e7c508':'federation','0x5e7c510':'empire','0x5e7c518':'alliance','0x5e7c520':'independent',
'0x5e7c540':'PilotsFederation','0x5e7c550':'Thargoid','0x5e7c558':'Guardian'}
assert all(names.get(k)==v for k,v in expected_names.items()),names
assert old.data(struct.unpack('<Q',old.data(0x5E9D640,8))[0]-old.base,6)==b'Human\0'
vt={r[1] for r in refs if r[0]==0x552E088};assert len(vt)==1
vt=vt.pop();callee=int(next(r['newRva'] for r in functions if r['oldRva']=='0x3b26a00'),16)
assert struct.unpack('<Q',old.data(0x552E088+0x50,8))[0]-old.base==0x3B26A00
assert struct.unpack('<Q',new.data(vt+0x50,8))[0]-new.base==callee
result=dict(runtimeNeutral=True,gameProcessAccess=False,gameCalls=0,oldImageSha256=hashes[0],newImageSha256=hashes[1],
functions=functions,globals=globals_,vtables={'0x552e088':hex(vt)},
slots=[dict(oldVtable='0x552e088',newVtable=hex(vt),slot='0x50',oldRva='0x3b26a00',newRva=hex(callee))],
references=[list(map(hex,r)) for r in refs],definitionNames=expected_names,
fields=dict(savedVisibilityIndex=10,metadataDescriptorDefinitionId=8,configKeys=['None','Human','Guardian','Thargoid'],
humanClassGlobals=['0x5e7c508','0x5e7c510','0x5e7c518','0x5e7c520','0x5e7c540'],
noneSentinel='18446744073709551615',nonPaletteDefinition='original None fallback',
uninitialisedDefinitions='unknown',missingMetadata='unknown until both existing ready guards are observed'))
path=Path('artifacts/galaxy-query-research/civilization/compatibility.json');path.parent.mkdir(parents=True,exist_ok=True)
path.write_text(json.dumps(result,indent=2)+'\n',encoding='utf8')
print(json.dumps(dict(path=str(path),globals=globals_,vtable=hex(vt),callee=hex(callee)),indent=2))
"""Civilization's actual metadata classifier and authored-key bindings, offline only."""
import hashlib, importlib.util, json, struct
from pathlib import Path
spec=importlib.util.spec_from_file_location('audit',Path(__file__).with_name('Audit-GalaxyClientCompatibility.py'))
audit=importlib.util.module_from_spec(spec);spec.loader.exec_module(audit)
old=audit.Image(Path('artifacts/ship-model-reference/client-copy/EliteDangerous64.exe'))
new=audit.Image(Path('D:/SteamLibrary/steamapps/common/Elite Dangerous/Products/elite-dangerous-odyssey-64/EliteDangerous64.exe'))
hashes=('6891f70a021fa9f3a0e00458c284f48d1226e68ae7fc02ad48081aed47857e93','ed5a8f8cd10f9a80d3bda5badd7ba1d4fcfc15996c8c7e018852cb170e264b63')
assert tuple(hashlib.sha256(x.raw).hexdigest() for x in (old,new))==hashes
functions=[];refs=[]
init=old.function(0x1414B26);assert init
for before in [0x3AD1F00,0x3B26A00,0x3B135C0,init[0]]:
fn=old.function(before);assert fn and fn[0]==before
row=audit.match(old,new,before,fn[1]-before);assert row['status']=='unique',row
row['oldRva']=hex(before);functions.append(row)
refs+=audit.references(old,new,before,int(row['newRva'],16),row['length'])
globals_={}
for before in [0x5E7C508,0x5E7C510,0x5E7C518,0x5E7C520,0x5E7C540,0x5E7C550,0x5E7C558,0x5F05E6C,0x5E9D640]:
matches={r[1] for r in refs if r[0]==before};assert len(matches)==1,(hex(before),matches)
globals_[hex(before)]=hex(matches.pop())
names={};pending=None;returned=None
for instruction in old.instructions(0x1414AFB,0x180):
if instruction.mnemonic=='lea' and instruction.op_str.startswith('r8, [rip + '):
target=instruction.address+instruction.size+instruction.operands[1].mem.disp-old.base
pending=old.data(target,64).split(b'\0')[0].decode('ascii')
if instruction.mnemonic=='call' and instruction.operands[0].imm-old.base==0x140FB40:returned=pending
if instruction.mnemonic=='mov' and instruction.op_str.startswith('qword ptr [rip + '):
target=instruction.address+instruction.size+instruction.operands[0].mem.disp-old.base
names[hex(target)]=returned
expected_names={'0x5e7c508':'federation','0x5e7c510':'empire','0x5e7c518':'alliance','0x5e7c520':'independent',
'0x5e7c540':'PilotsFederation','0x5e7c550':'Thargoid','0x5e7c558':'Guardian'}
assert all(names.get(k)==v for k,v in expected_names.items()),names
assert old.data(struct.unpack('<Q',old.data(0x5E9D640,8))[0]-old.base,6)==b'Human\0'
vt={r[1] for r in refs if r[0]==0x552E088};assert len(vt)==1
vt=vt.pop();callee=int(next(r['newRva'] for r in functions if r['oldRva']=='0x3b26a00'),16)
assert struct.unpack('<Q',old.data(0x552E088+0x50,8))[0]-old.base==0x3B26A00
assert struct.unpack('<Q',new.data(vt+0x50,8))[0]-new.base==callee
result=dict(runtimeNeutral=True,gameProcessAccess=False,gameCalls=0,oldImageSha256=hashes[0],newImageSha256=hashes[1],
functions=functions,globals=globals_,vtables={'0x552e088':hex(vt)},
slots=[dict(oldVtable='0x552e088',newVtable=hex(vt),slot='0x50',oldRva='0x3b26a00',newRva=hex(callee))],
references=[list(map(hex,r)) for r in refs],definitionNames=expected_names,
fields=dict(savedVisibilityIndex=10,metadataDescriptorDefinitionId=8,configKeys=['None','Human','Guardian','Thargoid'],
humanClassGlobals=['0x5e7c508','0x5e7c510','0x5e7c518','0x5e7c520','0x5e7c540'],
noneSentinel='18446744073709551615',nonPaletteDefinition='original None fallback',
uninitialisedDefinitions='unknown',missingMetadata='unknown until both existing ready guards are observed'))
path=Path('artifacts/galaxy-query-research/civilization/compatibility.json');path.parent.mkdir(parents=True,exist_ok=True)
path.write_text(json.dumps(result,indent=2)+'\n',encoding='utf8')
print(json.dumps(dict(path=str(path),globals=globals_,vtable=hex(vt),callee=hex(callee)),indent=2))