在最近的一个博客中@孤心浪子,我发现了某音乐平台缓存文件的加密方式,并成功实现了解密,还开源了相关工具:kgm_decoder_py。本文将记录我在逆向分析过程中的思路、推导以及一些有趣的发现,希望能为其他音频逆向分析爱好者提供帮助。
🎯 目标:还原被加密的缓存音频
许多音乐平台在本地缓存时,会对音频文件做一定的加密处理,防止用户直接复制使用。这次的目标是还原这种被加密的缓存文件,提取出原始的 .mp3 音频数据。
🧩 发现一:缓存文件多了 1024 字节
通过对比下载好的 .mp3 文件与缓存文件,很容易发现:
缓存文件比原始 .mp3 文件大 1024 字节;
且多个缓存文件开头这 1024 字节完全一致。
由此可以推断出,这 1024 字节并不是音频内容,而是某种标识头或用于加密解密的参数。因此,只需从第 1024 字节(0x400)开始读取,即为音频数据本体。
🧪 发现二:加密方式是循环异或
为了确定加密方式,我对比了一段加密前后的数据,发现了一个规律。
示例:
原始数据(加密前):
0x55 0x55 0x55 0x55
=> 二进制:
01010101 01010101 01010101 01010101
加密后数据:
0xA9 0xE9 0xDA 0x52
=> 二进制:
10101001 11101001 11011010 01010010
从这里可以看出,加密后出现了类似 4 字节轮换加密 的特征。我们猜测使用了异或(XOR)操作。
根据异或的公式:
密文 = 明文 XOR 密钥
我们可以反推出密钥:
0x55 XOR 0xA9 = 0xFC
0x55 XOR 0xE9 = 0xBC
0x55 XOR 0xDA = 0x8F
0x55 XOR 0x52 = 0x07
即第一轮推测出的 XOR 密钥为:
0xFC 0xBC 0x8F 0x07
🧠 发现三:密钥并不固定,而是变化的!
这时我尝试用同样的方法解另一个加密段:
明文:
0x49 0x44 0x33 0x03
密文:
0x75 0xE8 0xDC 0x64
得到的新一组密钥为:
0x3C 0xAC 0xEF 0x67
这显然不同于之前的 0xFC 0xBC 0x8F 0x07,说明密钥不是固定的,而是变化的。不过,我注意到一件事:
两组密钥的低 4 位都是:0xC 0xC 0xF 0x7
这提示我们:密钥的低 4 位可能是固定的,而高 4 位是变化的!
🧪 进一步分析:根据 0x00 反推出高 4 位
利用异或的特性 0 XOR X = X,我们找了一组全 0 的明文:
明文: 0x00 0x00 0x00 0x00
密文: 0xAC 0xEC 0xDF 0x57
直接得到密钥为:
0xAC 0xEC 0xDF 0x57
进一步拆解为高低位:
高4位:0xA 0xE 0xD 0x5
低4位:0xC 0xC 0xF 0x7
这就完美印证了我们的猜想。
🔍 深度推理:高 4 位的计算方式
有趣的是,在某些情况下,加密前的数据本身的高 4 位等于低 4 位。此时我们发现:
加密后高 4 位 = 固定值(0xA, 0xE, 0xD, 0x5)
于是我尝试了一个新公式来验证这个规律:
Y = H xor L xor I
其中:
H = 明文高 4 位
L = 明文低 4 位
I = XOR 密钥高 4 位
Y = 加密后高 4 位
这个公式在多个样本中都得到了验证,说明密钥的高 4 位是由明文高/低位组合而来的,可能是防止被静态分析识破。
🧰 开源工具:kgm_decoder_py
基于以上分析,我开发了 Python 解密工具,支持将加密缓存恢复为原始音频格式(mp3/flac):
📦 GitHub 项目地址: 👉 GitHub - 1848431227/kgm_decoder_py
支持特性:
自动跳过前 1024 字节无用头部;
自动推导密钥并解密;
支持批量解密;
命令行和脚本两种方式调用。
🧠 总结
通过一系列逐字节比对、异或反推、样本验证,我们逐步揭示了加密算法的细节。这个过程再次印证了逆向分析的乐趣:从“看不懂”到“懂了”,再到“写出工具”,成就感满满。
🎉 如果你对逆向、加密分析感兴趣,欢迎关注我的开源项目或留言交流!
作者:1848431227 | GitHub:kgm_decoder_py