Files
notiMessage/docs/Hook指南.md

13 KiB
Raw Blame History

消息抓取架构与 Hook 扩展指南

本文说明 notiMessage 的双通道抓取机制、Telegram 的实现方式、Xposed 与 LSPosed,以及日后接入其他 App 的步骤。

手机部署步骤见 手机操作手册.md · Telegram 专文Telegram抓消息说明.md · MariBank 见 MariBank风控与载荷说明.md


0. Xposed 与 LSPosed

0.1 是什么关系

Xposed经典 LSPosed
性质 Hook 框架概念 + 老实现(改 /system 现代实现,不动 system
依赖 老 Root / Recovery Magisk + Zygisk
作用域 全局或 Installer 里选 按 App 勾选
模块 API IXposedHookLoadPackage 同一套 API
本项目 源码在 xposed-module/ 手机上实际加载框架

日常说法:「Xposed 模块」= APK「启用 Xposed」= 在 LSPosed 里打开模块并勾选作用域

0.2 与本项目的关系

Magisk → Zygisk → LSPosed → com.miraclegarden.smsmessage.xposed
                              ├── MariBankRootBypassHook银行
                              ├── TelegramMessageHookTelegram
                              └── …

测银行 App 时通常还需 ShamikoHide Magisk与 LSPosed 分工见 MariBank风控与载荷说明.md §6

0.3 与其他工具对比

工具 特点
LSPosed 常驻、开机自动,适合银行 bypass
Frida 临时 attach与 LSPosed 同时开易冲突
Magisk 模块 改系统属性serial不是 Hook Java

1. 总体架构

notiMessage 使用 两条独立通道 抓取消息,互为补充:

┌─────────────────────────────────────────────────────────────────┐
│                        目标 App如 Telegram                    │
└───────────────┬─────────────────────────────┬───────────────────┘
                │                             │
     后台/锁屏弹系统通知              前台打开 App、消息入库/解码
                │                             │
                ▼                             ▼
   NotificationListenerService          Xposed Hook 模块
   (NotificationService)              (xposed-module)
                │                             │
                │                             │ Broadcast
                │                             ▼
                │                    HookMessageReceiver
                │                      │ goAsync()
                │                      ├─ MessageLogStore立即写入
                │                      ├─ DebugForwarder直接转发 PC
                │                      └─ submitFromHook仅正式上传模式
                │                             │
                └──────────────┬──────────────┘
                               ▼
              NotificationService.submitNotification()(通知通道)
                               │
              ┌────────────────┼────────────────┐
              ▼                ▼                ▼
      MessageLogStore    DebugForwarder    (可选)正式后端上传
      App 本地日志)    PC 调试台)      AppConfig.ENABLE_SERVER_UPLOAD
通道 触发条件 代码入口 日志前缀
通知监听 目标 App 在后台且弹出系统通知 NotificationService.onNotificationPosted() 无前缀
Hook 目标 App 进程收到新消息(通常在前台) HookMessageReceiver → 直接 DebugForwarder [Hook/xposed_telegram]

重要:仅开通知监听时,目标 App 在前台通常 不会 产生系统通知,因此抓不到消息。要覆盖前台场景,必须启用 Xposed Hook。


2. Telegram 实现方式

完整安装、双通道、排错、logcat:见专文 Telegram抓消息说明.md。本节保留架构摘要。

2.1 包名与作用域

Pixel 6 等设备上 Telegram 常见包名:

安装来源 包名
Play / 官网 APK org.telegram.messenger
部分渠道 / Web 版 org.telegram.messenger.web

LSPosed 作用域需勾选 目标 Telegram 包名 + notiMessage 主 App

默认作用域见 xposed-module/src/main/res/values/arrays.xml

2.2 为何不 Hook SQLite

Telegram 消息存在 SQLite 的 data 字段(加密二进制 TL 序列化),不是明文 content/text

通用 SqliteMessageHook 只能读明文列,对 Telegram 无效。因此单独实现 TelegramMessageHook

2.3 Hook 点

主路径Hook NotificationCenter.postNotificationName(int, Object[])

  • 读取静态字段 NotificationCenter.didReceiveNewMessages 作为事件 ID
  • id == didReceiveNewMessages 时,从参数里的 List<MessageObject> 取新消息
  • 只处理 非 outgoingmessageOwner.out == false)的消息

兜底路径Hook MessageObject 全部构造函数(主路径失败时启用)

源码位置:xposed-module/.../hook/TelegramMessageHook.java

2.4 字段提取逻辑

字段 提取方式 用途
群名/会话名 MessagesController.getPeerTitle(dialogId)MessageObject.getName()getChat().title 分组标题、转发 group
发送者 MessageObject.getFromName() 群内消息前缀 发送者: 内容
正文 messageTextmessageOwner.messagecaption 文本内容
图片+说明 识别 [图片] 等媒体标签 + 合并 caption 避免只显示「图片」丢失说明
dialogId MessageObject.getDialogId() 去重键 dialogId:messageId

注意:不要把 messageOwner.from_idTLRPC$TL_peerUser 对象)直接 toString() 当标题,会出现 TLRPC$TL_peerUser@xxxx

2.5 转发到主 App

Hook 模块通过 HookForwarder 发送广播:

Action: com.miraclegarden.smsmessage.action.HOOK_MESSAGE
Package: com.miraclegarden.smsmessage
Extras: packageName, title, content, timestamp, source=xposed_telegram

主 App 的 HookMessageReceiver 接收后:

  1. 检查该 packageName 是否在监听列表(App.getMessageByNotiList
  2. 写本地日志(MessageLogStore,立即持久化)
  3. 直接转发 PCDebugForwarder,不依赖 startService,后台可用)
  4. 若开启正式上传(ENABLE_SERVER_UPLOAD),再经 submitFromHook 交给 NotificationService

3. 主 App 相关模块

文件 职责
NotificationService.java 通知监听 + 统一提交入口
HookMessageReceiver.java 接收 Xposed 广播
MessageLogStore.java 日志持久化(后台也能保留历史)
DebugForwarder.java POST 到 PC 调试服务
AppConfig.java ENABLE_DEBUG_FORWARDENABLE_SERVER_UPLOAD 开关

PC 调试台

# 启动本地服务(含 adb reverse
powershell -ExecutionPolicy Bypass -File scripts\start-debug-server.ps1
# 浏览器打开 http://127.0.0.1:8765 ,按群/会话分组展示

4. 日后接入其他 App 的步骤

4.1 先判断用哪种 Hook 策略

目标 App 前台消息是否需要抓取?
├─ 否 → 仅通知监听即可,在 App「监听设置」里添加包名
└─ 是 → 需要 Xposed Hook
         │
         ├─ 消息以明文写入 SQLitecontent/text/body 等)?
         │   └─ 是 → 可复用 SqliteMessageHook默认兜底
         │
         ├─ 微信?
         │   └─ 是 → 已有 WeChatMessageHookHook WCDB message 表)
         │
         └─ 其他Telegram、WhatsApp、银行 App 等)
             └─ 需编写 **专用 Hook 类**

4.2 新增专用 Hook 的标准流程

以新 App com.example.chat 为例:

步骤 1分析目标 App

  1. adb shell pm path <包名> 拉出 APK
  2. jadx / dexdump 找消息解码后的类(类似 Telegram 的 MessageObject
  3. 确认:消息明文出现在哪个字段、哪个时机(构造函数 / 事件总线 / 通知回调)

步骤 2编写 Hook 类

xposed-module/src/main/java/.../hook/ 新建 ExampleChatMessageHook.java

public final class ExampleChatMessageHook {
    public static void install(XC_LoadPackage.LoadPackageParam lpparam) {
        // 1. findClass + findAndHookMethod / hookAllConstructors
        // 2. 提取 title群名、content正文、过滤 outgoing/系统消息
        // 3. 去重messageId + dialogId
        // 4. HookForwarder.forward(context, lpparam.packageName, title, content, "xposed_example");
    }
}

HookBridge.java 增加 source 常量,例如 SOURCE_XPOSED_EXAMPLE = "xposed_example"

步骤 3注册到 MainHook

编辑 MainHook.java

if ("com.example.chat".equals(lpparam.packageName)) {
    ExampleChatMessageHook.install(lpparam);
    return;
}

步骤 4更新 LSPosed 作用域

编辑 xposed-module/src/main/res/values/arrays.xml

<item>com.example.chat</item>

步骤 5主 App 添加监听

在 notiMessage「监听设置」中添加该 App或通过 shared_prefs/server.xmlsaveNotiList)。

bankInfoId 本地调试可用 local:<包名>

步骤 6构建、安装、验证

# 完整安装(主 App + Xposed + LSPosed 作用域)
powershell -ExecutionPolicy Bypass -File scripts\install-full.ps1

验证清单:

  • LSPosed 中模块已启用,作用域勾选 目标 App + notiMessage
  • 强制停止并重启目标 App让 Hook 重新加载)
  • notiMessage 监听控制台「开始监听」
  • 后台场景:收消息 → 通知通道有日志
  • 前台场景:收消息 → [Hook/xxx] 日志 + PC 调试台有数据
  • adb logcat | grep notiMessageHook 可见 installed for <包名>

4.3 复用通用 SqliteMessageHook 的条件

SqliteMessageHook 会在 MainHook 中作为 默认兜底 安装(非微信、非 Telegram 时)。

适用 App 特征:

  • 使用标准 SQLiteDatabase / FrameworkSQLiteDatabase
  • 表名含 message / messages
  • ContentValues 中有明文列:contenttextbodymsg

不适用Telegram、WhatsApp、Signal 等端到端加密或二进制 data 列的 App。

4.4 已有专用 Hook 参考

App Hook 目标
微信 WeChatMessageHook com.tencent.wcdb.database.SQLiteDatabase insertmessage
Telegram TelegramMessageHook NotificationCenter.didReceiveNewMessages + MessageObject
其他 SqliteMessageHook 通用 SQLite insert 兜底

5. 构建与安装

脚本 用途
scripts/build-debug.ps1 构建主 App + Xposed 双 APK
scripts/install-debug.ps1 仅安装双 APK
scripts/install-full.ps1 推荐:构建 + 双 APK + LSPosed 作用域 + adb reverse + 电池白名单
scripts/start-debug-server.ps1 启动 PC 调试台

注意Android Studio 点 Run 只安装 :app 主模块,不会安装 Xposed 模块。完整功能必须用 install-full.ps1 或手动安装两个 APK。


6. 常见问题

现象 原因 处理
前台有消息App 无日志 仅通知通道Hook 未生效 检查 LSPosed 作用域、重启目标 App
标题显示 TLRPC$... 误把对象当字符串 getPeerTitle 等 API见 TelegramMessageHook
图片消息只有「图片」 说明在 caption 字段 合并 caption + 媒体标签
PC 有数据App 无历史 旧版日志未持久化 已用 MessageLogStore 修复,更新主 App
Hook 日志前缀 [Hook/...] Xposed 未注入 确认 Magisk + LSPosed + 模块启用

7. 相关文件索引

xposed-module/
├── src/main/assets/xposed_init          # 入口 MainHook
├── src/main/java/.../MainHook.java      # 包名路由
├── src/main/java/.../HookForwarder.java # 广播转发
├── src/main/java/.../hook/
│   ├── TelegramMessageHook.java
│   ├── WeChatMessageHook.java
│   └── SqliteMessageHook.java
└── src/main/res/values/arrays.xml       # xposed_scope 默认作用域

app/
├── src/main/java/.../service/
│   ├── NotificationService.java
│   └── HookMessageReceiver.java
├── src/main/java/.../MessageLogStore.java
├── src/main/java/.../network/DebugForwarder.java
└── src/main/java/.../AppConfig.java

debug-server/server.py                   # PC 调试台
scripts/install-full.ps1                 # 一键完整部署