"""Exact original/current allegiance-definition provider; offline PE 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'))
expected=('6891f70a021fa9f3a0e00458c284f48d1226e68ae7fc02ad48081aed47857e93','ed5a8f8cd10f9a80d3bda5badd7ba1d4fcfc15996c8c7e018852cb170e264b63')
assert tuple(hashlib.sha256(i.raw).hexdigest() for i in (old,new))==expected
functions=[];refs=[]
for before in [0x14018E0,0x140F320,0x140ED40,0x14100E0,0x140FF40,0x3AC56A0]:
fn=old.function(before)
if before==0x140F320:
length=next(i.address-old.base-before for i in old.instructions(before,0x240) if i.mnemonic=='int3')
raw=old.data(before,length);hits=[];at=0
while (at:=new.text_bytes.find(raw,at))>=0:hits.append(new.text.VirtualAddress+at);at+=1
assert len(hits)==1
row=dict(status='unique',newRva=hex(hits[0]),length=length,rawLeafWholeBody=True,
oldWindowSha256=hashlib.sha256(raw).hexdigest(),newWindowSha256=hashlib.sha256(new.data(hits[0],length)).hexdigest())
else:
assert fn and fn[0]==before,(hex(before),fn)
row=audit.match(old,new,before,fn[1]-before);assert row['status']=='unique',(hex(before),row)
row['oldRva']=hex(before);functions.append(row)
refs+=audit.references(old,new,before,int(row['newRva'],16),row['length'])
tables={}
for before in [0x51BB980,0x51BB9B0,0x51BBAB0,0x51BBBA0]:
matches={r[1] for r in refs if r[0]==before};assert len(matches)==1
tables[hex(before)]=hex(matches.pop())
slots=[]
for offset,before in [(0,0x140EB70),(0x18,0x140F320),(0x20,0x140ED40),(0x48,0x14100E0),(0x50,0x140FF40)]:
after=struct.unpack('<Q',new.data(int(tables['0x51bbab0'],16)+offset,8))[0]-new.base
assert struct.unpack('<Q',old.data(0x51BBAB0+offset,8))[0]-old.base==before
fn=old.function(before)
length=0x202 if before==0x140F320 else fn[1]-before if fn and fn[0]==before else next(i.address+i.size-old.base-before for i in old.instructions(before,64) if i.mnemonic=='ret')
raw,mask,*_=audit.signature(old,before,length);actual=new.data(after,length)
assert not any(a!=b for a,b,keep in zip(raw,actual,mask) if keep)
if before==0x140F320:assert old.data(before,length)==actual
refs+=audit.references(old,new,before,after,length)
slots.append(dict(oldRva=hex(before),newRva=hex(after),bytes=length,oldVtable='0x51bbab0',newVtable=tables['0x51bbab0'],slot=hex(offset)))
globals_={}
for before in [0x5F05E6C]:
matches={r[1] for r in refs if r[0]==before};assert len(matches)==1
globals_[hex(before)]=hex(matches.pop())
result=dict(runtimeNeutral=True,canInstallHooks=False,runtimeValidated=False,gameProcessAccess=False,gameCalls=0,
oldImageSha256=expected[0],newImageSha256=expected[1],functions=functions,vtables=tables,slots=slots,globals=globals_,
references=[list(map(hex,r)) for r in refs],fields=dict(interfaceFromOwner=0x58,
idMaps=[0x80,0xA8,0xC8,0xE8,0x108],legacy32BitMap=0x128,nodeId=8,nodeWeakControl=0x10,nodeDefinition=0x18,
weakControlStrongCount=0xC,definitionId=0,definitionKey=8,definitionValid=0x18,
missing='unknown',noneSentinel='18446744073709551615',noneBasis='3AC56A0 explicitly inserts None under u64Max; 140F320 rejects this sentinel'))
path=Path('artifacts/galaxy-query-research/allegiance-definitions/compatibility.json')
path.write_text(json.dumps(result,indent=2)+'\n',encoding='utf8')
print(json.dumps(dict(path=str(path),vtables=tables,slots=slots,globals=globals_),indent=2))
"""Exact original/current allegiance-definition provider; offline PE 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'))
expected=('6891f70a021fa9f3a0e00458c284f48d1226e68ae7fc02ad48081aed47857e93','ed5a8f8cd10f9a80d3bda5badd7ba1d4fcfc15996c8c7e018852cb170e264b63')
assert tuple(hashlib.sha256(i.raw).hexdigest() for i in (old,new))==expected
functions=[];refs=[]
for before in [0x14018E0,0x140F320,0x140ED40,0x14100E0,0x140FF40,0x3AC56A0]:
fn=old.function(before)
if before==0x140F320:
length=next(i.address-old.base-before for i in old.instructions(before,0x240) if i.mnemonic=='int3')
raw=old.data(before,length);hits=[];at=0
while (at:=new.text_bytes.find(raw,at))>=0:hits.append(new.text.VirtualAddress+at);at+=1
assert len(hits)==1
row=dict(status='unique',newRva=hex(hits[0]),length=length,rawLeafWholeBody=True,
oldWindowSha256=hashlib.sha256(raw).hexdigest(),newWindowSha256=hashlib.sha256(new.data(hits[0],length)).hexdigest())
else:
assert fn and fn[0]==before,(hex(before),fn)
row=audit.match(old,new,before,fn[1]-before);assert row['status']=='unique',(hex(before),row)
row['oldRva']=hex(before);functions.append(row)
refs+=audit.references(old,new,before,int(row['newRva'],16),row['length'])
tables={}
for before in [0x51BB980,0x51BB9B0,0x51BBAB0,0x51BBBA0]:
matches={r[1] for r in refs if r[0]==before};assert len(matches)==1
tables[hex(before)]=hex(matches.pop())
slots=[]
for offset,before in [(0,0x140EB70),(0x18,0x140F320),(0x20,0x140ED40),(0x48,0x14100E0),(0x50,0x140FF40)]:
after=struct.unpack('<Q',new.data(int(tables['0x51bbab0'],16)+offset,8))[0]-new.base
assert struct.unpack('<Q',old.data(0x51BBAB0+offset,8))[0]-old.base==before
fn=old.function(before)
length=0x202 if before==0x140F320 else fn[1]-before if fn and fn[0]==before else next(i.address+i.size-old.base-before for i in old.instructions(before,64) if i.mnemonic=='ret')
raw,mask,*_=audit.signature(old,before,length);actual=new.data(after,length)
assert not any(a!=b for a,b,keep in zip(raw,actual,mask) if keep)
if before==0x140F320:assert old.data(before,length)==actual
refs+=audit.references(old,new,before,after,length)
slots.append(dict(oldRva=hex(before),newRva=hex(after),bytes=length,oldVtable='0x51bbab0',newVtable=tables['0x51bbab0'],slot=hex(offset)))
globals_={}
for before in [0x5F05E6C]:
matches={r[1] for r in refs if r[0]==before};assert len(matches)==1
globals_[hex(before)]=hex(matches.pop())
result=dict(runtimeNeutral=True,canInstallHooks=False,runtimeValidated=False,gameProcessAccess=False,gameCalls=0,
oldImageSha256=expected[0],newImageSha256=expected[1],functions=functions,vtables=tables,slots=slots,globals=globals_,
references=[list(map(hex,r)) for r in refs],fields=dict(interfaceFromOwner=0x58,
idMaps=[0x80,0xA8,0xC8,0xE8,0x108],legacy32BitMap=0x128,nodeId=8,nodeWeakControl=0x10,nodeDefinition=0x18,
weakControlStrongCount=0xC,definitionId=0,definitionKey=8,definitionValid=0x18,
missing='unknown',noneSentinel='18446744073709551615',noneBasis='3AC56A0 explicitly inserts None under u64Max; 140F320 rejects this sentinel'))
path=Path('artifacts/galaxy-query-research/allegiance-definitions/compatibility.json')
path.write_text(json.dumps(result,indent=2)+'\n',encoding='utf8')
print(json.dumps(dict(path=str(path),vtables=tables,slots=slots,globals=globals_),indent=2))