SKILL.md 7.69 KB

name: wechathook-recovery description: WeChatHook 注入丢失恢复——日志轮转致闸口误判 + force-stop 重新注入。触发词:WeChatHook not injected、hook 掉了、闸口误判、check_wechat_ready false but WeChat running。

category: wechat

WeChatHook Recovery — Hook 注入丢失恢复

症状

check_wechat_ready() 返回 ready: false,reason="WeChatHook not injected (no hook entries in LSPosed log)",但微信进程在运行(pidof com.tencent.mm 有 PID)。

诊断链

# 1. 确认微信进程在
su -c 'pidof com.tencent.mm'

# 2. 确认 lspd daemon 在
su -c 'pidof lspd'

# 3. 检查所有 verbose log(不是只查最新一个)
su -c 'grep -a "WeChatHook" /data/adb/lspd/log/verbose_*.log | tail -5'

# 4. 检查模块是否在 WeChat 进程内存中
su -c 'cat /proc/$(pidof com.tencent.mm)/maps | grep -i wechathook'

# 5. 检查 LSPosed 模块 DB
su -c 'sqlite3 /data/adb/lspd/config/modules_config.db "SELECT mid, module_pkg_name, enabled FROM modules;"'

常见原因

1. 日志轮转误判(最常见)

check_wechat_ready() 只检查最新的 verbose log。LSPosed 日志会轮转(~4MB 限制),"BroadcastReceivers registered" 记录可能在前一个日志中。闸口误判但 hook 实际在线。

验证:搜所有 verbose log 而不仅是最新:

su -c 'grep -a "BroadcastReceivers registered" /data/adb/lspd/log/verbose_*.log | tail -3'

如果找到记录 → 闸口误判,可以发(广播 result=0 验证)。

2. WeChat 进程重启后 hook 未重新注入

WeChat PID 变了(旧 PID 有 hook 记录,新 PID 没有)。LSPosed 在进程重启时未重新注入模块。

恢复步骤:

# Force-stop WeChat(触发 LSPosed 在下次启动时重新注入)
su -c 'am force-stop com.tencent.mm'
# 等待 3 秒
sleep 3
# 用户手动打开微信(Android 16 禁止程序化启动)
# 验证:
su -c 'pidof com.tencent.mm'  # 新 PID
su -c 'grep -a "BroadcastReceivers registered" $(ls -t /data/adb/lspd/log/verbose_*.log | head -1) | tail -1'
# 看到新的注册记录 → 恢复成功

⚠️ force-stop 可能踢掉平板登录态。打开微信后如需重新登录,走 wechat-pad-login-repair。

症状 2:hook 在线、能发消息,但收信中断(2026-09-20 实测)

闸口返回 ready: true、pidof com.tencent.mm 有 PID、hook 日志活跃、发消息 HighLevel send OK, 但群里一条消息都收不到(微信 DB 不再新增 isSend=0 的行)。

判据(全部满足 = 收信链路断了,不是"群里没人说话"):

# 1. DB 级:最新若干条消息里,最后一条 isSend=0 的时间戳离现在多久(>1h 且所有群一致停滞即可疑)
cd ~/wechat-viewer && python3 ~/tmp/msg_liveness.py   # 或直接 sqlcipher 查 message 表 ORDER BY createTime DESC
# 2. 逐个群比对当天消息数:正常群每小时 20-40 条,突然全体归零 ⇒ 不是用户安静
# 3. LSPosed 日志里找 hook 自己的异常堆栈(这是根因线索)
su -c 'grep -n "java.lang.Exception" /data/adb/lspd/log/verbose_*.log | tail'
#    栈里出现 com.example.wechathook.WeChatHook$N.afterHookedMethod + com.tencent.mm.storage.g9 /
#    c01.w9.x / messenger.foundation / plugin.zero ⇒ hook 异常抛在微信的收信入库线程里
# 4. 排除法:CGI 心跳在不在(findersync/oplog/predownload_check)⇒ 排除"没网";
#    dumpsys power 看 mLastWakeTime ⇒ 排除"锁屏 Doze 冻结"(屏幕点亮期间同样零收信就是真断)

2026-09-19 16:22 实例:9 个群(8×TGO + nmm)同时停在 16:22:29,之前 6 小时每小时 20–39 条; convertTo 链路 33 条异常堆栈的最后一条 16:22:45;进程/闸口/发送/网络/CGI 全部正常。 即 hook 抛异常后微信的收信线程静默失效(发送链路不受影响)。

症状 2 的判据修正:别在夜间定罪(2026-09-20 08:00 轮实测,二次证伪)

初判「16:22 起收信全断」是错的,两轮实测都把它翻了:

  • DB 级逐小时桶(~/tmp/msg_liveness.py,走 wechat_db 直读 EnMicroMsg.db,绕开查看器 API 滞后)显示 09-19 傍晚/夜间一直在收:17:00=6、18:00=25、19:00=3、20:00=2、21:00=20、22:00=14、23:00=3、09-20 00:04=12、01:07=34。 ⇒ 01:19 轮那次数的是当时的 DB,看不到这些行 ⇒ 根因是「入库滞后」,不是「收信断」。
  • ⚠️ 真实机制:微信写 EnMicroMsg.db 的入库可以滞后数小时(createTime 是发送时刻,但行是后来才写入的)。 钩子日志里最后一次收信写入 = 09-20 03:06:39–40,一批 5 条 msgId=40096–40100、createTime 却是 01:08 —— 正是「03:05 查当日 0 条 → 03:12 同命令 5 条」的来源(查看器 API 读数滞后只是同一现象的表层)。 ⇒ 「DB 里没有新 inbound 行」不构成「收信已断」的证据;必须过一段时间复读(≥2 次不同时刻)再判。
  • 钩子日志同批仍伴随 afterHookedMethod 异常栈(03:06:39–40,与写入同刻),但5 行消息照样写进去了 ⇒ 该异常发生在写库之后的回调里、未阻断写库;03:06:40 之后再无新异常、也无新写入 ⇒ 无新增证据。
  • 查看器 API 会滞后(03:05 查当日 0 条 → 03:12 同命令 5 条)⇒ 单次读数不足以判「断」。

判据(否则一律不下结论):

su -c "sh ~/.hermes/skills/wechat/wechathook-recovery/scripts/hook_inbound_timeline.sh 8"
cd ~/wechat-viewer && python3 ~/tmp/msg_liveness.py   # DB 级逐小时桶(权威)
#  ① 逐小时桶「白天活跃时段也全程零」⇒ 可疑;「白天有、夜里稀」⇒ 正常
#  ② 最后一次收信写入/最后一条 isSend=0 的 createTime 落在【夜里 01:00–08:00】且只静默这几小时 ⇒ **不定罪**
#  ③ 钩子仍有 ANYCGI 事件 ⇒ 会话在线(但只说明「能连」,不说明「能收」)
#  ④ **先确认设备已唤醒**(2026-09-20 09:00 轮新增):`su -c "dumpsys power | grep mWakefulness"` = `Dozing`
#     或 `su -c "dumpsys window | grep mDreamingLockscreen=true"` = 1
#     ⇒ 微信在 Doze/锁屏期**不落库**,「DB 无新 inbound 行」与「真断」**不可区分**
#     ⇒ 结论只能写「**不可判(设备未唤醒)**」,**禁**写成「收信仍断」;等设备点亮/唤醒后再复查
#     (09-20 09:02 实测:全群静默 7.9h,但整轮 `mWakefulness=Dozing` ⇒ 当时任何结论都不成立)
  • 必须跨日/多次复查(≥2 次不同时刻的同型读数)才可升级为真故障;升级前禁 force-stop。白天判据可复用 ~/.hermes/skills/cron/cron-handoff-lifecycle/scripts/inbox_last_inbound.py(9 个群逐一给最后收信时刻与静默时长)。

处置(2026-09-20 当时的选择,供参考):

  • 恢复大概率要重启微信(force-stop + 用户手动打开),但按 wechathook-do-not-break, force-stop 会丢平板登录、需要火星人扫码 ⇒ 无人值守的 cron 轮内不要自己动手。
  • 正确做法:留存证据(DB 时间戳 + 异常堆栈 + 排除项)→ 发微信给 yibooo 请其拍板 → 写便条给后续窗口(~/tmp/sched_note_<date>_<HHMM>.txt)。过期日报补跑办法见便条。

实战案例

2026-07-29:闸口报告 "WeChatHook not injected"。诊断发现:

  • WeChat PID 30619(当前)≠ 29621(日志中 hook 注入的 PID)
  • 最新 verbose log 有 999 条 WeChatHook 行但是旧 PID 的
  • 新 PID 的 /proc/30619/maps 中无 wechathook → 根因:WeChat 被重启过,hook 未重新注入 → 修复:force-stop + 手动打开微信 → 新 PID 19525,BroadcastReceivers 重新注册 → 验证:发送 15 张图片全部 result=0