某麦数据参数逆向分析
本帖最后由 wangguang 于 2023-5-10 19:22 编辑# 1.前言
这篇帖子还是关于数据采集的学习笔记,
我本就不多的分享欲都写进了笔记里面。
最近看到很喜欢的一句话:内心深处肯定会有觉得有趣的东西,如果不去做这个努力的话,自己觉得有趣的东西就会消失的。
所以要做自己喜欢的事情哦!!!
# 2.网址
aHR0cHM6Ly93d3cucWltYWkuY24vcmFuaw==
# 3.正文
在榜单处往下面划可以得到榜单app的数据
![](https://img1.imgtp.com/2023/05/10/sb7zufXD.png)
查看参数,只有一个**analysis**参数需要加密传参的
咦,看到后面的两个等于号,八成是base64编码,看能不能解码拿到其编码之前的数据。
![](https://img1.imgtp.com/2023/05/10/d7HXIXzJ.png)
解码之后是乱码,那么通过查看代码去逆向它这个参数是怎么生成的
![](https://img1.imgtp.com/2023/05/10/VKLWWTh5.png)
在initiator面板看到了`Promise.then`,并且每个数据包都携带了同一个参数。猜测这个xhr用了axios,其加密解密的代码都会运行在这个拦截器里面。
![](https://img1.imgtp.com/2023/05/10/5o1yCN2N.png)
## axios简介:
![](https://img1.imgtp.com/2023/05/10/XwAefQM1.png)
直接搜索拦截器interceptor看看能不能找到代码的关键位置,搜索到了一个唯一的js文件。可以证明这个xhr确确实实用了axios。
![](https://img1.imgtp.com/2023/05/10/LcoK9nZT.png)
在js里面搜索interceptor,但是发现三个都不是正常的使用拦截器。
正常的拦截器的使用方式应该是`xxx.interceptors.request.use()`
![](https://img1.imgtp.com/2023/05/10/9iyW8B4l.png)
## 正常的拦截器使用方法:
![](https://img1.imgtp.com/2023/05/10/upVSSjLA.png)
那便不去找`xxx.interceptors.request.use()`,估计混淆了。因为394行到409行是axios的核心,无论加密的拦截器在哪里执行最后都会经过这个axios代码的地方的。分析这段代码从而找到加密的关键代码处。
## 拦截器代码分析:
t是一个数组,第三和第五行分别把请求拦截器和响应拦截器的两个函数传到了t里面。
for循环,只要t数组里面有值,便执行`n = n.then(t.shift(), t.shift());`
![](https://img1.imgtp.com/2023/05/10/Vw3w6sGt.png)
n是promise,便可以知道是发送请求,并且是把t数组里面的函数两两对应进行发送。
![](https://img1.imgtp.com/2023/05/10/dvj2Eurk.png)
那么把断点下到407行,刷新取t的值看看。总共有6个函数,请求拦截器的函数是添加到t数组的前面的,便去前面的函数看看。
![](https://img1.imgtp.com/2023/05/10/SVgLA7bP.png)
从t的第0个函数进去继续跟代码。
![](https://img1.imgtp.com/2023/05/10/x2a9Igy8.png)
代码跟进去的时候停在了2572行,在2575行下断点看看是不是加密关键代码
![](https://img1.imgtp.com/2023/05/10/aLqg3Mc4.png)
在控制台打印了Kt,Ut,Ft,符合拦截器`xxx.interceptors.request.use()`
但是并不确定这段代码到底是不是我们需要的加密代码勒。
![](https://img1.imgtp.com/2023/05/10/JQUJCTSi.png)
在2572和2595行下断点,在榜单页面鼠标往下滑。可以看到e就是我们需要的加密参数。那么加密函数肯定就在这段代码里面了。
![](https://img1.imgtp.com/2023/05/10/QL1opCJU.png)
## 关键代码分析:
代码中有两个逻辑或,逻辑或的执行原理就是当左边为假的时候才执行右边,左边为真的时候就不执行右边的代码了。
![](https://img1.imgtp.com/2023/05/10/uZcBys2h.png)
浏览器调试f和 F!=s
![](https://img1.imgtp.com/2023/05/10/MefeJtPE.png)
在控制台打印值,可以看到f为false,于是执行了F!=s,F是null,s是一个数字。所以F!=s为真,右边的代码不执行。
![](https://img1.imgtp.com/2023/05/10/FaFgSCbP.png)
先替换z
![](https://img1.imgtp.com/2023/05/10/31dvBCDz.png)
是个生成时间戳的函数
s是一个会变的数值,先写死。H是0
![](https://img1.imgtp.com/2023/05/10/wz08KZvd.png)
![](https://img1.imgtp.com/2023/05/10/jSsMezIX.png)
替换Zt
![](https://img1.imgtp.com/2023/05/10/PcSDk85X.png)
t是传下来的参数,t里面的params是传参。
![](https://img1.imgtp.com/2023/05/10/gpjwImtB.png)
`void 0 === t["params"] && (t["params"] = {}`
代码有个逻辑与,逻辑与的执行原理是左边为真,执行右边,左边为假,右边不执行。上面的代码的意思就是如果传下来的参数t里面的params没有值的话就让它等于一个空对象。
替换z,Z,i7,Zt,M,P,!B,N2,b
![](https://img1.imgtp.com/2023/05/10/04luZmnN.png)
![](https://img1.imgtp.com/2023/05/10/luIbSriQ.png)
`window['Object']['keys'](t['params'])['forEach'](function(n) {if (n == 'analysis') return false;t['params']['hasOwnProperty'](n) && a['push'](t['params'])})`
这段代码的意思就是取出params里面的键遍历出来传给n,如果键是analysis就结束,是其余的键就执行后面的代码。
后面的代码有个逻辑与,逻辑与的执行原理是左边为真,执行右边,左边为假,右边不执行
把断点打到2585行,左边为真,执行右边的代码。`a['push'](t['params'])`的意思是把值都存到a数组里面。
![](https://img1.imgtp.com/2023/05/10/aLqg3Mc4.png)
下一行
![](https://img1.imgtp.com/2023/05/10/XtGXd3MO.png)
替换Ot,I1,__
![](https://img1.imgtp.com/2023/05/10/9cqXX3c7.png)
`a = a["sort"]()["join"](""),`
代码的意思是将a里面的值按照字符编码的顺序进行排序然后拼接起来。
下一行是一个函数调用了a重新赋值给了a,需要找到对应的函数扣下来。
![](https://img1.imgtp.com/2023/05/10/tm7BNgwV.png)
把断点下到2588行进去查看函数
![](https://img1.imgtp.com/2023/05/10/0oKRhn6y.png)
把这段代码扣下来,分析这段代码做了什么。
![](https://img1.imgtp.com/2023/05/10/KNJtRwRh.png)
替换混淆的字符
![](https://img1.imgtp.com/2023/05/10/86DW4jah.png)
得到新的代码
``function v(t) {
t = window["encodeURIComponent"](t)["replace"](/%({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函数是做什么的。
![](https://img1.imgtp.com/2023/05/10/XdiYqlEe.png)
o函数是将传进去的参数转为一个字符。
![](https://img1.imgtp.com/2023/05/10/XxGlxXo1.png)
try...catch...就只是一个异常捕获函数,作用就是将参数base64编码之后返回。直接改写成node环境中能用的base64编码就行了。
下一行
![](https://img1.imgtp.com/2023/05/10/3yUrGqup.png)
替换混淆代码
`a = (a += "@#" + t["url"]["replace"](t["baseURL"], "")) + ("@#" + r) + ("@#" + 3),`
![](https://img1.imgtp.com/2023/05/10/RCPa9aSV.png)
这一行明显就是拼接一些乱七八糟的东西。
主要就baseurl跟r。
![](https://img1.imgtp.com/2023/05/10/ZZci4aju.png)
r在上面代码就已经生成了
而那个baseurl就是我们传下来的url里面的**pathname**,传url的时候取一下pathname替换这段代码就好了。
![](https://img1.imgtp.com/2023/05/10/v7cEXDnS.png)
下一行
![](https://img1.imgtp.com/2023/05/10/82q7G9EI.png)
替换混淆代码
![](https://img1.imgtp.com/2023/05/10/qrcm1My5.png)
得到下面代码
i是我们刚刚已经扣下来的v函数,直接替换
d是字符串**"xyz517cda96abcd"**
替换后的代码
`-1 == t["url"]["indexOf"]("analysis") && (t["url"] += (-1 != t["url"]["indexOf"]("?") ? "&" : "?") + "analysis" + "=" + window["encodeURIComponent"](e)), t`
i是h函数,进去扣下来替换。
![](https://img1.imgtp.com/2023/05/10/8xYuavRG.png)
![](https://img1.imgtp.com/2023/05/10/gRzEaL8I.png)
替换混淆代码
![](https://img1.imgtp.com/2023/05/10/DpwyjTiE.png)
替换后的代码
`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 = o(n(0) ^ t[(i + 10) % r](0));
return n["join"]("")
}`
分析了代码,我们要传的参数有个url跟params
![](https://img1.imgtp.com/2023/05/10/t7abG1Qs.png)
运行代码报错了。
![](https://img1.imgtp.com/2023/05/10/nWGDE666.png)
![](https://img1.imgtp.com/2023/05/10/nzwfrr5X.png)
缺啥补啥
![](https://img1.imgtp.com/2023/05/10/20KGmJUN.png)
报了个window未定义
![](https://img1.imgtp.com/2023/05/10/OZtUSMd7.png)
给window赋值个全局变量
最后一件事情,我们传进去的url是长的,而baseurl要的是短的。所以我们要在代码把长url变成短的url
![](https://img1.imgtp.com/2023/05/10/euvkHEsd.png)
运行代码,链接生成成功
![](https://img1.imgtp.com/2023/05/10/EaivOpax.png)
用python执行,成功获取到数据
![](https://img1.imgtp.com/2023/05/10/eEpOyDBP.png)
# 结尾:
有个总结,baseurl不能错,自己可以插赃看一下js代码生成的跟浏览器生成的那个a是不是一样的。因为这个baseurl错了改bug改了好久。
![](https://img1.imgtp.com/2023/05/10/602ZCqUT.png)
就因为一个us的大小写调试了好久好久。哭唧唧啊!!!具体解决方法就是自己传baseurl。 wangguang 发表于 2023-5-10 17:52
emmmm,咦。
为什么我的上传图床的图片显示不出来@涛之雨
有防盗链吧,f12看下链接都403了。 Hmily 发表于 2023-5-10 18:21
有防盗链吧,f12看下链接都403了。
好的老大,我已经更换了图床链接了 emmmm,咦。
为什么我的上传图床的图片显示不出来@涛之雨 感谢分享
感谢分享 感谢分享 控制台打印用的淋漓尽致,我每次弄的时候总是差最后一点的时候没耐心了。。 学习了,感谢大佬分享思路