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

XFEEDToolBox

【WinUI】XFE精英危险工具箱

公开
关注 0 Fork 0 Star 0
UTF-8
"""Read the pinned world's existing orbital matrices with QUERY_INFORMATION | VM_READ.

No injection, native calls, inputs, or process writes. The initial component
snapshot must refer to the same live player; all body reads are bounded.
"""
import argparse, ctypes as c, ctypes.wintypes as w, hashlib, json, math, struct
from datetime import datetime, timezone
from pathlib import Path

p = argparse.ArgumentParser(description=__doc__)
p.add_argument('snapshot', type=Path)
p.add_argument('output', type=Path)
a = p.parse_args()
d = json.loads(a.snapshot.read_text(encoding='utf-8-sig'))
k = c.WinDLL('kernel32', use_last_error=True)
k.OpenProcess.argtypes = [w.DWORD, w.BOOL, w.DWORD]; k.OpenProcess.restype = w.HANDLE
k.ReadProcessMemory.argtypes = [w.HANDLE,c.c_void_p,c.c_void_p,c.c_size_t,c.POINTER(c.c_size_t)]
k.QueryFullProcessImageNameW.argtypes = [w.HANDLE,w.DWORD,w.LPWSTR,c.POINTER(w.DWORD)]
k.CloseHandle.argtypes = [w.HANDLE]
h = k.OpenProcess(0x410,False,d['pid'])
if not h: raise c.WinError(c.get_last_error())
try:
    name=c.create_unicode_buffer(32768); size=w.DWORD(len(name))
    if not k.QueryFullProcessImageNameW(h,0,name,c.byref(size)): raise c.WinError(c.get_last_error())
    if hashlib.sha256(Path(name.value).read_bytes()).hexdigest()!=d['gameSha256']: raise ValueError('Game build changed')
    base=int(d['base'],16)
    def read(at,n):
        if at<0x10000 or not 0<n<=8192: raise ValueError('Read outside bound')
        buf=c.create_string_buffer(n); done=c.c_size_t()
        if not k.ReadProcessMemory(h,at,buf,n,c.byref(done)) or done.value!=n: raise c.WinError(c.get_last_error())
        return buf.raw
    def u(at,n=8): return int.from_bytes(read(at,n),'little')
    def f(at): return struct.unpack('<f',read(at,4))[0]
    fsd=int(next(x for x in d['components'] if x['name']=='fsd')['address'],16)
    life=int(next(x for x in d['components'] if x['name']=='fsd')['lifecycle'],16)
    if u(life+0xc0,4)!=8 or str(u(life+0xb0))!=d['player']['entityId']: raise ValueError('Player identity changed')
    pose=int(d['poseLookup']['poseAddress'],16); bodies=u(fsd+0x6a0)
    if u(u(bodies)+0x60)!=base+0x3ceb400: raise ValueError('Body service binding changed')
    world=u(pose+0xe8); system=world&0x7fffffffffffff
    def bucket_key(value):
        mask=0xffffffffffffffff
        value=(value*0x40000+(~value&mask))&mask
        value=((value>>31)^value)*21&mask
        value=((value>>11)^value)*65&mask
        return ((value>>22)^value)&0xffffffff
    def lookup(table_at,capacity_at,key,payload,system_table=False):
        table,capacity=u(table_at),u(capacity_at)
        if not table or not 0<capacity<=65536: raise ValueError('Body map bounds invalid')
        sentinel=table+8*(bucket_key(key)%capacity); node=u(sentinel)
        seen=set()
        while node!=sentinel:
            if node in seen or len(seen)>=4096: raise ValueError('Body map chain invalid')
            seen.add(node)
            if u(node+8)==key and (not system_table or u(node+16,1)==0): return u(node+payload)
            node=u(node)
        return 0
    # Service is the +0x58 interface of its owner; the original lookup masks
    # the system key before borrowing its loaded body-resource map.
    owner=bodies-0x58
    resource=lookup(owner+0x278,owner+0x280,system,24,True)
    if not resource or u(resource+4,4)!=5 or u(resource+0x90,4)==0: raise ValueError('System bodies are not loaded')
    def body_for(address): return lookup(resource+0x140,resource+0x148,address,16)
    def matrix(at):
        values=struct.unpack('<16d',read(at,128))
        if not all(math.isfinite(x) for x in values): raise ValueError('Nonfinite matrix')
        # Cobra stores three doubles plus an unused alignment lane per row.
        # Its affine product treats those lanes as 0/0/0/1, not as live data.
        return [list(values[i:i+3])+[1.0 if i==12 else 0.0] for i in range(0,16,4)]
    def mul(left,right): return [[sum(left[i][t]*right[t][j] for t in range(4)) for j in range(4)] for i in range(4)]
    def global_pose(body,universal=None):
        parent=u(body+0x378); index=u(body+0x384,4)
        # The loaded transform buffer consists of 0x180-byte slots. Slot
        # identity is checked against the body's own immutable address/index.
        if parent!=resource or index>=4096: raise ValueError('Body transform owner/index changed')
        transforms=u(parent+0x388)
        result=matrix(universal+0x10) if universal else [[1.0 if i==j else 0.0 for j in range(4)] for i in range(4)]
        if universal and u(universal+0x90,1): result=mul(result,matrix(transforms+index*0x180+0x80))
        result=mul(result,matrix(transforms+index*0x180+0x100))
        return result
    ship_body=body_for(world)
    if not ship_body or u(ship_body+0x18)!=world: raise ValueError('Reference body changed')
    ship_matrix=global_pose(ship_body,pose+0xe8)
    rows=[]
    settings=u(bodies-8)
    names={int(r['worldAddress']):r['name'] for r in d['navigationRecords']['records'] if r['type']==1}
    body_nodes=[];table,capacity=u(resource+0x140),u(resource+0x148)
    if not 0<capacity<=65536: raise ValueError('Body map capacity invalid')
    seen=set()
    for bucket in range(capacity):
        sentinel=table+8*bucket;node=u(sentinel)
        while node!=sentinel:
            if node in seen or len(seen)>=4096:raise ValueError('Body map is cyclic or exceeds bound')
            seen.add(node);body_nodes.append((u(node+8),u(node+16)));node=u(node)
    for addr,body in body_nodes:
        if not body:continue
        if u(body+0x18)!=addr or addr&0x7fffffffffffff!=system:raise ValueError('Body identity mismatch')
        kind=u(body+0x20,4)
        if kind not in (1,2,7): continue
        getter=u(u(body)+0x10)
        code=read(getter,16)
        if code[:6]==bytes.fromhex('488b0148ff60'):
            getter=u(u(body)+code[6]); code=read(getter,16)
        # Record the pinned leaf getter for static verification. No call.
        radius=None
        if code[:4]==bytes.fromhex('f30f1081'): radius=f(body+struct.unpack_from('<i',code,4)[0])
        elif code[:4]==bytes.fromhex('f30f1041'): radius=f(body+struct.unpack_from('<b',code,4)[0])
        elif getter==base+0x3cf2750:
            radius=struct.unpack('<f',struct.pack('<f',struct.unpack('<d',read(body+0x710,8))[0]))[0]
        entry={'name':names.get(addr,str(addr)),'address':str(addr),'kind':kind,'radiusGetterRva':hex(getter-base),
               'radiusGetterBytes':code.hex(),'radius':radius,'body':hex(body),
               'matrix':global_pose(body)}
        if radius is not None:
            star_type=u(body+0x448,4) if kind==1 else None
            offset=0x2c if star_type==0x29 else 0x34 if star_type in range(0x19,0x29) else 0x3c if kind==1 else 0x44
            entry['starType']=star_type
            entry['exclusionRadius']=radius*f(settings+offset)+f(settings+offset+4) if kind in (1,2) else radius
        rows.append(entry)
    if u(pose+0xe8)!=world or u(life+0xb0)!=int(d['player']['entityId']): raise ValueError('Reference changed during read')
    result={'pid':d['pid'],'gameSha256':d['gameSha256'],'entityId':d['player']['entityId'],'observedAt':datetime.now(timezone.utc).isoformat(),
            'referenceWorldAddress':str(world),'system':str(system),'referenceBodyKind':u(ship_body+0x20,4),
            'rawPosition':list(struct.unpack('<3d',read(pose+0x158,24))),'shipMatrix':ship_matrix,
            'bodyCount':len(rows),'bodyMapNodes':len(body_nodes),'bodies':rows,'gameInputsSent':0,'nativeFunctionsInvoked':False,'processAccess':'QUERY_INFORMATION | VM_READ'}
    a.output.write_text(json.dumps(result,indent=2))
    print(json.dumps({key:value for key,value in result.items() if key!='bodies'},indent=2))
finally: k.CloseHandle(h)