移动安全
使用 Frida 抓取 Android 加密参数与解密明文
文章 AI 总结
用更短的路径抓住本文重点
- 针对Android应用加密分析,通过Frida动态插桩Hook javax.crypto关键类,实时捕获密钥、IV及解密明文。
- 完整流程涵盖环境准备、ADB连接、frida-server部署及脚本注入四步,需Root权限与USB调试支持。
- 核心脚本通过拦截SecretKeySpec、IvParameterSpec和Cipher.doFinal,以十六进制输出密钥与解密数据。
- 实际应用中可扩展Hook Cipher.init记录操作模式,结合调用栈追踪定位业务加密入口,辅助协议还原。
- 操作需在授权测试环境进行,仅适用于Root设备,抓取结果可用于接口重放与安全评估。
一、环境准备#
开始之前,请确认以下环境已经准备就绪:
- 一台已经 Root 的 Android 设备或模拟器,本文使用的是 MuMu 模拟器和 Android 12。
- PC 端已经安装
adb,并配置好环境变量。 - PC 端已经安装 Python 3 和
frida-tools,可通过下面命令安装:
pip install frida-tools
- 已经下载与设备架构匹配的
frida-server,可在 Frida Releases 页面获取。
二、连接 ADB 设备#
先确保 ADB 服务正常,并且能够识别目标设备:
adb kill-server
adb start-server
adb devices
命令说明如下:
adb kill-server:关闭当前 ADB 服务进程,避免旧连接干扰。adb start-server:重新启动 ADB 服务。adb devices:列出所有已连接的设备。看到设备序列号,并且状态为device,就表示连接成功。
如果出现
unauthorized,需要在手机或模拟器中点击「允许 USB 调试」。如果没有设备,请检查连接、驱动和模拟器 ADB 设置。
三、部署并启动 frida-server#
将 frida-server 推送到设备的 /data/local/tmp/ 目录,赋予执行权限,然后以 root 权限在后台运行:
adb push frida-server /data/local/tmp/
adb shell chmod 755 /data/local/tmp/frida-server
adb shell "su -c /data/local/tmp/frida-server &"
如果命令执行后没有明显报错,通常说明 frida-server 已经启动。后续可以通过 frida-ps -U 检查 Frida 是否能够正常连接设备。
四、注入 Hook 脚本#
使用 -U 指定 USB 设备,使用 -F 附加到当前前台应用,使用 -l 加载 Hook 脚本:
frida.exe -U -F -l tt.js
参数说明:
-U:连接 USB 设备或模拟器。-F:附加到当前前台应用。-l tt.js:加载本地 Hook 脚本。
如果需要指定包名启动应用,可以使用
-f <package>替代-F,并加上--no-pause让应用自动继续运行。
五、Hook 脚本解析#
完整脚本如下。核心思路是 Hook javax.crypto 相关关键类,拦截密钥创建、IV 构造,以及 Cipher.doFinal 的输出。
"use strict";
setInterval(function() {}, 1000);
function toHex(bytes) {
if (!bytes) return "(null)";
var hex = [];
for (var i = 0; i < bytes.length; i++) {
var b = bytes[i] & 0xFF;
hex.push(('0' + b.toString(16)).slice(-2));
}
return hex.join(' ');
}
Java.perform(function() {
console.log("[*] Hook 已激活...");
// 抓密钥
var SecretKeySpec = Java.use("javax.crypto.spec.SecretKeySpec");
SecretKeySpec.$init.overload('[B', 'java.lang.String').implementation = function(key, algo) {
console.log("\n[密钥] 算法: " + algo + " Hex: " + toHex(key));
return this.$init(key, algo);
};
// 抓 IV
var IvParameterSpec = Java.use("javax.crypto.spec.IvParameterSpec");
IvParameterSpec.$init.overload('[B').implementation = function(iv) {
console.log("[IV] Hex: " + toHex(iv));
return this.$init(iv);
};
// 抓解密结果,不再调用 getOpMode,避免异常
var Cipher = Java.use("javax.crypto.Cipher");
Cipher.doFinal.overload('[B').implementation = function(input) {
var result = this.doFinal(input); // 直接调用原始方法,安全
try {
// 只打印长度较大的结果,大概率是解密后的业务数据
if (result.length > 64) {
console.log("\n[解密输出] 长度: " + result.length);
console.log("[解密输出] Hex: " + toHex(result));
try {
var str = Java.use("java.lang.String").$new(result, "UTF-8");
console.log("[解密输出] 明文: " + str);
} catch (e) {
console.log("[解密输出] 非 UTF-8 文本");
}
}
} catch (e) {
console.log("[!] 打印异常: " + e);
}
return result;
};
});
5.1 工具函数 toHex#
toHex 用来把字节数组格式化为以空格分隔的十六进制字符串,方便肉眼识别密钥、IV 等二进制数据。
关键点如下:
b & 0xFF:避免 Java 字节有符号导致的负数问题。('0' + b.toString(16)).slice(-2):保证每个字节都是两位十六进制。
5.2 抓取密钥:SecretKeySpec.$init#
SecretKeySpec 是 Java 标准库中构造对称密钥最常用的类。它的构造函数 (byte[], String) 中,两个参数分别是密钥字节和算法名,例如 AES、DES、HmacSHA256 等。
这里通过下面方式精准匹配重载:
SecretKeySpec.$init.overload('[B', 'java.lang.String')
在调用前打印算法和 Hex 格式的密钥,然后再执行:
return this.$init(key, algo);
这样既能拿到关键参数,又不会破坏原有业务逻辑。
5.3 抓取 IV:IvParameterSpec.$init#
对于 CBC、CFB、OFB、GCM 等加密模式,IV 或 Nonce 通常会通过 IvParameterSpec(byte[]) 传入。
因此,Hook 它的构造函数,就可以拿到明文 IV:
IvParameterSpec.$init.overload('[B').implementation = function(iv) {
console.log("[IV] Hex: " + toHex(iv));
return this.$init(iv);
};
5.4 抓取解密输出:Cipher.doFinal([B)#
Cipher.doFinal 是加解密流程的最终执行点。Hook 它可以同时拦截加密结果和解密结果。
脚本中的处理逻辑如下:
- 先调用原始方法拿到结果,再打印,保证原有流程不被破坏。
- 使用长度过滤,只打印
length > 64的输出。经验上,这类长度的结果更可能是解密后的业务数据,例如 JSON、XML 等;短输出更多可能是哈希、签名或其他噪声数据。 - 尝试使用 UTF-8 解码成明文字符串。如果失败,则只保留 Hex 输出。
六、常见扩展思路#
根据实际分析需求,可以在这份脚本基础上继续扩展:
- Hook
Cipher.init:获取opmode、Key、IV,把每次调用的上下文完整串起来。其中opmode = 1通常表示加密,opmode = 2通常表示解密。 - 打印调用栈:在关键 Hook 点中通过
Log.getStackTraceString(Throwable.$new())反查业务调用位置。 - 区分加密和解密输出:配合
Cipher.init的模式记录,分别标记[加密输出]和[解密输出]。 - Hook
MessageDigest和Mac:抓取 MD5、SHA、HMAC 的输入输出,用来定位签名算法。 - 配合 Objection 或 Wallbreaker:做动态类查看和反射分析,辅助定位加密入口。
七、关于拉流地址的说明#
拉流地址通常可以按照下面思路拼接:
直播基础地址(固定部分) + Hook 得到的拉流标识(stream id / key) = 完整拉流地址
分析时可以重点关注以下内容:
- 基础地址可以通过抓包工具定位,例如 Charles、Fiddler、mitmproxy 等。
- 常见直播协议包括
rtmp://、HTTP-FLV、HLS,也就是m3u8等,需要按目标平台的实际格式拼接。 - 部分平台的 URL 还会携带签名、时间戳、token 等参数,需要配合其他 Hook 点或接口分析补全。
八、小结#
整个流程可以概括为四步:
连接设备 → 部署 frida-server → 注入脚本 → 读取 Hook 日志
通过这套通用 Hook 脚本,基本可以覆盖大部分基于 javax.crypto 的 Android 应用加密实现,快速拿到密钥、IV 与解密明文。
这些信息可以帮助我们进一步进行接口重放、协议还原和安全评估。实际使用时,建议只在授权测试环境中操作,避免对第三方业务造成影响。
使用 Frida 抓取 Android 加密参数与解密明文
https://maxs.eu.org/posts/348f48da2d50.html- 本文作者
- 马小酷
- 发布于
- 更新于
- 版权协议
- CC BY-NC-SA 4.0
转载或引用本文时请遵守许可协议,注明出处、不得用于商业用途!