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

XFEEDToolBox

【WinUI】XFE精英危险工具箱

公开
关注 0 Fork 0 Star 0
UTF-8
"""Print bounded original-image evidence for the offline update comparison."""
import json,struct,hashlib
from pathlib import Path
import pefile
from capstone import Cs,CS_ARCH_X86,CS_MODE_64

paths=[Path('work/launcher-recovery-20261023/EliteDangerous64-before-update.exe'),Path('D:/SteamLibrary/steamapps/common/Elite Dangerous/Products/elite-dangerous-odyssey-64/EliteDangerous64.exe')]
pes=[pefile.PE(str(p),fast_load=True) for p in paths]
maps=json.loads(Path('work/trade-live-20261023/updated-build-rva-map.json').read_text())
mapping={int(x['old'],16):int(x['new'],16) for x in maps['mapping']}
md=Cs(CS_ARCH_X86,CS_MODE_64)
for x in [0x8ae6f0,0xeacb30,0x3cf04b0]:
    print('OLD',hex(x))
    for ins in md.disasm(pes[0].get_data(x,72),x):
        print(hex(ins.address),ins.bytes.hex(),ins.mnemonic,ins.op_str)
        if ins.mnemonic=='ret':break
for x in [0x5165e48,0x5539c58,0x5316cf8]:
    y=mapping.get(x);print('TABLE',hex(x),hex(y) if y else None)
    if not y:continue
    for off in range(0,0xE0,8):
        ov=struct.unpack('<Q',pes[0].get_data(x+off,8))[0]-pes[0].OPTIONAL_HEADER.ImageBase
        nv=struct.unpack('<Q',pes[1].get_data(y+off,8))[0]-pes[1].OPTIONAL_HEADER.ImageBase
        if ov in [0x8ae6f0,0xeacb30,0x3cf04b0]:print('DIRECT',hex(off),hex(ov),hex(nv))
for index,pe in enumerate(pes):
    rd=pe.sections[1].get_data();needle=struct.pack('<Q',pe.OPTIONAL_HEADER.ImageBase+(0x3ceb400 if index==0 else mapping[0x3ceb400]));at=0
    while True:
        at=rd.find(needle,at)
        if at<0:break
        table=pe.sections[1].VirtualAddress+at-0x60
        print('Body service table',index,hex(table),'radius',hex(struct.unpack('<Q',pe.get_data(table+0xd0,8))[0]-pe.OPTIONAL_HEADER.ImageBase));at+=8

root=paths[1].parent;resources=[]
for name,collection in [('local-model-reference.json','models'),('local-nebula-reference.json','templates')]:
    data=json.loads((Path('XFEEDToolBox.Core/Rendering')/name).read_text())
    for entry in data[collection]:
        h=entry['resourceHash'];f=root/'Win64'/f'{int(h[0],16):02x}'/h
        resources.append({'resource':h,'matches':f.exists() and hashlib.sha256(f.read_bytes()).hexdigest()==entry['sourceSha256']})
model=json.loads(Path('XFEEDToolBox.Core/Rendering/local-model-reference.json').read_text())
key=pes[0].get_data(model['publicKeyRva'],model['publicKeyBytes']);locations=[]
for s in pes[1].sections:
    at=s.get_data().find(key)
    if at>=0:locations.append(s.VirtualAddress+at)
print('RESOURCE SUMMARY',len(resources),'matching',sum(x['matches'] for x in resources),'keylocations',locations)
for index,(pe,rva,end) in enumerate([(pes[0],0x3cf04b0,0x3cf0580),(pes[1],0x3cf0410,0x3cf04e0)]):
    print('RADIUS FULL',index)
    for ins in md.disasm(pe.get_data(rva,end-rva),rva):
        print(hex(ins.address),ins.mnemonic,ins.op_str)
        if ins.mnemonic=='ret':break
report={'resources':resources,'keyLocations':locations}
Path('work/trade-live-20261023/updated-resource-evidence.json').write_text(json.dumps(report,indent=2))