XFE Git
XFE Studio Git
Git 首页 全局搜索
XFE 主站 文档 NuGet

XFEEDToolBox

【WinUI】XFE精英危险工具箱

公开
关注 0 Fork 0 Star 0
UTF-8
"""The original colour classifier's owner identity/cache chain; no game access."""
import hashlib,importlib.util,json,struct
from pathlib import Path
sp=importlib.util.spec_from_file_location('audit',Path(__file__).with_name('Audit-GalaxyClientCompatibility.py'))
a=importlib.util.module_from_spec(sp);sp.loader.exec_module(a)
old=a.Image(Path('artifacts/ship-model-reference/client-copy/EliteDangerous64.exe'))
new=a.Image(Path('D:/SteamLibrary/steamapps/common/Elite Dangerous/Products/elite-dangerous-odyssey-64/EliteDangerous64.exe'))
hashes=[hashlib.sha256(im.raw).hexdigest() for im in (old,new)]
assert hashes==['6891f70a021fa9f3a0e00458c284f48d1226e68ae7fc02ad48081aed47857e93','ed5a8f8cd10f9a80d3bda5badd7ba1d4fcfc15996c8c7e018852cb170e264b63']
functions=[];refs=[]
for before in [0x3ACEFA0,0x3AD4EB0,0x3B3E560,0x3B3E6F0,0x3B1A200,0x3B26390,0x3B26BD0,0x11968D0,0x1195EF0,0x2603390,0x3ADFB50]:
 f=old.function(before);assert f and f[0]==before
 length=f[1]-before
 if before==0x3B1A200:
  # Two16-entry RVA tables follow its single common RET. Compare the whole
  # executable body separately, then each actual table's relative targets.
  ret=next(i for i in old.instructions(before,length) if i.mnemonic=='ret')
  length=ret.address-old.base+ret.size-before
 row=a.match(old,new,before,length);assert row['status']=='unique',(hex(before),row)
 if before==0x3B1A200:
  other=int(row['newRva'],16);tables=[]
  left=[i for i in old.instructions(before,length) if any(p.type==a.cs.x86.X86_OP_MEM and p.mem.index!=0 and before<=p.mem.disp<f[1] for p in i.operands)]
  right=[i for i in new.instructions(other,length) if any(p.type==a.cs.x86.X86_OP_MEM and p.mem.index!=0 and other<=p.mem.disp<other+f[1]-before for p in i.operands)]
  assert len(left)==len(right)==2
  for l,r in zip(left,right):
   lt=next(p.mem.disp for p in l.operands if p.type==a.cs.x86.X86_OP_MEM and p.mem.index!=0)
   rt=next(p.mem.disp for p in r.operands if p.type==a.cs.x86.X86_OP_MEM and p.mem.index!=0)
   ltargs=struct.unpack('<16I',old.data(lt,64));rtargs=struct.unpack('<16I',new.data(rt,64))
   assert [x-before for x in ltargs]==[x-other for x in rtargs]
   assert all(before<=x<before+length for x in ltargs)
   tables.append(dict(oldTable=hex(lt),newTable=hex(rt),relativeTargets=[x-before for x in ltargs]))
  row['actualSwitchTables']=tables
 row['oldRva']=hex(before);functions.append(row);refs+=a.references(old,new,before,int(row['newRva'],16),row['length'])
def paired(before):
 targets={r[1] for r in refs if r[0]==before};assert len(targets)==1,(hex(before),targets)
 return targets.pop()
tables={x:paired(x) for x in [0x552D8A8,0x552D950]}
def mapped(before):return int(next(r['newRva'] for r in functions if int(r['oldRva'],16)==before),16)
slots=[]
for vt,slot,target in [(0x552D8A8,0x20,0x3B3E560),(0x552D8A8,0x50,0x3B26390),
 (0x552D950,0x20,0x3B3E6F0),(0x552D950,0x50,0x3B26BD0),(0x52A0288,0x38,0x2603390),(0x519DBB0,0x30,0x11968D0)]:
 current=tables.get(vt,{0x52A0288:0x52A0258,0x519DBB0:0x519DB70}.get(vt))
 assert struct.unpack('<Q',old.data(vt+slot,8))[0]-old.base==target
 assert struct.unpack('<Q',new.data(current+slot,8))[0]-new.base==mapped(target)
 slots.append(dict(oldVtable=hex(vt),newVtable=hex(current),slot=hex(slot),oldRva=hex(target),newRva=hex(mapped(target))))
globals_={hex(x):hex(paired(x)) for x in [0x5F05BAC,0x5F5A820]}
out=Path('artifacts/galaxy-query-research/colonisation-colour');out.mkdir(exist_ok=True)
result=dict(sourceHashes=hashes,functions=functions,slots=slots,vtables={hex(k):hex(v) for k,v in tables.items()},globals=globals_,
 fields=dict(providerCachedCommanderId='0x90',providerLocalIdentity='0x88',providerClaimCache='0x80',
  ordinaryHandleRelativeToController58='0x3c0',specialHandleRelativeToController58='0x3d0',
  cacheManagerRelativeToInterface='-0x58',mapManagerOffset='0x160',rowStride='0x110',rowKey='0',rowStatus='0x10',rowValueSystemAddress='0x18',rowCommanderId='0x20'),
 contract='Only a present stable actual claim row with a current non-sentinel cached CommanderID establishes ownership equality. Missing/pending source or cache miss is unknown. No Journal/public fields. This does not establish the independently radius-gated special-green colour branch.',
 gameProcessAccess=False,gameCalls=0,runtimeValidated=False)
(out/'compatibility.json').write_text(json.dumps(result,indent=2)+'\n',encoding='utf8')
print(json.dumps(dict(functions=len(functions),slots=len(slots),tables=result['vtables'],globals=globals_)))