1.前言
这篇帖子还是关于数据采集的学习笔记,
我本就不多的分享欲都写进了笔记里面。
最近看到很喜欢的一句话:内心深处肯定会有觉得有趣的东西,如果不去做这个努力的话,自己觉得有趣的东西就会消失的。
所以要做自己喜欢的事情哦!!!
2.网址
aHR0cHM6Ly93d3cucWltYWkuY24vcmFuaw==
3.正文
在榜单处往下面划可以得到榜单app的数据
查看参数,只有一个analysis参数需要加密传参的
咦,看到后面的两个等于号,八成是base64编码,看能不能解码拿到其编码之前的数据。
解码之后是乱码,那么通过查看代码去逆向它这个参数是怎么生成的
在initiator面板看到了Promise.then
,并且每个数据包都携带了同一个参数。猜测这个xhr用了axios,其加密解密的代码都会运行在这个拦截器里面。
axios简介:
直接搜索拦截器interceptor看看能不能找到代码的关键位置,搜索到了一个唯一的js文件。可以证明这个xhr确确实实用了axios。
在js里面搜索interceptor,但是发现三个都不是正常的使用拦截器。
正常的拦截器的使用方式应该是xxx.interceptors.request.use()
正常的拦截器使用方法:
那便不去找xxx.interceptors.request.use()
,估计混淆了。因为394行到409行是axios的核心,无论加密的拦截器在哪里执行最后都会经过这个axios代码的地方的。分析这段代码从而找到加密的关键代码处。
拦截器代码分析:
t是一个数组,第三和第五行分别把请求拦截器和响应拦截器的两个函数传到了t里面。
for循环,只要t数组里面有值,便执行n = n.then(t.shift(), t.shift());
n是promise,便可以知道是发送请求,并且是把t数组里面的函数两两对应进行发送。
那么把断点下到407行,刷新取t的值看看。总共有6个函数,请求拦截器的函数是添加到t数组的前面的,便去前面的函数看看。
从t的第0个函数进去继续跟代码。
代码跟进去的时候停在了2572行,在2575行下断点看看是不是加密关键代码
在控制台打印了Kt,Ut,Ft,符合拦截器xxx.interceptors.request.use()
但是并不确定这段代码到底是不是我们需要的加密代码勒。
在2572和2595行下断点,在榜单页面鼠标往下滑。可以看到e就是我们需要的加密参数。那么加密函数肯定就在这段代码里面了。
关键代码分析:
代码中有两个逻辑或,逻辑或的执行原理就是当左边为假的时候才执行右边,左边为真的时候就不执行右边的代码了。
浏览器调试f和 F!=s
在控制台打印值,可以看到f为false,于是执行了F!=s,F是null,s是一个数字。所以F!=s为真,右边的代码不执行。
先替换z[w]
是个生成时间戳的函数
s是一个会变的数值,先写死。H是0
替换Zt
t是传下来的参数,t里面的params是传参。
void 0 === t["params"] && (t["params"] = {}
代码有个逻辑与,逻辑与的执行原理是左边为真,执行右边,左边为假,右边不执行。上面的代码的意思就是如果传下来的参数t里面的params没有值的话就让它等于一个空对象。
替换z,Z,i7,Zt,M,P,!B,N2,b
window['Object']['keys'](t['params'])['forEach'](function(n) {if (n == 'analysis') return false;t['params']['hasOwnProperty'](n) && a['push'](t['params'][n])})
这段代码的意思就是取出params里面的键遍历出来传给n,如果键是analysis就结束,是其余的键就执行后面的代码。
后面的代码有个逻辑与,逻辑与的执行原理是左边为真,执行右边,左边为假,右边不执行
把断点打到2585行,左边为真,执行右边的代码。a['push'](t['params'][n])
的意思是把值都存到a数组里面。
下一行
替换Ot,I1,__
a = a["sort"]()["join"](""),
代码的意思是将a里面的值按照字符编码的顺序进行排序然后拼接起来。
下一行是一个函数调用了a重新赋值给了a,需要找到对应的函数扣下来。
把断点下到2588行进去查看函数
把这段代码扣下来,分析这段代码做了什么。
替换混淆的字符
得到新的代码
`function v(t) { t = window["encodeURIComponent"](t)["replace"](/%([0-9A-F]{2})/g, function(n, t) { return o("0x" + t) }); try { return window["btoa"](t) } catch (n) { return window["Buffer"]["from"](t)["toString"]("base64") } }
有个o函数,扣下来。
看看o函数是做什么的。
o函数是将传进去的参数转为一个字符。
try...catch...就只是一个异常捕获函数,作用就是将参数base64编码之后返回。直接改写成node环境中能用的base64编码就行了。
下一行
替换混淆代码
a = (a += "@#" + t["url"]["replace"](t["baseURL"], "")) + ("@#" + r) + ("@#" + 3),
这一行明显就是拼接一些乱七八糟的东西。
主要就baseurl跟r。
r在上面代码就已经生成了
而那个baseurl就是我们传下来的url里面的pathname,传url的时候取一下pathname替换这段代码就好了。
下一行
替换混淆代码
得到下面代码
i[jt]是我们刚刚已经扣下来的v函数,直接替换
d是字符串"xyz517cda96abcd"
替换后的代码
-1 == t["url"]["indexOf"]("analysis") && (t["url"] += (-1 != t["url"]["indexOf"]("?") ? "&" : "?") + "analysis" + "=" + window["encodeURIComponent"](e)), t
i[qt]是h函数,进去扣下来替换。
替换混淆代码
替换后的代码
function h(n, t) { t = t || u(); for (var e = (n = n["split"](""))["length"], r = t["length"], a = "charCodeAt", i = 0; i < e; i++) n[i] = o(n[i][a](0) ^ t[(i + 10) % r][a](0)); return n["join"]("") }
分析了代码,我们要传的参数有个url跟params
运行代码报错了。
缺啥补啥
报了个window未定义
给window赋值个全局变量
最后一件事情,我们传进去的url是长的,而baseurl要的是短的。所以我们要在代码把长url变成短的url
运行代码,链接生成成功
用python执行,成功获取到数据
结尾:
有个总结,baseurl不能错,自己可以插赃看一下js代码生成的跟浏览器生成的那个a是不是一样的。因为这个baseurl错了改bug改了好久。
就因为一个us的大小写调试了好久好久。哭唧唧啊!!!具体解决方法就是自己传baseurl。