Skip to content

SkyBlue997/htbot

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

htbot

异环 (NTE) macOS 上的钓鱼 / 麻将工具。Frida 读取游戏内存,通过 CGEvent 或 frida widget 回调下发输入。

  • 钓鱼:全自动。挂上之后从抛竿、提竿、minigame 拉鱼到关结算页全部自己处理,不需要任何人工介入。
  • 麻将:半自动。事件能识别(摸/打/换三张/听牌等),缺一门按钮自动按,但换三张选 3 张牌、平时出牌、碰/胡/杠都需要手动点。

安装

cd htbot
pip install -r requirements.txt

依赖:frida 16+(已在 17 上验证)、pyobjc-framework-Quartz、mss、numpy。Python 3.10 还需要 pip install tomli

第一次运行先复制配置模板:

cp config.example.toml config.toml

合成按键需要 Accessibility 权限。打开"系统设置 → 隐私与安全性 → 辅助功能",把运行 Python 的终端(Terminal / iTerm / VS Code 等)加进去并启用,然后重启终端。


钓鱼

钓鱼有 6 个状态: NONE → SELECTPOINT → THROWROD → BAIT → PLAYER_SURE → THROWUP,然后回到 SELECTPOINT 循环。状态从 AHTPlayerState 内存里的 EFishingType 字段读。

抓 actor 地址

每次启动游戏,actor 地址都会因 ASLR 重新随机化。但只需要在第一次进入钓鱼场景时抓一次 — 探针装了常驻 hook 在 OnTick 上,实例如果被销毁重建会自动追踪到新地址。

进游戏走到钓鱼点旁,运行:

python -m utils.find_actors fishing

回游戏按 F 进钓点。终端几秒内会输出:

✓ player_state @ 0x...
✓ fish_main @ 0x...

地址自动写回 config.toml,工具自动退出。保持游戏运行,不要关。

启动

#点击开始钓鱼后运行
python -m htbot --no-dry-run --max-sec 1800

正常一轮的日志大致是:

state NONE -> SELECTPOINT
SELECTPOINT 抛竿 (延迟 437ms)
state SELECTPOINT -> THROWROD
state THROWROD -> BAIT
BAIT 反应 187ms 后提竿
state BAIT -> PLAYER_SURE
minigame interval=BELOW → 按 D
minigame interval=IN_INTERVAL → 静止
minigame interval=APPROACHING → 按 A
state PLAYER_SURE -> THROWUP
钓上 1 条! 累计 1 条

Minigame 决策

不依赖图像识别,而是直接调用游戏内的 UHTUI_FishMain::RodIsInFishInterval() 取真值。返回 0/1/2/3 对应 NO_FISH / IN_INTERVAL / 鱼钩偏左 / 鱼钩偏右,分别处理为释放 / 按 D 拉右 / 按 A 拉左。

但这只是 4 态粗信号,鱼钩会停在区间边缘 — 一进区间就松手,残留动量越过中点又出去,然后反向拉回,反复横跳。所以在此基础上又读取 rod 和 interval 的连续 X 坐标,瞄区间中点,加 Schmitt 双阈值:中心 ±4% 内才松手,偏移超过 14% 才按方向键,中间过渡区维持上一次动作。这样自然摇晃不会触发反复 press / release。

输入模式

[fishing.input]
mode = "callback"   # 默认

callback 通过 frida RPC 直接调用游戏内 UMG 按钮的 C++ 回调函数,不经过 macOS 输入子系统。游戏窗口可以放在副屏、缩到角落、切到另一个 Space,都不影响。唯一不行的是把游戏完全最小化到 Dock — UE 会暂停 tick,什么都不跑。锁屏 / 系统睡眠同理。

mode = "key" 是另一个选项,走 CGEvent 合成键盘事件,要求游戏在前台。除非 frida 那条路出问题,否则没必要切。

结算页处理

钓上鱼会弹一个"钓鱼成功"结算页(显示鱼名 + 经验)。callback 模式下不能用 CGEvent 点屏幕中央来关掉,所以加了专门的 hook:从 UHTUI_FishingSuccess::SetFishingResult 触发的实例捕获 widget 指针,然后调用它的 OnCloseBtnClickkey 模式下直接 mouse_click 屏幕中央即可。


麻将

异环游戏内的"小小雀魂"模式,底层实际是川麻血流 (AHTChuanMahjong* 系列),不是雀魂式日麻。所以没有"吃",有"缺一门"和"换三张"。

当前能力

阶段 状态
摸牌跟踪 自动累加到本地手牌
牌河观察 自动
换三张:决策选哪门 + 推荐给哪 3 张 决策出来打日志,3 张牌需手动点
缺一门按钮 换三张事件后 30 秒自动点
听牌提示 显示日志
鸣牌响应(碰 / 胡 / 杠 / 过) 手动
平时出牌 手动(bot 给推荐)

跑法

进对局之前或大厅都可以(Tick hook 会刷新到当前 actor),运行:

python -m utils.find_actors mahjong

table_actor_addr + ui_form_addr 写回 config。然后把 [mahjong] enabled = true,启动:

python -m htbot mahjong --no-dry-run --max-sec 600

进对局后,起手 13 张牌都会被记录。换三张阶段 bot 会建议选哪门 — 自己点 3 张 + 确认,30 秒后 bot 自动按对应的缺一门按钮。之后正常出牌,每次轮到自己时 bot 推荐打哪张,手动点对应的牌即可。Hu / 碰 / 杠 只在听牌提示阶段有日志输出,实际按钮需要手动点。


命令行选项

python -m htbot [mode] [options]

mode          fish | mahjong | auto (默认读 config.toml)
--once        一次性快照,打印后退出
--dry-run     强制 dry-run,只打日志不发输入
--no-dry-run  关闭 dry-run,真发输入
--no-frida    禁用 frida(纯视觉,minigame 没了 frida 决策几乎不可用)
--max-sec N   会话上限秒数,默认 7200
--log-level   DEBUG / INFO / WARNING / ERROR

工具脚本

python -m utils.find_actors fishing      # 抓钓鱼 actor 地址,自动写 config
python -m utils.find_actors mahjong      # 抓麻将 actor (table + ui_form)
python -m utils.probe_fishing_state      # 钓鱼状态字段诊断
python -m utils.test_input               # 测合成键鼠 (调试 Accessibility 权限)

故障排查

state 一直显示 NONE。重启游戏后 ASLR 让旧地址失效,重新跑 find_actors fishing

attach 异环 失败。frida 没连上。先 frida-ps | grep 异环 确认进程在。如果是 macOS 权限问题,可能需要禁用 SIP 或使用签名过的 frida-server。最后兜底是 --no-frida 走纯视觉,但钓鱼意义不大。

F / A / D 不响应游戏。Accessibility 权限没给。系统设置 → 隐私与安全性 → 辅助功能,加上你的终端,重启终端后再跑

A / D 在控制角色而不是鱼钩。当前不在 PLAYER_SURE 状态(还没进 minigame),或游戏窗口不在前台(key 模式下要前台,可改用 callback 模式绕开)。

SELECTPOINT 反复"卡住"。鱼饵用完了,手动补充。

Frida 17 报 Memory.readU8 not a function。旧 API 在 17 移除,本仓库已全部改成 instance method (ptr.readU8())。如果还报错,拉最新版。

find_actors 抓到 0x100 这种垃圾值。已加 sanity check 拒绝 < 4GB 的指针,重跑即可。

pyobjc-framework-CoreGraphics 未找到。PyObjC 没这个独立包,已从 requirements.txt 移除。pip install -r requirements.txt 重装即可(CoreGraphics 包含在 pyobjc-framework-Quartz 中)。


反作弊

之前做过一轮 audit:客户端没有反 Frida / 反 hook / OS 自省检测,钓鱼麻将均不触发已知的 game-state tripwire。但服务端行为分析,所以 humanize 模块给所有动作加了高斯抖动 — 反应延迟、按键时长、随机分神、会话节奏。


项目结构

htbot/
  README.md
  config.example.toml
  config.toml                # find_actors 自动填地址
  requirements.txt
  htbot/
    __main__.py              # CLI 入口
    core/                    # 共享:frida bridge / 输入 / vision / humanize / config / 主调度
    modules/
      fishing/               # 状态机 + minigame 闭环 + callback 输入
      mahjong/               # 事件驱动 + 半自动
  frida_scripts/
    fishing_probe.js
    mahjong_probe.js
  utils/                     # 抓地址 / 诊断脚本

已知限制

仅在 macOS 上验证过 — input 走 CGEvent + pyobjc。Linux / Windows 需要重写 input 层。

每次游戏更新可能让 frida 脚本里的函数地址 / 字段偏移失效,要重新 nm 一遍并修改 frida_scripts/*.js 里的常量。config.toml 里的 actor 地址不需要动(只是初始 seed,自动追踪会刷新)。

游戏完全最小化到 Dock 时 UE 暂停 tick,所有逻辑停止运行。需要后台跑就用小窗或副屏。

About

异环 (NTE) macOS 钓鱼 / 麻将自动化 — Frida + CGEvent

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors