【JS逆向百例】酷某音乐 wasm 逆向
字数 1085 2025-08-20 18:18:40
酷某音乐WASM逆向分析教学文档
1. 逆向目标分析
目标网站:酷某音乐(aHR0cHM6Ly93d3cua3Vnb3UuY29tLw==)
主要逆向参数:
miduuidsignatureparamspksidedt
2. 抓包分析流程
- 进入首页,输入手机号点击发送验证码
- 关键接口分析:
send_mobile:首次请求后在响应头返回ssa-codeget_verfy_info:携带ssa-code参数,返回全局唯一的sessionidv4/verify_user_info:易盾点选/滑块验证码验证接口- 再次调用
send_mobile,status:1表示发送成功
3. 参数逆向详解
3.1 mid和uuid参数
生成逻辑:
- 从cookie中获取
kg_mid - 若不存在则生成浏览器指纹信息并通过md5算法生成
Hook方法:
(function() {
'use strict';
var cookieTemp = '';
Object.defineProperty(document, 'cookie', {
set: function(val) {
if (val.indexOf('kg_mid') != -1) {
debugger;
}
console.log('Hook捕获到cookie设置->', val);
cookieTemp = val;
return val;
},
get: function() {
return cookieTemp;
},
});
})();
uuid生成算法:
Guid: function() {
function S4() {
return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);
}
return (S4() + S4() + "-" + S4() + "-" + S4() + "-" + S4() + "-" + S4() + S4() + S4());
}
3.2 signature参数
生成逻辑:
- 将url中的
parm参数与data参数拼接 - 调用
K.unshift(y)和K.push(y)在数组开头和结尾插入固定字符串 - 通过
join拼接成字符串 - 进行md5加密生成
signature
3.3 params和pk参数
AES加密流程:
function AES_Encrypt(data) {
// 将输入数据转换为JSON字符串
const jsonString = JSON.stringify(data);
// 生成随机密钥(Key)
const generateRandomKey = (length) => {
const chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
let randomKey = '';
for (let i = 0; i < length; i++) {
randomKey += chars.charAt(Math.floor(Math.random() * chars.length));
}
return randomKey;
};
// 如果未提供密钥,则生成一个16字符的随机密钥
key = generateRandomKey(16);
// 使用MD5对密钥进行编码,并截取前32字符作为实际密钥
const md5Key = md5_encode(key).substring(0, 32);
// 如果未提供向量(IV),则使用密钥的最后16字符
iv = md5Key.substring(md5Key.length - 16);
// 将密钥和向量转换为CryptoJS的Utf8对象
const cryptoKey = CryptoJS.enc.Utf8.parse(md5Key);
const cryptoIv = CryptoJS.enc.Utf8.parse(iv);
// 使用AES算法进行加密
const encrypted = CryptoJS.AES.encrypt(jsonString, cryptoKey, {
iv: cryptoIv,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
});
// 将加密结果转换为Hex字符串
const encryptedHexStr = CryptoJS.enc.Hex.stringify(CryptoJS.enc.Base64.parse(encrypted.toString()));
return {
key: key,
encryptedStr: encryptedHexStr
};
}
pk参数RSA加密:
const RSA = require('./rsa'); // 引入保存的rsa.js文件
function rsa_encode(word){
word = JSON.stringify(word)
// 使用的公钥
const publicKey = "B1B1EC76A1BBDBF0D18E8CD9A87E53FA3881E2F004C67C9DDA2CA677DBEFA3D61DF8463FE12D84FF4B4699E02C9D41CAB917F5A8FB9E35580C4BDF97763A0420A476295D763EE10174E6F9EBF7DF8A77BA5B20CDA4EE705DEF5BBA3C88567B9656E52C9CD5CD95CA735FF2D25F762B133273EEEB7B4F3EA8B6DA29040F3B67CD";
// 使用encrypt函数进行加密
const encryptedMessage = RSA.encrypt(word);
return encryptedMessage
}
3.4 sid和edt参数
生成逻辑:
var t = new wasm_bindgen.EData;
e.sid = t.get_sid(),
e.edt = c
WASM环境检测点:
- 原型链检测
- DOM层相关检测
- WebGL原型链检测
- WebGL相关API操作检测
环境补全要点:
HTMLCanvasElement = function HTMLCanvasElement (){ }
canvas.__proto__=HTMLCanvasElement.prototype
function WebGLRenderingContext() {}
// 为WebGLRenderingContext添加Symbol.hasInstance
Object.defineProperty(WebGLRenderingContext, Symbol.hasInstance, {
value: function (obj) {
return obj && typeof obj === 'object' &&
obj.drawingBufferWidth !== undefined &&
obj.drawingBufferHeight !== undefined;
}
});
异步调用解决方案:
setTimeout(function(){
var t = new wasm_bindgen.EData;
console.log(t.get_sid())
console.log(t.get_edt())
}, 1000);
Node.js接口实现:
const express = require('express');
const app = express();
const port = 3000;
app.get('/getValues', async (req, res) => {
setTimeout(function(){
try {
var t = new wasm_bindgen.EData();
const get_sid = t.get_sid();
const get_edt = t.get_edt();
res.json({ get_sid, get_edt });
} catch (error) {
res.status(500).json({ error: error.message });
}
}, 1000);
});
app.listen(port, () => {
console.log(`Server is running on http://localhost:${port}`);
});
4. 关键函数解析
_instanceof函数分析
function _instanceof(left, right) {
if (right != null && typeof Symbol !== "undefined" && right[Symbol.hasInstance]) {
return !!right[Symbol.hasInstance](left);
} else {
return left instanceof right;
}
}
功能说明:
- 使用
Symbol.hasInstance进行类型检查 - 如果
right有Symbol.hasInstance方法,则调用并将left传递给right[Symbol.hasInstance] - 使用
!!将结果强制转为布尔值 - 如果不满足条件,则使用JavaScript内置的
instanceof操作符
5. 实现流程总结
- 获取
mid和uuid参数 - 生成
signature参数 - 生成
params和pk参数 - 处理WASM环境并获取
sid和edt参数 - 完成验证码验证流程
- 最终调用
send_mobile接口发送验证码
6. 注意事项
- WASM加载是异步过程,需要正确处理异步调用
- 环境检测严格,需要完整补全浏览器环境
- 原型链继承关系需要正确处理
- 建议使用代理框架处理环境检测问题
- 关键检测点可以通过插桩打印或直接修改返回值进行调试