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

XFEEDToolBox

【WinUI】XFE精英危险工具箱

公开
关注 0 Fork 0 Star 0
UTF-8
"""Observe only the plugin's original docking getters; no game calls or inputs."""
import argparse, hashlib, json, time
from pathlib import Path
import frida

p = argparse.ArgumentParser(description=__doc__)
p.add_argument('--pid', type=int, required=True)
p.add_argument('--output', type=Path, required=True)
a = p.parse_args()
game = Path('D:/SteamLibrary/steamapps/common/Elite Dangerous/Products/elite-dangerous-odyssey-64/EliteDangerous64.exe')
expected = 'ed5a8f8cd10f9a80d3bda5badd7ba1d4fcfc15996c8c7e018852cb170e264b63'
if hashlib.sha256(game.read_bytes()).hexdigest() != expected:
    raise ValueError('Unsupported game build')
source = r'''
const game = Process.getModuleByName('EliteDangerous64.exe');
if (game.path.toLowerCase() !== IMAGE.toLowerCase()) throw new Error('Selected image differs');
const hooks = []; const counts = {};
for (const [name, rva] of [['moduleAvailable',0xed7e20],['dockingAvailability',0xed7e10],['dockingDuty',0xed6620],['launchDuty',0xed7d10]]) {
  counts[name] = 0;
  hooks.push(Interceptor.attach(game.base.add(rva), {
    onEnter(args) {
      this.record = ++counts[name] <= 3;
      if (!this.record) return;
      const row = {kind:'enter', name, thread:Process.getCurrentThreadId(), object:args[0].toString()};
      try {
        row.table = args[0].readPointer().sub(game.base).toString();
        row.moduleId = args[0].add(0x290).readU32();
        row.moduleService = args[0].add(0x168).readPointer().toString();
        row.brain = args[0].add(0x1d0).readPointer().toString();
        row.dockingModuleId = args[0].add(0x360).readU32();
        row.dockingModuleService = args[0].add(0xe0).readPointer().toString();
        row.dockingModuleOperational = args[0].add(0x377).readU8();
        for (const [label, offset, slot] of [['module',0x168,0xb0],['brain',0x1d0,0xa0]]) {
          const object = args[0].add(offset).readPointer();
          const table = object.readPointer();
          row[label+'Table'] = table.sub(game.base).toString();
          row[label+'Method'] = table.add(slot).readPointer().sub(game.base).toString();
        }
      } catch(error) { row.observationError = String(error); }
      send(row);
    },
    onLeave(result) { if (this.record) send({kind:'leave',name,result:result.toUInt32() & 255}); }
  }));
}
rpc.exports = {summary(){return {counts,gameCallsInvoked:0,gameInputsSent:0,screenUse:false};}};
'''.replace('IMAGE', json.dumps(str(game)))
with a.output.open('x', encoding='utf-8') as output:
    session = frida.attach(a.pid)
    try:
        script = session.create_script(source)
        script.on('message', lambda message, data: (output.write(json.dumps(message)+'\n'), output.flush()))
        script.load()
        time.sleep(5)
        result = script.exports_sync.summary()
        output.write(json.dumps(result)+'\n')
        print(json.dumps(result), flush=True)
        script.unload()
    finally:
        session.detach()