某App中关键请求参数Java层面逆向分析
字数 1563 2025-10-01 14:05:45
Android应用逆向分析:关键请求参数生成机制解析
概述
本文档基于对某Android应用的Java层逆向分析,详细解析其关键请求参数(x-bili-trace-id、Authorization和key)的生成逻辑与算法实现。适用于移动安全研究人员、逆向工程师及对API安全机制感兴趣的技术人员。
一、x-bili-trace-id参数生成分析
1. 定位与代码追踪
- 在JADX中搜索
x-bili-trace-id可定位到相关代码逻辑。 - 核心生成逻辑位于
j()函数,最终跳转到h()函数,与RpcExtra类关联。
2. 生成逻辑详解
步骤1:生成随机字节数组
- 定义一个16位的字节数组(
byte[16])。 - 使用
Random类填充随机数(熵源)。
步骤2:处理时间戳
long currentTimeMillis = System.currentTimeMillis() / 1000; // 毫秒转秒
int timestamp = (int) currentTimeMillis;
步骤3:字节数组后4位填充时间戳
- 从数组最后一个元素(索引15)向前遍历至索引12(共4字节)。
- 每次循环将
timestamp右移8位,取低8位写入数组:for (int i = 15; i >= 12; i--) { array[i] = (byte) (timestamp & 0xFF); timestamp >>= 8; }
步骤4:转换为十六进制字符串
- 调用
XTraceKt.a()方法(Kotlin实现),将字节数组转换为16进制字符串。 - 示例:
[0x1A, 0x3F]→"1A3F"。
步骤5:拼接最终格式
- 取完整字符串的前半部分(
substring(0, length/2))。 - 拼接格式:
{原字符串}:{前半部分}:0:0。
二、Authorization参数生成分析
1. 定位与确认
- 搜索
Authorization定位到生成方法,通过Frida Hook确认其有效性。
2. 核心方法调用链
d() → c() → apiSign() → getMapParamsSign()
3. 签名算法关键点
getSignHash()方法调用gs(),后者通过反射初始化KeyInfo类。gs()为native方法,实际逻辑在SO库中(本文暂不展开)。
三、key参数生成分析
1. 代码位置
- 位于
com.kugou.android.app.common.comment.b.i的b()方法。
2. 参数组成
调用形式:br.a(param1, param2, param3, param4)
- param1: 定值(通过Frida Hook确认)。
- param2: 定值(同上)。
- param3: 由
F()函数生成,结果为定值。 - param4: 时间戳(毫秒级,需转换为秒级)。
3. 最终处理:MD5与十六进制转换
br.a()对拼接后的参数进行MD5哈希。- 将MD5结果(字节数组)传入
c()方法处理。 c()遍历数组,对每个字节调用a()方法转换为十六进制字符串:String a(byte b) { char[] hexChars = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'}; return String.valueOf(hexChars[(b >> 4) & 0xF]) + hexChars[b & 0xF]; }
关键工具与技术
- JADX: 用于反编译APK,定位关键代码。
- Frida:
- Hook关键函数,动态验证参数值。
- 打印中间变量,确认定值或动态值。
- 代码分析: 结合静态阅读与动态调试,厘清调用链。
总结与改进方向
已解析内容
x-bili-trace-id: 基于时间戳+随机数的可逆生成机制。key: 多定值+时间戳的MD5哈希机制。Authorization: 依赖Native层签名,Java层为反射调用。
未解析内容
Authorization的Native层逻辑(gs()方法)。- 部分定值的来源(如
key的param1/param2)。
后续建议
- 对SO库进行逆向分析,完整还原
Authorization生成逻辑。 - 使用Frida批量Hook相关函数,自动化参数生成。
- 结合抓包工具(如Charles)验证参数有效性。
附录:代码片段示例
x-bili-trace-id生成伪代码
byte[] array = new byte[16];
new Random().nextBytes(array); // 填充随机数
long timestamp = System.currentTimeMillis() / 1000;
for (int i = 15; i >= 12; i--) {
array[i] = (byte) (timestamp & 0xFF);
timestamp >>= 8;
}
String hex = XTraceKt.a(array); // 字节数组转Hex
String result = hex + ":" + hex.substring(0, hex.length()/2) + ":0:0";
key的MD5处理伪代码
String input = param1 + param2 + param3 + param4;
byte[] md5Bytes = MD5(input);
StringBuilder sb = new StringBuilder();
for (byte b : md5Bytes) {
sb.append(a(b)); // 单字节转Hex
}
return sb.toString();
注意:本文仅用于技术研究,请勿用于非法用途。