# 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 本地编译 ```bash # 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 版](https://github.com/JingMatrix/LSPosed/releases)(或 Vector 2.0+) 3. LSPosed Manager → 模块 → 启用 HermesWeChatSendMsg → 作用域选择 **微信(com.tencent.mm)** 4. 强行停止微信,重新打开 ## 使用 ### 发送文本消息(推荐方式:直接广播) ```bash 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 ```bash 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。 ### 查询发送状态 ```bash adb shell content query \ --uri content://com.hermes.wechat.xposed.provider/status ``` 返回 `pending` 或 `true`/`false`。 ### 查看模块日志 ```bash # 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 | ## 安全提示 - 本模块仅用于个人设备上的自动化测试和学习研究 - 微信账号存在被封风险,建议在测试用小号上操作