README.md 9.44 KB

Hermes WeChat SendMsg — LSPosed Module + AccessibilityService

针对 WeChat 8.0.72 的 Android 模块,包含两套发送实现:

  • ✅ HermesAccessibilityService(生产路径) — 监听广播 com.hermes.wechat.SEND_MSG,纯 UI 自动化:搜索联系人 → 输入文本 → 点发送按钮。当前唯一稳定可用的发送方式。
  • ❌ HermesWeChatModule(已废弃,保留代码作记录) — LSPosed 入口,hook ExtContentProviderBase / AESUtil 后反射调用 u01.r1.a → m1.a()。在 WeChat 8.0.72 上主线程 NetScene 提交持续 NPE 失败,Send result: true 是误报,消息不进 message 表。

功能

  1. A11y 自动化发送(主路径) — HermesAccessibilityService 模拟用户在微信主界面搜索联系人、点进聊天、写文本、点发送按钮
  2. Auth Bypass / AESUtil / MsgInfo hook(历史遗留) — HermesWeChatModule 内的 LSPosed hook 对生产路径没有影响,可选保留
  3. ContentProvider 暴露 — HermesWeChatProvider 把 content insert 翻译成广播,主要给非 root 的调用方用

项目结构

lsposed-wechat-sendmsg/
├── app/build.gradle              # App 模块构建配置
├── app/src/main/
│   ├── AndroidManifest.xml       # 模块声明 + Provider 暴露
│   ├── assets/xposed_init        # 模块入口类名
│   └── java/com/hermes/wechat/xposed/
│       ├── HermesWeChatModule.java   # Xposed 入口:Hook + 广播接收器
│       └── HermesWeChatProvider.java # ContentProvider:外部 API

编译

Mac 本地编译

# 1. 安装 Java(如尚未安装)
brew install openjdk@17
export JAVA_HOME=/opt/homebrew/opt/openjdk@17

# 2. 安装 Android SDK
mkdir -p ~/android-sdk/cmdline-tools
cd ~/android-sdk/cmdline-tools
curl -O https://dl.google.com/android/repository/commandlinetools-mac-11076708_latest.zip
unzip commandlinetools-mac-11076708_latest.zip
mv cmdline-tools latest
export ANDROID_HOME=~/android-sdk
export PATH=$PATH:$ANDROID_HOME/cmdline-tools/latest/bin

# 3. 接受许可并安装必要组件
yes | sdkmanager --licenses
sdkmanager "platform-tools" "build-tools;34.0.0" "platforms;android-34"

# 4. 编译 APK
cd lsposed-wechat-sendmsg
export ANDROID_HOME=~/android-sdk
./gradlew assembleRelease

# 输出:app/build/outputs/apk/release/app-release-unsigned.apk
# 签名:
keytool -genkey -v -keystore hermes-debug.keystore -alias hermes -keyalg RSA -keysize 2048 -validity 10000 -storepass hermes123 -keypass hermes123 -dname "CN=Hermes"
$ANDROID_HOME/build-tools/34.0.0/apksigner sign --ks hermes-debug.keystore --ks-pass pass:hermes123 --key-pass pass:hermes123 --in app/build/outputs/apk/release/app-release-unsigned.apk --out app/build/outputs/apk/release/app-release.apk

安装

A11y 路径(生产,必做)

  1. 安装本模块 APK:adb install app/build/outputs/apk/release/app-release.apk
  2. 启用 AccessibilityService(关键,最容易踩的坑): bash adb shell "su -c 'settings put secure enabled_accessibility_services com.hermes.wechat.xposed/com.hermes.wechat.xposed.accessibility.HermesAccessibilityService; settings put secure accessibility_enabled 1'" 或手动:设置 → 辅助功能 / 无障碍 → Hermes WeChat SendMsg → 启用
  3. 验证: bash adb shell "dumpsys accessibility | grep -A3 Hermes" # 应看到 Bound services / Enabled services 都包含 HermesAccessibilityService

A11y service 会在重启、微信更新、本模块更新、用户在设置里关闭后失效,发送将静默失败——把启用检查纳入保活脚本。

LSPosed 模块路径(可选,目前无功能贡献)

如果同时希望 LSPosed hook 生效(虽然反射发送已坏,但 hook 本身对 A11y 没影响):

  1. 确保 Magisk 已安装且 Zygisk 已启用
  2. 安装 LSPosed Zygisk 版(或 Vector 2.0+)
  3. LSPosed Manager → 模块 → 启用 HermesWeChatSendMsg → 作用域选择 微信(com.tencent.mm)
  4. 强行停止微信,重新打开

使用

发送文本消息(推荐方式:直接广播)

adb shell "am broadcast -a com.hermes.wechat.SEND_MSG \
  --es toUser yibooo \
  --es toUserDisplayName 火星人 \
  --es content '你好,这是测试消息'"

字段说明:

  • toUser — 接收者 wxid(如 wxid_xxxxxx、yibooo、filehelper)。注意:A11y 流程不直接用这个值发送,但留着用于校验
  • toUserDisplayName — 必须传:WeChat 里的 nickname(如 火星人、文件传输助手)。A11y 用它来在搜索框里输入并定位联系人。如果只传 wxid 通常搜不到
  • content — 消息内容

备用:ContentProvider insert

adb shell content insert \
  --uri content://com.hermes.wechat.xposed.provider/send \
  --bind toUser:s:yibooo \
  --bind content:s:"你好"

这条路径会双广播(同时触发 LSPosed 反射 + A11y),LSPosed 那条会失败但不影响最终结果;A11y 这条把消息真正发出去。但因为 content insert 不传 toUserDisplayName,A11y 会用 toUser 当 nickname 去搜,搜不到的情况下发送失败——所以推荐用 am broadcast 显式传 displayName。

查询发送状态

adb shell content query \
  --uri content://com.hermes.wechat.xposed.provider/status

返回 pending 或 true/false。

查看模块日志

# A11y 路径(看这个判断实际是否发送)
adb logcat -s HermesA11y:*

# LSPosed 路径(已废弃,仅供参考)
adb shell su -c "cat /data/adb/lspd/log/verbose_*.log | grep HermesWX | tail -20"

正常 A11y 成功日志:

HermesA11y: Received send request: to=yibooo searchName=火星人 content=...
HermesA11y: Root package=com.tencent.mm
HermesA11y: Already in correct chat, typing directly   (或 "Not in chat, starting search")
HermesA11y: Setting chat text: ...
HermesA11y: Clicking send button (by ID)
HermesA11y: State reset

技术细节

进程拓扑

外部调用方(adb / hermes / shell)
        │
        │ am broadcast com.hermes.wechat.SEND_MSG
        ▼
Android system broadcast manager
        │
        ├──────────────────────────┐
        │                          │
        ▼                          ▼
HermesAccessibilityService   HermesWeChatModule (LSPosed)
(模块 APK 进程)              (注入在微信主进程)
        │                          │
        │ AccessibilityNodeInfo    │ 反射调用 u01.r1.a → m1.a()
        ▼                          ▼
微信主进程 UI(前台)          【已坏:主线程 NPE 被 swallow】
        │
        ▼
微信走自己的发送流程 → 服务器 → message 表

两个广播 receiver 并行触发,A11y 那条成功、LSPosed 那条静默失败。整个生产路径只依赖 A11y。

A11y 用到的 UI 节点(WeChat 8.0.72)

用途 resource-id
主界面搜索按钮 com.tencent.mm:id/jha
搜索输入框 com.tencent.mm:id/d98
聊天输入框容器(FrameLayout,内含 EditText) com.tencent.mm:id/bkk
发送按钮 com.tencent.mm:id/bql
聊天页标题(用于校验进入了正确的会话) com.tencent.mm:id/obn

微信版本升级后这些 ID 会变化,需要重新 uiautomator dump 验证。

LSPosed Hook 点(历史记录,目前无生产作用)

目标类 方法 作用
ExtContentProviderBase h() → return 1 绕过 appId + UID + 签名校验
ExtContentProviderBase b() → return true 绕过登录状态检查
AESUtil b(long) → 返回原值 跳过加密,明文传递 wxid
AESUtil a(String) → 返回原值 跳过解密
MsgInfo (f9) c1(String) 监控消息内容变更,记录日志

LSPosed 反射发送的调用链 u01.r1.a → builder.e → builder.h(0) → builder.a() → m1.a() 在 WeChat 8.0.72 上 m1.a() 主线程提交触发 NPE 失败。已确认无法修复(怀疑 WeChat 在 NetScene 链路加了反作弊校验)。代码仍保留在 HermesWeChatModule.java 中作为反编译记录。

故障排查

现象 可能原因 解决
am broadcast 返回 0 但 yibooo 没收到 / message 表无新行 最常见:A11y service 未启用 adb shell "settings get secure enabled_accessibility_services",为 null 用上文命令重新启用
HermesA11y 日志 Root package=com.termux 后退出 广播触发时微信不在前台 先 adb shell am start -n com.tencent.mm/.ui.LauncherUI 再发 broadcast
Search button not found 当前不是 LauncherUI / nickname 错 确认 toUserDisplayName 是 WeChat 里实际的昵称
No clickable search result found 搜不到该 nickname 在微信里手动搜一下验证
[HermesWX] Send result: true 但 message 表没新行 LSPosed 反射路径的误报(已知 bug) 忽略 LSPosed 日志,看 HermesA11y 日志判断真实状态
微信 UI 节点 ID 找不到(升级后) WeChat 版本变化导致 resource-id 变 adb shell uiautomator dump 后重新核对
模块未出现在 LSPosed Manager APK 未正确安装或签名问题 重新安装模块 APK

安全提示

  • 本模块仅用于个人设备上的自动化测试和学习研究
  • 微信账号存在被封风险,建议在测试用小号上操作