声明:本篇文章仅用于知识分享
实战网站: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 execjsfile = 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"))
运行结果如下。
跟页面回显的内容一致。
大功告成,结束收工。