某云音乐为例-反调试绕过,栈回溯,web算法逆向
字数 1282 2025-08-22 22:47:30
某云音乐爬虫逆向分析:反调试绕过与加密算法解析
前言
本文详细记录了某云音乐爬虫逆向分析的全过程,重点包括反调试绕过技术、加密参数解析和算法逆向。通过静态堆栈回溯、动态调试等技术手段,最终锁定目标加密函数的调用位置并实现算法还原。
工具准备
- 浏览器:Chrome/Edge/Firefox,用于分析网络行为
- Python环境:3.8+,用于实现爬虫脚本
- JavaScript环境:Node.js,用于运行测试JS代码
- 抓包工具:Fiddler/Wireshark/Burp Suite,监控网络请求
- 基础技能:JS/Python编程、加密算法基础(AES/RSA)
反调试技术汇总与绕过
1. 无限Debugger技术
- 直接插入debugger语句
- 使用eval创建debugger
- 通过Function动态创建debugger
- 重写JS原生功能(如constructor、eval、setInterval)
2. 阻止开启开发者工具
- 禁用右键菜单和F12快捷键
- 检测开发者工具开启状态:
- 通过加载时间间隔判断
- 根据浏览器宽高判断
- 使用disable-devtool等插件
3. 前端代码混淆技术
- 代码压缩:删除注释和空格
- 变量/函数名混淆
- 关键数据加密传输
- CDN分发资源隐藏真实地址
反调试绕过原理
通过中间代理工具(Charles/Fiddler)截获并替换前端JS/HTML代码,绕过反调试措施后使用浏览器原生调试工具进行分析。
目标分析流程
1. 目标URL定位
通过抓包分析确定关键API:
https://music.163.com/weapi/song/enhance/player/url/v1
2. 关键参数识别
请求中包含三个关键参数:
csrf_token:防CSRF令牌params:加密参数encSecKey:加密密钥
3. 加密位置定位方法
静态堆栈回溯
- 在开发者工具中查看调用栈
- 过滤无关调用(XMLHttpRequest.send等)
- 定位自定义函数调用链
动态调试
- 在XMLHttpRequest.send处设断点
- 触发目标API请求
- 筛选目标请求并分析调用栈
4. 加密函数分析
通过动态调试定位到核心加密函数:
var bVj1x = window.asrsea(
JSON.stringify(i6c),
bse8W(["流泪", "强"]),
bse8W(RR7K.md),
bse8W(["爱心", "女孩", "惊恐", "大笑"])
);
参数解析:
- 原始JSON数据
- RSA公钥指数"010001"
- RSA模数(长字符串)
- AES密钥"0CoJUm6Qyw8W8jud"
加密算法逆向
1. 加密函数结构
function d(d, e, f, g) {
var h = {}, i = a(16);
h.encText = b(d, g);
h.encText = b(h.encText, i);
h.encSecKey = c(i, e, f);
return h
}
2. 各函数功能
a() - 生成随机字符串
function a(a) {
var d, e, b = "abcdef...0123456789", c = "";
for(d = 0; a > d; d += 1)
e = Math.floor(Math.random() * b.length),
c += b.charAt(e);
return c
}
b() - AES加密
function b(a, b) {
var c = CryptoJS.enc.Utf8.parse(b),
d = CryptoJS.enc.Utf8.parse("0102030405060708"),
e = CryptoJS.enc.Utf8.parse(a),
f = CryptoJS.AES.encrypt(e, c, {
iv: d,
mode: CryptoJS.mode.CBC
});
return f.toString()
}
c() - RSA加密
function c(a, b, c) {
var d, e;
return setMaxDigits(131),
d = new RSAKeyPair(b, "", c),
e = encryptedString(d, a)
}
3. 加密流程
- 生成16位随机字符串i
- 用固定密钥g对原始数据d进行AES加密 → encText1
- 用随机字符串i对encText1再次AES加密 → 最终encText
- 用RSA公钥加密随机字符串i → encSecKey
Python实现
1. AES加密实现
def b(self, data, key):
iv = b'0102030405060708'
pad = 16 - len(data) % 16
data = data + chr(2) * pad
aes = AES.new(key.encode(), AES.MODE_CBC, iv)
tmp = aes.encrypt(data.encode())
return base64.b64encode(tmp).decode()
2. RSA加密实现
def c(self, a, b, c):
a = a[::-1]
result = pow(int(hexlify(a.encode()), 16),
int(b, 16),
int(c, 16))
return format(result, 'x').zfill(131)
3. 完整加密流程
def getData(self):
d = {
"ids": "[%s]" % self.id,
"level": "standard",
"encodeType": "aac",
"csrf_token": ""
}
d = json.dumps(d)
e = '010001'
f = '00e0b509f6259df8642dbc...0462db0a22b8e7'
g = '0CoJUm6Qyw8W8jud'
i = self.a() # 生成随机字符串
params = self.b(d, g) # 第一次AES加密
params = self.b(params, i) # 第二次AES加密
encSecKey = self.c(i, e, f) # RSA加密
return {
'params': params,
'encSecKey': encSecKey
}
总结
- 通过代理工具绕过反调试措施
- 使用堆栈回溯定位加密函数位置
- 分析出双重AES+RSA的混合加密方案
- 固定随机数生成实现算法还原
- Python实现完整加密流程获取数据
关键点:某云音乐加密算法多年未变,相同算法可用于多个接口。