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

XFEEDToolBox

【WinUI】XFE精英危险工具箱

公开
关注 0 Fork 0 Star 0
UTF-8
"""Bounded offline inventory of CommodityList/UID producer strings in the pinned client."""
import bisect,hashlib,json,re,struct
from pathlib import Path
import pefile
from capstone import Cs,CS_ARCH_X86,CS_MODE_64

image=Path('artifacts/ship-model-reference/client-copy/EliteDangerous64.exe');raw=image.read_bytes()
expected='6891f70a021fa9f3a0e00458c284f48d1226e68ae7fc02ad48081aed47857e93'
if hashlib.sha256(raw).hexdigest()!=expected:raise ValueError('Expected fixed old image')
pe=pefile.PE(data=raw,fast_load=True)
pe.parse_data_directories(directories=[pefile.DIRECTORY_ENTRY['IMAGE_DIRECTORY_ENTRY_EXCEPTION']])
entries=sorted((e.struct.BeginAddress,e.struct.EndAddress,e.struct.UnwindData) for e in pe.DIRECTORY_ENTRY_EXCEPTION);starts=[e[0] for e in entries]
def parent(rva):
    i=bisect.bisect_right(starts,rva)-1
    if i<0 or rva>=entries[i][1]:return None
    row=entries[i]
    for _ in range(16):
        header=pe.get_data(row[2],4)
        if not header[0]>>3&4:return hex(row[0])
        row=struct.unpack('<III',pe.get_data(row[2]+4+((header[2]+1)&~1)*2,12))
    raise ValueError('Unwind chain depth')
names=['CommodityList','comboOptions','hierarchyLevel','selectedCommodityUID','CommodityIndex','commodityId','commodityID','commodityUID','commodityName','CommodityName']
rows=[]
for name in names:
    needle=name.encode()+b'\0';offset=0
    while (offset:=raw.find(needle,offset))>=0:
        rows.append(dict(name=name,rva=hex(pe.get_rva_from_offset(offset))));offset+=len(needle)
# Original service getter lazily selects this actual registered interface.
service_type_rva=0x3b268ca+6+0x245ee18
service_bytes=pe.get_data(service_type_rva,4)
result=dict(imageSha256=expected,strings=rows,serviceTypeGlobal=hex(service_type_rva),serviceTypeId=struct.unpack('<I',service_bytes)[0] if len(service_bytes)==4 else None,savedCommodityUidHex=hex(671333304))
pointer_rows=[]
for target in (0x3b87400,0x1e2a6f0,0x1e11170,0x1e11180):
    needle=struct.pack('<Q',pe.OPTIONAL_HEADER.ImageBase+target)
    for section in pe.sections:
        if section.Characteristics&0x20000000:continue
        data=section.get_data();offset=0
        while (offset:=data.find(needle,offset))>=0:
            pointer_rows.append(dict(target=hex(target),rva=hex(section.VirtualAddress+offset),nearby=[hex(value-pe.OPTIONAL_HEADER.ImageBase) for value in struct.unpack('<16Q',data[offset-64:offset+64])]))
            offset+=8
result['pointerRows']=pointer_rows
result['vtables']={hex(start):[hex(value-pe.OPTIONAL_HEADER.ImageBase) for value in struct.unpack('<16Q',pe.get_data(start,16*8))] for start in (0x552ff80,0x552fff0,0x5242458)}
executables=[(section.VirtualAddress,section.VirtualAddress+section.Misc_VirtualSize) for section in pe.sections if section.Characteristics&0x20000000]
boundary=0x5530048
for _ in range(256):
    rva=struct.unpack('<Q',pe.get_data(boundary-8,8))[0]-pe.OPTIONAL_HEADER.ImageBase
    if not any(start<=rva<end for start,end in executables):break
    boundary-=8
result['precedingExecutableTableBoundary']=hex(boundary)
table_refs=[]
provider_refs=[]
type_initializers=[]
for section in pe.sections:
    if not section.Characteristics&0x20000000:continue
    for match in re.finditer(rb'[\x40-\x4f]?[\x8d\x8b][\x05\x0d\x15\x1d\x25\x2d\x35\x3d]....',section.get_data(),re.S):
        rva=section.VirtualAddress+match.start();instruction=match.group();target=rva+len(instruction)+struct.unpack_from('<i',instruction,len(instruction)-4)[0]
        if 0x552ff00<=target<=0x5530060:table_refs.append(dict(rva=hex(rva),parent=parent(rva),target=hex(target),instruction=instruction.hex()))
        if target in (0x5f05ce8,0x5f05c34,0x5f856e8):provider_refs.append(dict(kind='read',rva=hex(rva),parent=parent(rva),target=hex(target),instruction=instruction.hex()))
        if any(start<=rva<end for start,end in ((0x67b20,0x67b90),(0x67e00,0x67e70),(0xbe180,0xbe1f0))):
            literal=pe.get_data(target,160).split(b'\0',1)[0]
            type_initializers.append(dict(rva=hex(rva),target=hex(target),text=literal.decode('ascii',errors='replace') if all(32<=c<127 for c in literal) else None,instruction=instruction.hex()))
    for match in re.finditer(rb'[\x40-\x4f]?\x89[\x05\x0d\x15\x1d\x25\x2d\x35\x3d]....',section.get_data(),re.S):
        rva=section.VirtualAddress+match.start();instruction=match.group();target=rva+len(instruction)+struct.unpack_from('<i',instruction,len(instruction)-4)[0]
        if target in (0x5f05ce8,0x5f05c34,0x5f856e8):provider_refs.append(dict(kind='write',rva=hex(rva),parent=parent(rva),target=hex(target),instruction=instruction.hex()))
result['mainUiNearbyTableRefs']=table_refs
result['providerRefs']=provider_refs
result['typeInitializerRefs']=type_initializers
decoder=Cs(CS_ARCH_X86,CS_MODE_64);decoder.skipdata=True
result['typeInitializerWindows']=[dict(store=hex(store),instructions=[dict(rva=hex(i.address),text=i.mnemonic+' '+i.op_str) for i in decoder.disasm(pe.get_data(store-15,48),store-15)]) for store in (0x67b6f,0x67e4f,0xbe1cf)]
result['tradeHandlerTargets']={name:hex(struct.unpack('<Q',pe.get_data(0x5530150+offset,8))[0]-pe.OPTIONAL_HEADER.ImageBase) for name,offset in (('traderSource',0xd8),('commodityCategory',0xe0),('commodity',0xe8))}
output=Path('artifacts/galaxy-query-research/commodity-tree/uid-producer-strings.json');output.write_text(json.dumps(result,indent=2),encoding='utf-8')
print(json.dumps(result,indent=2))