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

XFEEDToolBox

【WinUI】XFE精英危险工具箱

公开
关注 0 Fork 0 Star 0
UTF-8
"""Apply the original zero-throttle setter once after exact original ATC grant.

No clearance, docking state, equipment, ship pose, velocity or cargo is written.
The diagnostic remains resident until this exact game process exits.
"""
import argparse,ctypes as c,ctypes.wintypes as w,hashlib,json
from pathlib import Path
import frida
p=argparse.ArgumentParser(description=__doc__)
p.add_argument('--pid',type=int,required=True);p.add_argument('--components',type=Path,required=True)
p.add_argument('--market',type=int,required=True);p.add_argument('--thread',type=int,required=True);p.add_argument('--output',type=Path,required=True)
a=p.parse_args();snapshot=json.loads(a.components.read_text(encoding='utf-8-sig'))
image=Path(r'D:/SteamLibrary/steamapps/common/Elite Dangerous/Products/elite-dangerous-odyssey-64/EliteDangerous64.exe')
if snapshot['pid']!=a.pid or hashlib.sha256(image.read_bytes()).hexdigest()!=snapshot['gameSha256']:raise ValueError('Game process/build differs')
dock=next(x for x in snapshot['components'] if x['name']=='docking');computer=next(x for x in snapshot['routeBindings'] if x.get('name')=='launchAssist' and x.get('owner')=='ship')
physics=snapshot['physics'][0] if isinstance(snapshot['physics'],list) else snapshot['physics']
config={'image':str(image),'life':dock['lifecycle'],'entity':dock['entityId'],'dock':hex(int(dock['address'],16)+0x58),
        'computer':computer['address'],'root':physics['inputRoot'],'controller':physics['controller'],'market':str(a.market),'thread':a.thread}
source=r'''
const C=__CONFIG__,game=Process.getModuleByName('EliteDangerous64.exe'),base=game.base;
if(game.path.toLowerCase()!==C.image.replaceAll('/','\\').toLowerCase())throw new Error('Unexpected image');
const dock=ptr(C.dock),computer=ptr(C.computer),life=ptr(C.life),root=ptr(C.root),controller=ptr(C.controller);
const zero=new NativeFunction(base.add(0x25E5DD0),'void',['pointer','float'],{scheduling:'exclusive'});
let applied=false,observed=false,last='';
Interceptor.attach(base.add(0x8F0C00),{onLeave(){try{
 if(applied){if(!observed&&computer.readPointer().equals(base.add(0x5165288))){
  const brain=computer.add(0x1D0).readPointer();if(!brain.isNull()){
   const duty=new NativeFunction(brain.readPointer().add(0xA0).readPointer(),'pointer',['pointer'],{scheduling:'exclusive'})(brain);
   if(!duty.isNull()){const type=new NativeFunction(duty.readPointer().add(0x20).readPointer(),'uint',['pointer'],{scheduling:'exclusive'})(duty);
    if(type===1){observed=true;send({kind:'actual-original-docking-duty',type});}}
  }
 }return;}
 if(Process.getCurrentThreadId()!==C.thread||life.add(0xC0).readU32()!==8||life.add(0xB0).readU64().toString()!==C.entity
  ||!dock.readPointer().equals(base.add(0x5315D58))||![3,4].includes(dock.add(0x4C0).readU32())||dock.add(0x614).readU32()!==2
  ||dock.add(0x4E9).readU8()===255||dock.add(0x4E0).readPointer().add(0xB0).readU64().toString()!==C.market
  ||!computer.readPointer().equals(base.add(0x5165288))||!computer.add(0x240).readPointer().equals(controller)
  ||!root.add(0x2F8).readPointer().equals(controller)||!controller.readPointer().equals(base.add(0x52A0960))
  ||!controller.readPointer().add(0x158).readPointer().equals(base.add(0x25E5DD0)))return;
 const before=controller.add(0x680).readFloat();applied=true;zero(controller,0);
 send({kind:'original-zero-throttle-after-atc-grant',before,after:controller.add(0x680).readFloat(),market:C.market,thread:Process.getCurrentThreadId(),flightAxesSent:0});
 }catch(error){const e=String(error);if(last!==e){last=e;send({kind:'refused',error:e});}}}});
'''.replace('__CONFIG__',json.dumps(config))
k=c.WinDLL('kernel32',use_last_error=True);k.OpenProcess.argtypes=[w.DWORD,w.BOOL,w.DWORD];k.OpenProcess.restype=w.HANDLE
k.WaitForSingleObject.argtypes=[w.HANDLE,w.DWORD];k.CloseHandle.argtypes=[w.HANDLE]
handle=k.OpenProcess(0x100000,False,a.pid)
if not handle:raise c.WinError(c.get_last_error())
with a.output.open('x',encoding='utf-8') as out:
    session=frida.attach(a.pid);script=session.create_script(source)
    def emit(message,data):
        row=message.get('payload',message);out.write(json.dumps(row)+'\n');out.flush();print(json.dumps(row),flush=True)
    script.on('message',emit)
    try:script.load()
    except Exception as error:print(json.dumps({'loadError':str(error),'remainingResident':True}),flush=True)
    try:
        while k.WaitForSingleObject(handle,1000)==258:pass
    finally:k.CloseHandle(handle)