js逆向实战之酷我音乐请求参数reqId加密逻辑
声明:本篇文章仅用于知识分享
实战网站:https://www.kuwo.cn/search/list?key=可以不是你
加密逻辑分析
-
访问界面,根据数据包的回显内容判断哪个是我们需要的。
-
找到相应的数据包,看下请求参数。
发现reqId
参数是一串随机字符串,所以就需要知道该参数的生成过程。 -
全局搜索
reqId
,总共有9个结果。
下面5个是固定值不需要看,上面四个无法判断,所以都得打上断点。 -
刷新界面,看触发哪一个。
执行到对应处的时候,n
已经生成了特定格式的字符串,说明加密逻辑在上面。 -
往上找
n
的生成过程
关键语句:n = l()()
-
控制台输出
l()
的结果,找到函数的定位处。
-
在
n=l()()
处打上断点,在函数第一行打上断点,重新刷新界面让程序运行到这里。
-
记住传进来的三个参数都为
undefined
,让程序一步一步往下执行。前面四行的变量值都为固定值,如下。
继续往下进入if判断,m
是个数组,其由l()
生成。
由于我们不能判断其是个固定值还是随机值,可以在控制台多输出几遍。
每次结果都不一样,说明是个随机值,等下在抠代码的时候,我们可以给m
变量随便赋值即可。再往下,会通过运算得到f
和v
的值。
接下来分析var y = void 0 !== e.msecs ? e.msecs : (new Date).getTime()
,是个三目运算,void 0 !== e.msecs
的值为false,所以简化一下就是var y = (new Date).getTime()
。
w = void 0 !== e.nsecs ? e.nsecs : h + 1
分析逻辑与上面一致,void 0 !== e.nsecs
的值为false,所以简化一下就是var w = h + 1
。
下面的代码就全是一系列的运算操作了,就暂时先不分析了。
直接运行到return t || c(b)
处,分别看下t
和c(b)
的输出。
发现c(b)
才是我们需要的输出,看下b
是什么。
就是一个数组,说明加密逻辑就是c()
函数了。控制台输出c
,找到它的定位处。
打断点进来。
e
是我们传进来的数组,t
的值为undefined。继续往下执行,看下i
和r
的值是什么。
i
是0,r
是n
赋值给它的,找n
的生成过程,往上翻几眼就能找到。
通过循环得到,直接复制代码即可。至此,大概的加密逻辑都分析到位了。 -
抠代码的时候先把能简化的简化,如果碰到有变量未定义,在该行代码的上下行找找就能找到。
好像就下面两个变量。
完整的js如下。
function generate(e, t, n) {
var i = t && n || 0
, r, o, h=0,d=0
, b = t || []
, f = undefined
, v = undefined;
if (null == f || null == v) {
var m = {
"0": 43,
"1": 64,
"2": 160,
"3": 14,
"4": 221,
"5": 55,
"6": 249,
"7": 97,
"8": 86,
"9": 170,
"10": 120,
"11": 218,
"12": 66,
"13": 188,
"14": 238,
"15": 102
};
null == f && (f = r = [1 | m[0], m[1], m[2], m[3], m[4], m[5]]),
null == v && (v = o = 16383 & (m[6] << 8 | m[7]))
}
var y = (new Date).getTime()
, w = h + 1
, dt = y - d + (w - h) / 1e4;
if (dt < 0 && void 0 === undefined && (v = v + 1 & 16383),
(dt < 0 || y > d) && void 0 === undefined && (w = 0),
w >= 1e4)
throw new Error("uuid.v1(): Can't create more than 10M uuids/sec");
d = y,
h = w,
o = v;
var A = (1e4 * (268435455 & (y += 122192928e5)) + w) % 4294967296;
b[i++] = A >>> 24 & 255,
b[i++] = A >>> 16 & 255,
b[i++] = A >>> 8 & 255,
b[i++] = 255 & A;
var x = y / 4294967296 * 1e4 & 268435455;
b[i++] = x >>> 8 & 255,
b[i++] = 255 & x,
b[i++] = x >>> 24 & 15 | 16,
b[i++] = x >>> 16 & 255,
b[i++] = v >>> 8 | 128,
b[i++] = 255 & v;
for (var T = 0; T < 6; ++T)
b[i + T] = f[T];
return t || c(b)
}
function c(e, t) {
for (var n = [], i = 0; i < 256; ++i)
n[i] = (i + 256).toString(16).substr(1);
var i = t || 0
, r = n;
return [r[e[i++]], r[e[i++]], r[e[i++]], r[e[i++]], "-", r[e[i++]], r[e[i++]], "-", r[e[i++]], r[e[i++]], "-", r[e[i++]], r[e[i++]], "-", r[e[i++]], r[e[i++]], r[e[i++]], r[e[i++]], r[e[i++]], r[e[i++]]].join("")
}
// console.log(generate());
运行结果如下,符合我们的预期,每次运行的结果都不一样。
- 最后编写python代码获取数据即可。
import requests
import execjs
file = open("test.js", mode="r")
exec_code = file.read()
exec_js = execjs.compile(exec_code)
reqId = exec_js.call("generate")
key = input("请输入你要查询的音乐:")
url = "https://www.kuwo.cn/openapi/v1/www/search/searchKey?key={}" \
"&httpsStatus=1&reqId={}&plat=web_www&from=".format(key, reqId)
headers = {"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) "
"Chrome/129.0.0.0 Safari/537.36"}
resp = requests.get(url, headers=headers)
resp.encoding = "utf-8"
print(resp.content.decode("utf-8"))
运行结果如下。
跟页面回显的内容一致。
大功告成,结束收工。