一场有趣的猫鼠游戏:当开发者针对旧版破解方案引入了硬编码的校验逻辑,我们该如何层层剥茧,还原其背后的算法真相?
0x01 前言
在 8 月份的文章中,我分享了如何通过 mitmproxy 激活 Shottr。原本以为这只是一个简单的 HTTP 数据包篡改游戏,但作者在 v1.9.1 版本中打了一个"反击战"。
更新版本后,原本的 Mock 方案失效了。抓包发现 API 返回了一个全新的字段 ch2,其格式类似于 时间戳.Hash。如果不提供匹配的 Hash,客户端会抛出严重的 Integrity 校验错误。
这不再是修改一个布尔值就能解决的问题。这是一次需要动用静态分析与动态追踪的深度逆向实战。
本文仅供网络安全技术交流与学习,请支持正版软件。
0x02 成果展示
在深入枯燥的汇编代码之前,我们先来看看最终的破解成果。
下面的截图,均采用破解后的 Shottr v1.9.1 完成的
破解前
破解前:License 验证失败

破解后
破解后:激活成功,显示 Pro 订阅

0x03 初步摸底:隐藏在二进制中的密钥
当我们尝试像以前那样伪造 tier 字段(会员等级)时,客户端报错了。观察网络请求,除了 verify.php 之外,并没有其他远程校验行为。
结论很明确: 校验这个 ch2 Hash 的逻辑和所需的 Secret,全部硬编码在 Shottr 的二进制文件中。只要我们能在几万行汇编中定位到那段逻辑,算法就无所遁形。
0x04 静态分析:定位验证入口 (radare2)
我们使用 radare2 来探索 Shottr 的内心世界。
1. 寻找突破口
首先,我们搜索 API 返回的关键字段名和可能的报错信息:
| |
输出定位到了数据段中的字符串地址。
2. 追踪交叉引用 (X-Ref)
找到字符串后,我们通过 axt 命令寻找是谁在引用这些字符串。最终我们将目光锁定在了函数 sym.func.1000e25e0 上。
反汇编该函数,我们发现了决定性的逻辑分支:
| |
通过这一步,锁定了核心验证逻辑的起始地址:0x1000e7ae4。
3. 发现加密原语
在这个验证函数周边,我们发现它频繁调用了 CC_SHA256。通过搜索加密函数的 X-Ref,我们还意外在地址 0x1001f3280 附近发现了一些长得像 Secret 的 16 位硬编码字符串。
目前的战果:
- 找到了验证函数入口。
- 确认了使用了 SHA256 算法。
- 拿到了几个可疑的 Secret。
难点: 静态分析很难看清 SHA256 输入字符串的精确拼接格式(比如有没有空格?先后顺序?)。
0x05 动态追踪:窥察内存真相 (Frida)
为了看清内存中生成的拼装字符串,我们需要在运行时"窃听" CC_SHA256。
1. 绕过 Hardened Runtime
Shottr 启用了 macOS 的 Hardened Runtime,这会阻止调试器。我们需要先给它脱掉这层"软甲":
| |
2. 编写 Frida Hook 脚本
我们使用 frida-trace 快速生成模版,并编写 Handler 打印 CC_SHA256 的第一个参数(即待计算的明文字符串)。
| |
3.触发验证
运行 Frida,并在 Shottr 界面输入任意 License Key。惊喜出现了,Frida 捕获到了三次连续的哈希计算过程:
- 第一波:
License前缀 + SECRET_A→Hash1 - 第二波:
License前缀 + Hash1 + " " + 当前时间戳 + " " + SECRET_B - 第三波 (关键):
License前缀 + Hash1 + " " + ch2时间戳 + " " + tier + " " + SECRET_C
0x06 算法还原:最终的公式
6.1 完整公式
基于动态分析,还原出 ch2 验证算法:
| |
6.2 验证算法正确性
编写 Go 程序验证:
| |
用 Frida 捕获的数据验证:
- 输入: license前缀=“1234”, timestamp=“1767014600”, tier=“free”
- 计算结果与 Frida 捕获的 hash 完全匹配 ✅
这意味着什么?这意味着 Shottr 的安全性完全建立在 Secret 的私密性上。而既然 Secret 是硬编码在客户端的,对于逆向工程来说,它就是透明的。
0x07. 关键发现
7.1 算法特点
- 双重哈希: 先计算 license 的基础 hash,再计算最终验证 hash
- 时间戳绑定: hash 包含时间戳,防止重放
- 等级绑定: hash 包含 tier,防止篡改等级
- License 绑定: hash 包含 license 前缀
7.2 安全弱点
- Secrets 硬编码: 所有 secret 都存储在客户端二进制中
- 算法可逆: 知道 secrets 后可以计算任意有效的 ch2
- 无证书固定: 可以进行中间人攻击
7.3 利用方式
基于以上分析,可以实现:
- 中间人攻击,动态计算并返回有效的 ch2
- 本地 patch,绕过验证检查
0x08. 工具和命令汇总
radare2 常用命令
| 命令 | 说明 |
|---|---|
aaa | 完整分析 |
/ string | 搜索字符串 |
axt @ addr | 查找交叉引用 |
s addr | 跳转到地址 |
pd N | 反汇编 N 条指令 |
pdf | 反汇编整个函数 |
ps @ addr | 打印字符串 |
px N | 打印 hex |
Frida 工作流程
- 绕过代码签名保护
- 使用 frida-trace 自动生成 handler
- 修改 handler 记录函数输入输出
- 触发目标功能,观察调用
- 分析数据,还原算法
0x09 总结与思考
本次逆向经历可以总结为标准的 “四步走” 流程:
| 步骤 | 动作 | 工具 | 目的 |
|---|---|---|---|
| 1. 侦察 | 抓包分析 API | Charles | 确定攻击面 (ch2 字段) |
| 2. 定位 | 字符串搜索与交叉引用 | radare2 | 找到二进制中的验证逻辑开关 |
| 3. 截获 | Hook 加密函数 | Frida | 还原明文字符串的拼接格式 |
| 4. 攻克 | 算法编写与 Mock | Go/Python | 本地生成合法 Hash 完成破解 |