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

XFEEDToolBox

【WinUI】XFE精英危险工具箱

公开
关注 0 Fork 0 Star 0
UTF-8
"""Trace original Power state UI labels and callback registrations offline."""
import bisect,hashlib,json,re,struct
from pathlib import Path
import pefile
from capstone import Cs,CS_ARCH_X86,CS_MODE_64,CS_OP_MEM
from capstone.x86_const import X86_REG_RIP

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);base=pe.OPTIONAL_HEADER.ImageBase
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=['UnOccupiedFilterToggled','ExpansionFilterToggled','ConflictFilterToggled','ExploitedFilterToggled','FortifiedFilterToggled','StrongholdFilterToggled','unoccupiedToggled','expansionToggled','conflictToggled','exploitedToggled','fortifiedToggled','strongholdToggled']
strings={}
for name in names:
    needle=name.encode()+b'\0';offset=0
    while (offset:=raw.find(needle,offset))>=0:strings[pe.get_rva_from_offset(offset)]=name;offset+=len(needle)
code_ranges=[(s.VirtualAddress,s.VirtualAddress+s.Misc_VirtualSize) for s in pe.sections if s.Characteristics&0x20000000]
decoder=Cs(CS_ARCH_X86,CS_MODE_64);decoder.detail=True;references=[]
for section in pe.sections:
    if not section.Characteristics&0x20000000:continue
    pattern=rb'(?:[\x40-\x4f]?[\x8d\x8b]|[\x40-\x4f]?[\x66\xf2\xf3]?\x0f[\x10\x28\x6f])[\x05\x0d\x15\x1d\x25\x2d\x35\x3d]....'
    for match in re.finditer(pattern,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 not in strings:continue
        callbacks=[]
        for i in decoder.disasm(pe.get_data(rva,160),rva):
            if i.mnemonic!='lea' or not i.op_str.startswith('rcx, '):continue
            for operand in i.operands:
                if operand.type!=CS_OP_MEM or operand.mem.base!=X86_REG_RIP:continue
                destination=i.address+i.size+operand.mem.disp
                if any(start<=destination<end for start,end in code_ranges):callbacks.append(hex(destination))
        references.append(dict(name=strings[target],rva=hex(rva),parent=parent(rva),followingCallbackCandidates=callbacks))
result=dict(imageSha256=expected,strings=[dict(rva=hex(rva),name=name) for rva,name in strings.items()],references=references)
result['newMapReceiverSlots']=[dict(offset=hex(offset),target=hex(struct.unpack('<Q',pe.get_data(0x5530150+offset,8))[0]-base)) for offset in (0x370,0x378,0x380,0x388,0x390,0x398)]
result['galaxyUiReceiverSlots']=[dict(offset=hex(offset),target=hex(struct.unpack('<Q',pe.get_data(0x551fff0+offset,8))[0]-base)) for offset in (0xd8,0xe0,0xe8,0x370,0x378,0x380,0x388,0x390,0x398)]
out=Path('artifacts/galaxy-query-research/power-state-filters');out.mkdir(parents=True,exist_ok=True);(out/'callback-refs.json').write_text(json.dumps(result,indent=2),encoding='utf-8')
print(json.dumps(result,indent=2))