# raw_codec_rpc 基于 Frida RPC 的 `raw_data` 编解码调用封装,核心依赖 App 运行时中的 Java 层逻辑(`gc.b.b` / `gc.a.intercept`)。 ## 目录说明 - `jhs_raw_codec_rpc.js`:Frida 侧 RPC 脚本(实现 enc/dec) - `jhs_raw_codec_client.py`:Python 客户端封装(设备连接、attach、RPC 调用、CLI 兜底) - `jhs_rpc_spider.py`:主爬虫脚本(定时采集 + 入库) - `demo.py`:单页请求封装示例(可直接改为多页循环) - `auto_dismiss_update.js`:常驻 Frida 脚本(自动 dismiss App 启动时的"立即更新"弹窗) - `start_auto_dismiss.ps1` / `stop_auto_dismiss.ps1`:弹窗清除脚本的后台启动 / 停止 - `start_jhs_zygiskfrida_bg.ps1` / `stop_jhs_zygiskfrida_bg.ps1`:旧版后台 hook 启停脚本(当前未使用,保留备查) - `application.yml`:配置文件(数据库等) - `requirements.txt`:Python 依赖清单 ## 1. 环境要求 ### 1.1 PC 端(Windows) - Python:3.12.10+ - ADB:可用(`adb version` 正常) - Frida CLI:可用(`frida --version` 正常) - Python 包:`frida`、`frida-tools`、`requests` ### 1.2 设备端(Android) > **本项目使用 ZygiskFrida(Zygisk 模块)而非传统 frida-server。** > ZygiskFrida 会在 App 启动时自动将 frida-gadget 注入目标进程,无需手动推送或运行 frida-server。 - 已 root(Magisk / KernelSU)并启用 Zygisk - 已安装 [ZygiskFrida](https://github.com/lico-n/ZygiskFrida) 模块,并在模块配置中指定目标包名 `com.jihuanshe` - 已安装并可启动目标 App:`com.jihuanshe` - 设备可 ADB 连接 ## 2. 安装步骤 ### 2.1 PC 端安装 在 `scripts/raw_codec_rpc` 目录下执行: ```bash python -m venv .venv .venv\Scripts\activate pip install -r requirements.txt ``` 确认命令可用: ```bash python -c "import frida, requests; print('ok')" frida --version adb version ``` ### 2.2 设备端安装 ZygiskFrida > 本项目**不使用**传统的 `frida-server`,而是通过 ZygiskFrida 模块在 App 启动时自动注入 frida-gadget。 1. 确保设备已 root 且 Magisk/KernelSU 中 **Zygisk 已开启** 2. 下载 [ZygiskFrida](https://github.com/lico-n/ZygiskFrida/releases) 模块 zip,在 Magisk/KernelSU 中刷入 3. 在 `/data/local/tmp/re.zyg.fri/target_packages.txt` 中添加目标包名: ``` com.jihuanshe ``` 4. 重启设备使模块生效 5. 验证:启动目标 App 后,在 PC 端执行: ```bash frida -U -N com.jihuanshe ``` 如果能正常 attach 说明 gadget 注入成功。 ### 2.3 弹窗清除脚本(按需启动) 老版本 App 启动会弹"立即更新"提示,挡住登录等人工操作。提供常驻 Frida 脚本自动 dismiss: **启动**(重启 App → 等待 gadget 注入 → 挂载 dismiss 脚本): ```powershell .\start_auto_dismiss.ps1 # 后台运行 .\start_auto_dismiss.ps1 -Foreground # 前台跑,看实时日志(推荐调试时用) .\start_auto_dismiss.ps1 -NoRestart # App 已经在跑,跳过重启直接 attach ``` 可选参数: | 参数 | 默认值 | 说明 | |------|--------|------| | `-Package` | `com.jihuanshe` | 目标包名 | | `-DelayMs` | `12000` | 等待 ZygiskFrida 注入毫秒数 | | `-Adb` | `D:\platform-tools\adb.exe` | adb 路径 | | `-Frida` | `C:\Python\Python312\Scripts\frida.exe` | frida CLI 路径 | | `-Hook` | `auto_dismiss_update.js` | hook 脚本路径 | | `-NoRestart` | 关 | 加上则跳过 App 重启,直接 attach | | `-Foreground` | 关 | 前台运行(Ctrl+C 停止);不加则后台运行写日志文件 | **停止**: ```powershell .\stop_auto_dismiss.ps1 ``` **说明**:弹窗只挡人工操作,不影响爬虫 RPC(爬虫不碰 UI),所以该脚本只在「需要登录刷 token」时跑一次即可,**日常爬取不需要**。 ## 3. 日常使用流程 ### 3.1 场景 A:日常跑爬虫(token 还有效) 只要 App 在手机上正常运行(ZygiskFrida 会在 App 启动时自动注入 gadget),直接: ```bash python .\jhs_rpc_spider.py ``` 爬虫的 `JhsRawCodecClient` 会自己 attach 到 App 调 RPC,不需要任何其他守护进程。弹窗在不在都无所谓。 ### 3.2 场景 B:token 过期需要重新登录 `jhs_token` 表里的 token 是 JWT,过期后接口会返回 `401 MARKET_UNAUTHORIZED`,爬虫报 `KeyError: 'raw_data'`。流程: ```powershell # 1. 启动弹窗清除(推荐 -Foreground 看日志) # App 还没开 → 用这条(会自动重启 App 并等待注入) .\start_auto_dismiss.ps1 -Foreground # App 已经在跑 → 用这条(跳过重启,直接 attach,更快) .\start_auto_dismiss.ps1 -NoRestart -Foreground # 看到 [dismiss] all hooks installed 即可,弹窗一出来就会被自动关掉 # 2. 在手机里登录账号;用抓包工具拿新 token # (token 在登录接口返回里,或后续请求的 token 参数) # 3. 手动 UPDATE 数据库 # UPDATE jhs_token SET token = '<新token>' WHERE id = 1; # (写库操作必须人工执行) # 4. Ctrl+C 停掉 dismiss 脚本(或者 .\stop_auto_dismiss.ps1) # 5. 跑爬虫 python .\jhs_rpc_spider.py ``` ### 3.3 程序运行时的设备状态要求 - 设备保持开机,不要休眠 - 目标 App 已启动,并停留在前台页面(至少已完成初始化) - ZygiskFrida 模块已生效(App 启动时 gadget 会自动注入,无需额外守护进程) - 跑批量分页时,不要频繁切换 App 到后台 ## 4. 关键参数说明 `JhsRawCodecClient(...)` 支持: - `device_id`:指定设备 ID(多模拟器必须传) - `cli_target_sec`:CLI 兜底模式的 frida `-t` 秒数(建议 `2` 或 `3`) 可选环境变量(不强制): - `FRIDA_DEVICE_ID` - `FRIDA_CLI_TARGET_SEC` - `JHS_CODEC_DEBUG`(`1/true/on` 开启日志) ## 5. 推荐调用方式(多页复用) 核心原则:**client 和 Session 放在循环外,只创建一次。** ```python from jhs_raw_codec_client import JhsRawCodecClient import requests page = 1 with JhsRawCodecClient(device_id="25051FDD4S018P", cli_target_sec=2) as client: with requests.Session() as sess: while page < 100: result = fetch_market_page( page=page, token=TOKEN, client=client, session=sess, headers=HEADERS, ) print(page, result["decoded"]) page += 1 ``` ## 6. 性能建议 - 多页任务复用单个 `JhsRawCodecClient` - 多页任务复用单个 `requests.Session` - `cli_target_sec` 建议先设 `2`,不稳定再回退 `3` - 仅在排障时开启 `JHS_CODEC_DEBUG` ## 7. 常见问题排查 ### 7.1 `unable to attach ...` - 确认 App 正在运行 - 确认 `device_id` 传对 - 确认 ZygiskFrida 模块已启用,且 `target_packages.txt` 包含目标包名 - 尝试重启 App(或用 `start_jhs_zygiskfrida_bg.ps1` 重新走完流程) ### 7.2 `Java is not defined` - 当前会自动降级到 CLI 兜底 - 若仍慢,优先调低 `cli_target_sec` ### 7.3 多模拟器连错设备 - 显式传 `device_id` - 用 `adb devices` / `frida-ls-devices` 核对 ID ### 7.4 "立即更新"弹窗去不掉 老版本 App 启动会弹"有新版本 / 立即更新",挡住登录操作。 **先用算法助手**(LSPosed 模块)的「拦截关键词弹窗」开关,多数 App 这样就够了。 **若算法助手失效**(集换社这个弹窗就是):它不是标准 `Dialog`,而是 App 自己用 `WindowManager.addView()` 手撸的自定义弹窗,算法助手只盯标准 Dialog,盯不到这层。解决: ```powershell # App 已经在跑、弹窗正显示时,直接 attach 我们的脚本即可 .\start_auto_dismiss.ps1 -NoRestart -Foreground ``` `auto_dismiss_update.js` 在最底层的 `WindowManager.addView()` 也下了 hook,能兜住任意形态的弹窗。原理详见 `docs/优化记录_jhs_rpc_spider_20260609.md` 的 §5、§6。 排查口诀: 1. 确认算法助手「拦截关键词弹窗」已开、关键词文案对得上 2. 仍不掉 → 大概率是自定义 `WindowManager.addView` 实现 3. 用我们的 `start_auto_dismiss.ps1` 兜底 ## 8. 安全说明 - `TOKEN` 建议不要硬编码在仓库,改为环境变量或外部配置 - 避免在日志中输出完整 token/raw_data(生产环境)