5.9 KiB
AnantaInjector(注入器最小依赖副本)
从 C:\Game\Ananta_mainleakflow_keitaro_gg\AnantaUnifiedLoader 里只挑出需要的部分拷过来的,
给服务端根目录那个 一键启动.exe 用。
带的模块
| 模块 | 通道 | 作用 |
|---|---|---|
modules/bowling_agent.js |
C | 保龄球球瓶 |
modules/balloon_fix.js |
C | 打气球的气球本体 |
故意不放的那些(服务端已经接管,注入器再开就是白刷负载):
gadget_loader(A 户外 gadget 网格)→ 服务端GameRouter.GadgetGrid.csworld_mod(B 场景物品网格)→ 服务端GameRouter.SceneItemGrid.cstrain(D 地铁座位 / E 室内扇区)→ 服务端GameRouter.MetroGadget.cs/ indoorSectorsaddbtn(F 提示按钮)→ 客户端自己会出 F,已降级为手动兜底settingsfix(设置-图像页错位行)→ 纯手动 RPC,无常驻行为
✅
balloon现在是可用的(2026-09-29 修):GameRouter.Balloon.cs已就位,服务端每次 push 会写%LOCALAPPDATA%\AnantaBalloon\balloon_push.json(实测 21:07 写过 16 条)。 ⛑ 但balloon_fix.js:3417的PUSH_PATHS默认是作者自己机器的D:\Ananta\gym_tools\_balloon_push.json, R146 注释写明「exe 加载器会把这一行整个改写成本机多路径」。原版 exe 做了,我们之前没做 ⇒ agent 读不到 ⇒pushN恒 0 ⇒ 一颗气球都不出。 现在由loader_common.apply_balloon_paths()在create_script前改写(js 文件本身仍与上游逐字节一致)。
分组开关(2026-10-01)
每个模块用 "group": "xxx" 声明组别,config.json 顶层 groups 整组一起开关,
改完重启加载器生效(config 只在启动时读一次):
"groups": { "minigame": true }
- 目前只有一组:
minigame(=bowling+balloon)。 - ⛔
traffic组(modules/vehicle_go.js)已于 2026-10-01 晚整组删除,不要再加回来: 它 hook 的AetherVehicleViewManager:CheckShouldNotUseGo(RVA0x0B108F00)实机 8 探针 全 0 命中 ⇒ 那个类根本没在用。车流现改走服务端trafficCruiseDrive(SyncAssignVehicleAITask68549522 +VehicleCruiseParameters,客户端本地 AI 开车)。 - ⛑ 与模块自身的
enabled、命令行--no a,b是叠加关系 —— 任一处关掉就不挂。 - ⛑⛑ 别复制第二份目录去"跑两个加载器":同一时刻只能有一个 frida 会话挂在
Ananta.exe上 (两个 = 游戏必崩),常驻模式靠.loader.lock挡着。所谓"拆分"是同一进程内的模块取舍。
两道保险(针对「注入器是不是得先进入世界再启动」)
① 进入世界闸门 attachGate
bowling_agent.js:5547 / balloon_fix.js 里装 hook 的 Il2Cpp.perform(...) 没有重试:
var blob = bfClass('LX6.Item.SceneItemBlob');
if (!blob) { sendlog('ERR: SceneItemBlob not found'); return; } // ← 永久放弃
所以「游戏刚起就挂」是有真实风险的。闸门的做法:先看服务端日志里有没有 只有 world-ready 之后才会打的行,命中了再 attach —— 等价于复现手动操作时 「进世界 → 再开加载器」这条已经验证过的顺序。
标记(任意一条命中即放行):
[RESTOCK] raid=[GADGET-GRID] push group[SCENE-ITEM-GRID] push group
⛑ 只扫本次开始跟踪之后新增的字节,不会把上一局的历史内容当成「已进世界」。
⛑ 三条 marker 对应的服务端功能全关掉时,闸门会走 timeoutSec(默认 900s)超时兜底,
按 fallback=attachAnyway 照样挂 —— 不会把你卡死。
想关掉闸门(排查时用):config.json 里 attachGate.mode 改成 process。
② armed 守卫 armedGuard
闸门只保证「时机对」,不保证脚本里那次 bfClass(...) 真的成功。
所以 attach 之后持续轮询 bfStatus.armed:
armed=true→ 正常。tpl=false是正常的(还没拿到模板),不会因此重挂armed=false→ 说明脚本里 return 掉了 ⇒ 等maxWaitSec(60s)后主动重挂
最多连试 maxAttempts(5)次,之后退避 backoffSec(120s)再试,不会无限刷。
手动跑
C:\Users\Noiro\.workbuddy\binaries\python\envs\default\Scripts\python.exe unified_loader.py
其它命令同 AnantaUnifiedLoader:diag / scan / rpc <模块> <RPC> [参数] / --no a,b。
⛑ 同一时刻只能有一个 frida 会话挂在 Ananta.exe 上(两个 = 游戏必崩)。
常驻模式用 .loader.lock 挡着;手动 rpc 之前请先关掉常驻窗口。
injector_status.json(界面靠它显示状态)
注入器会把自己的状态写进同目录 injector_status.json,根目录那个「一键启动」界面每秒读一次,
所以界面上的「已启动 / 等待 / 已注入」是真实状态,不是瞎猜的:
| state | 界面显示 |
|---|---|
starting |
正在启动… |
waiting_game |
已启动,等待游戏打开 |
waiting_world |
已启动,等你进入游戏世界 |
attached |
已连上客户端,正在装载… |
injected |
已注入(保龄球瓶 + 气球生效) |
stopped |
已退出 |
界面还会用文件里的 pid 判断注入器进程是否还活着(不是看「有没有 python 进程」,
那样会被机器上别的 python 误导)。
判活
... unified_loader.py rpc bowling bfStatus
... unified_loader.py rpc balloon bfStatus
- bowling:
armed=true且tpl=true才真的生效。tpl=false就站进保龄球馆让 AOI 表加载一次 (模板是「等客户端自己成功查一次表」时顺手收的)。 - balloon:
armed=true即可;pushN是服务端推送条目数 —— 必须 >0,pushErr会写清是哪几个候选路径读不到(修好后应为none、pushSrc指向 LOCALAPPDATA 那份)。