吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 2365|回复: 37
上一主题 下一主题
收起左侧

[Android 分享] 椒盐音乐(Salt Player)12.3.2 PRO 功能分析

  [复制链接]
跳转到指定楼层
楼主
Bot95 发表于 2026-10-2 18:55 回帖奖励
本帖最后由 Bot95 于 2026-10-2 18:59 编辑


【前言】

椒盐音乐是作者 Moriafly 开发的纯本地音乐播放器,Pro 版走 Google Play 内购解锁。
分析过程中发现两点比较有意思:一是 Pro 权益判定完全落在客户端本地状态(MMKV)上,
没有服务端强校验;二是它内置了一套名为 "Sky" 的反篡改防护,检测维度比较全面,
值得拆一拆。本文仅做技术分析,不提供任何成品。

【实验环境】

- 设备:Android 真机 / 模拟器(Android 15)
- 逆向工具:MT Manager(MCP 自动化)、Jadx、Apktool
- 分析方式:静态分析 + MCP 自动化检索(dex 字符串/方法/字段交叉引用)

【App 基本信息】

- 应用名:Salt Player(椒盐音乐)
- 包名:com.salt.music
- 版本:12.3.2(versionCode 2026090601)
- minSdk / targetSdk:23 / 36
- 签名方案:V1 + V2
- 加固情况:无壳(R8 混淆 + 自定义字符串加密)
- UI 框架:Jetpack Compose
- 关键 so:无 native 层参与校验逻辑,纯 Java/Kotlin 层

【混淆与保护手法观察】

1. **命名桶伪装**:R8 重命名时把大量业务类映射进了 androidx.media3 这个第三方
   命名空间下,很容易被误判成 ExoPlayer 媒体库代码,实际是核心业务逻辑。
2. **字符串编译期加密**:所有敏感字符串(SKU、接口地址、渠道标识、邮箱等)在编译期
   被替换为 long 常量,运行时统一经一个解密函数还原(形如 `X.ތ(long)`),
   静态检索看不到明文,需顺着调用点理解语义。
3. **Lambda 池合并**:大量单逻辑被合并进共用的 synthetic lambda 类,通过构造参数
   (case id)在方法内用 packed-switch 分发。定位具体功能必须结合 `<clinit>` 中
   Lazy 包装时传入的 case 号,不能只看类的表象语义。

【权益模型分析】

Pro 通过 Google Play Billing 解锁,商品定义为枚举,含两个条目:

- **SaltPlayerPro**:主程序 Pro 权益(对应一个正式 SKU + 一个 debug SKU)
- **AudiophilePack**:Pro 之上的独立专业拓展包(USB 独占输出、DAC 控制、
  一项名为 Morvanium 的智能音频过渡分析功能)

除内购外还有多渠道分发(Google Play / 官网直售 / 联名发行),
渠道判定由一个独立单例完成,官网渠道通过 MMKV 存储用户 token,
配合服务端下单接口完成购买。

购买链路大致为:Billing 管理器 → queryPurchases 回调(遍历 Purchase 的
productIds 匹配 SKU)→ 结果回调命中则置位本地状态并落盘 MMKV。

**关键结论一**:权益判定最终只依赖客户端本地的一个布尔状态(MMKV 持久化),
未购买时不会主动写 false,只吃初始化默认值。这意味着状态位的读写入口就是分析切入点,
客户端侧存在修改空间(服务端无法强校验这一层)。

【Sky 反篡改防护拆解】

这是本文的重点。该防护在启动首屏路由阶段即触发,表现为进入即弹拦截页,
页面含一个向作者报告的邮箱入口和一个"立刻上报并退出"的按钮。

检测链路集中在 Sky 相关类及其关联的懒加载 lambda,结果以布尔值注入首屏路由,
由路由决定渲染拦截页还是正常主界面。检测维度包括:

1. **assets 特征文件扫描**
   遍历 assets 目录取全部文件名,与内置黑名单比对,识别常见的破解/patch
   特征文件(如 SignatureKiller、Hook_so、lspatch、KillByNP 等)。
   这类检测针对的是"二次打包后再注入 patch 工具"的场景。

2. **核心签名多重校验(最关键,也是重打包必然踩雷的点)**
   经一个独立的签名管理类做多层校验,包含:
   - 签名 hashCode 与内置常量比对
   - 包名 / 渠道哈希比对
   - ApplicationInfo 的 debug flag 检测
   - 第三方崩溃上报 SDK 的包名 MD5 校验
   - 自定义 ClassLoader 动态加载校验

   重打包后签名必然改变,上述任一项比对失败即判定篡改。

3. **宿主 Application 完整性**
   校验 Application 的父类是否仍为原生父类,防止被 hook 框架替换。

4. **签名块存在性检测**
   检测 APK 内是否存在 v2/v3 签名块被剥离的痕迹(SignatureKiller 式改包手法的
   对抗检测)。

【遇到的坑(重点踩坑记录)】

**坑 1:检测布尔值的极性容易搞反,方向错了越改越糟。**
这是本次分析最大的弯路。该防护有两处布尔检测(assets 扫描结果 + 核心签名校验),
最终注入首屏路由决定渲染拦截页还是主界面。首次分析时我把 assets 扫描的返回值
改成了 false,结果不仅没绕过,反而被路由逻辑推向了拦截分支——因为在消费端
的分支语义里,false 恰恰对应"需要拦截"的路径。
**教训:这类开关不能凭直觉判断 true/false 哪个是"安全",必须顺着消费方的
if/else 分支把两种取值各走一遍,确认哪个值走正常流程,再动手改。**

**坑 2:认准"伪混淆",别被类名表象带跑。**
业务类藏在 androidx.media3 下,第一反应容易当成媒体库代码而跳过。
识别办法:看有没有业务特征字符串、有没有被 Settings/Billing 链路引用。

**坑 3:Lambda 池里定位功能要跟 case 号。**
共用 lambda 类里有几十个分支,靠构造参数分发。只看类的表象方法名
(比如看到一个全是 Compose 渲染代码的类)会误判其用途,必须回到
`<clinit>` 看 Lazy 包装时传的到底是哪个 case。

**坑 4:静态加密字符串让搜索失效。**
直接搜关键字符串搜不到,必须结合调用链和上下文反推语义,比如顺着
"购买结果回调 → 状态置位方法 → MMKV 写入"这条链一路跟下去。

【复现要点小结】

1. 从资源文案和购买提示切入,确认是本地权益而非服务端校验
2. 顺着 Billing 回调找到权益状态位的 setter/getter
3. 拦截页从特征文案反查渲染方法,再顺着路由消费方定位检测结果注入点
4. 检测判定常有多层(assets 扫描 + 签名多重比对 + hook 检测),
   客户端侧真正卡住重打包的是签名比对那几层
5. 改任何布尔开关前,先把 true/false 两种取值在消费端各推演一遍

【核心结论】

- 权益判定:纯客户端本地状态,无服务端强校验,客户端侧存在修改空间
- 反篡改:assets 特征扫描 + 签名多重比对 + Application 完整性 + 签名块检测,
  设计较完整,对二次打包和注入式 patch 都有针对性拦截
- 整体看,该 App 的加固思路值得学习:权益与反篡改解耦(权益弱、反篡改强),
  把主要防护压力放在反篡改而非权益校验上

【参考】

- 静态分析工具链:MT Manager (MCP)、Jadx、Apktool
- 交流与勘误欢迎论坛内讨论

【免责声明】

本文及所涉分析仅限用于学习和研究目的,不得用于商业或非法用途,
否则一切后果由使用者自负。请勿将本文内容用于制作、传播破解成品或注册机。
分析涉及的样本请在研究结束后及时删除。
喜欢请支持正版软件。[/md]

免费评分

参与人数 4吾爱币 +3 热心值 +4 收起 理由
ifrv + 1 + 1 鼓励转贴优秀软件安全工具和文档!
VictorEL1 + 1 热心回复!
wanfon + 1 + 1 热心回复!
Ty007 + 1 + 1 我很赞同!

查看全部评分

发帖前要善用【论坛搜索】功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

推荐
zhiqingchun 发表于 2026-10-5 09:44
楼主这个分析写得很扎实,特别是把三个大坑都记录下来了。坑3那个 Lambda 池 case 号的教训特别真实——只看类名语义确实太容易被 R8 的命名桶伪装带偏,androidx.media3 这个伪装有点损。

想请教两个问题:

1. MT Manager 那边的 MCP 自动化检索是怎么接的?是自己写了 MCP server 去桥接它的脚本能力,还是用的现成方案?我之前做类似本地校验的应用基本都是手动在 Jadx 里一层层跟,效率确实低。

2. 关于权益状态位,最后是直接改 MMKV 落盘的值生效,还是在 Billing 的 queryPurchases 回调链路上动的手?按帖子里的购买链路描述,回调命中后置位并落盘,那如果用 frida 伪造 queryPurchases 返回的 Purchase 列表,是不是更稳一点,至少版本升级后不用重新找混淆后的 MMKV key?

另外 Sky 那套检测链路最后“以布尔值注入首屏路由”的设计挺有意思,相当于把所有防护收敛成一个开关再消费,这种收敛点反而是最好的定位目标。下次再遇到类似的应用,我也先找这个收敛点下手。
沙发
ruomengfeiyang 发表于 2026-10-3 00:27
感谢分享经验,现在的软件防破解做的越来越仔细了
3#
shumengzu6 发表于 2026-10-3 09:21
4#
SaoXiaoyu 发表于 2026-10-3 09:22
换个思路讲,软件只走本地校验尝试绕过谷歌的IAB也是一种不错的方式
5#
Benett 发表于 2026-10-3 11:21
试试看怎么样
6#
maqianjin100 发表于 2026-10-3 11:53
不错,下载下来试试
7#
seawhale 发表于 2026-10-3 13:33
看上去不错的
8#
zhuan 发表于 2026-10-3 15:36
感谢分享经验,现在的软件防破解做的越来越仔细了
9#
那样不行asd 发表于 2026-10-3 16:36
这思路好帮啊
10#
ljkone 发表于 2026-10-3 16:53
FB2K,绝对的神。
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - 52pojie.cn ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2026-10-17 02:01

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表