文章目录
- 1. 写在前面
- 2. 接口分析
- 3. 分析与扣代码
【🏠作者主页】:吴秋霖
【💼作者介绍】:擅长爬虫与JS加密逆向分析!Python领域优质创作者、CSDN博客专家、阿里云博客专家、华为云享专家。一路走来长期坚守并致力于Python与爬虫领域研究与开发工作!
【🌟作者推荐】:对爬虫领域以及JS逆向分析感兴趣的朋友可以关注《爬虫JS逆向实战》《深耕爬虫领域》
未来作者会持续更新所用到、学到、看到的技术知识!包括但不限于:各类验证码突防、爬虫APP与JS逆向分析、RPA自动化、分布式爬虫、Python领域等相关文章
作者声明:文章仅供学习交流与参考!严禁用于任何商业与非法用途!否则由此产生的一切后果均与作者无关!如有侵权,请联系作者本人进行删除!
1. 写在前面
上次周六的时候熬夜分析还原了一下商家后台的Anti-Content,那个参数是0aq开头的,本次的话应粉丝要求对批发网站进行了同样的参数分析,与其不同的是参数开头为0ar
分析目标:
aHR0cHM6Ly9waWZhLnBpbmR1b2R1by5jb20v
老规矩,开局先放一张结果图,后续内容全靠编!!!
另外,对之前商家端Anti-Content参数分析感谢的,请看这篇文章:最新商家后台Anti-Content参数逆向分析与纯算法还原
2. 接口分析
主要通过商品搜索入口展开分析,然后到商品详情。首先,还是老规矩打开网站随便找个商品搜索一下,不出意料开局也是给了我一张图,据说多多的批发目前的风控是极其强的,我就分析测试了一下,黑了我一个号!!!
如果你看到你的页面一直是提示操作太过频繁,请稍后再试!之后页面就试一片空白,所有的功能都用不了
这个滑块的话,问题不大。有实力的话可以分析研究一下。我的话,没有实力,直接页面手动拖动一下,不然接口后续请求基本如下:
{result":{“verifyAuthToken”:“309dYy7ZgpWuk00cOyrgcQ3bed9a9ba4fdagfc7”},“error code”:54001, “error msa”:“”}
在此过程中我发现了一个特别迷惑的行为,就是出现滑块之后,网站页面,并没有弹出滑块的图,但是重新执行程序,接口不出滑块,正常可以请求到数据
我不知道是不是session的问题,但是就算重新执行程序,过程中比如在搜索提交一定次数后,同样会再次出现滑块反馈
直到最后,你的网页它也给你弹出了滑块,这个时候,更梦幻的就来了,你会发现浏览器触发一次滑块后,直接手过一下,拿参数下来用后续不会再出滑块
为了验证这个问题,我挂了程序一段时间,访问正常、搜索正常、详情页商品数据获取正常
说了这么多题外话,只是为了给大家一点踩过的坑。下面我们还是回到正题,如下所示:
参数没有啥加密的,主要的还是头部这个Anti-Content的参数加密,解决了它就迈过了第一重大山
再看一下响应数据,图中标注的字段在详情页接口请求中会用到
3. 分析与扣代码
跟商家端一样,我门搜索参数,然后断点开始调试分析。这里还是Webpack,所以我们找到入口,把自执行函数扣下来,Webpack最基本的组成就是自执行函数跟模块加载器!
之后把函数的实参,全部导出来放到自执行调用函数下,因为本身调用执行的就是一堆函数,只不过都是索引的方式
分析调试找到自执行函数,把代码扣出来,如下所示:
!function(e) {
function t(t) {
for (var n, o, d = t[0], f = t[1], i = t[2], u = 0, s = []; u < d.length; u++)
o = d[u],
Object.prototype.hasOwnProperty.call(c, o) && c[o] && s.push(c[o][0]),
c[o] = 0;
for (n in f)
Object.prototype.hasOwnProperty.call(f, n) && (e[n] = f[n]);
for (l && l(t); s.length; )
s.shift()();
return a.push.apply(a, i || []),
r()
}
function r() {
for (var e, t = 0; t < a.length; t++) {
for (var r = a[t], n = !0, o = 1; o < r.length; o++) {
var f = r[o];
0 !== c[f] && (n = !1)
}
n && (a.splice(t--, 1),
e = d(d.s = r[0]))
}
return e
}
var n = {}
, o = {
21: 0
}
, c = {
21: 0
}
, a = [];
function d(t) {
if (n[t])
return n[t].exports;
var r = n[t] = {
i: t,
l: !1,
exports: {}
};
return e[t].call(r.exports, r, r.exports, d),
r.l = !0,
r.exports
}
d.e = function(e) {
var t = [];
o[e] ? t.push(o[e]) : 0 !== o[e] && {
1: 1,
10: 1,
11: 1,
12: 1,
14: 1,
15: 1,
17: 1
}[e] && t.push(o[e] = new Promise((function(t, r) {
for (var n = "static/css/" + ({
7: "AccountCenter",
8: "Activity",
9: "BestGoods",
10: "Cart",
11: "GoodsDetail",
12: "GoodsDropShipping",
13: "Home",
14: "Mall",
15: "MallSearch",
16: "NotFound",
17: "Order",
18: "Payment",
19: "Search"
}[e] || e) + "." + {
0: "31d6cfe0d",
1: "1bb732cb7",
2: "31d6cfe0d",
3: "31d6cfe0d",
4: "31d6cfe0d",
5: "31d6cfe0d",
6: "31d6cfe0d",
7: "31d6cfe0d",
8: "31d6cfe0d",
9: "31d6cfe0d",
10: "86909bf59",
11: "1405928aa",
12: "9eff41d5d",
13: "31d6cfe0d",
14: "941e90c52",
15: "86909bf59",
16: "31d6cfe0d",
17: "07dca30ce",
18: "31d6cfe0d",
19: "31d6cfe0d",
23: "31d6cfe0d",
24: "31d6cfe0d",
25: "31d6cfe0d",
26: "31d6cfe0d",
27: "31d6cfe0d",
28: "31d6cfe0d",
29: "31d6cfe0d",
30: "31d6cfe0d"
}[e] + ".chunk.css", o = d.p + n, c = document.getElementsByTagName("link"), a = 0; a < c.length; a++) {
var f = (u = c[a]).getAttribute("data-href") || u.getAttribute("href");
if ("stylesheet" === u.rel && (f === n || f === o))
return t()
}
var i = document.getElementsByTagName("style");
for (a = 0; a < i.length; a++) {
var u;
if ((f = (u = i[a]).getAttribute("data-href")) === n || f === o)
return t()
}
var l = document.createElement("link");
l.rel = "stylesheet",
l.type = "text/css",
l.onload = t,
l.onerror = function(t) {
var n = t && t.target && t.target.src || o
, c = new Error("Loading CSS chunk " + e + " failed.\n(" + n + ")");
c.request = n,
r(c)
}
,
l.href = o,
document.getElementsByTagName("head")[0].appendChild(l)
}
)).then((function() {
o[e] = 0
}
)));
var r = c[e];
if (0 !== r)
if (r)
t.push(r[2]);
else {
var n = new Promise((function(t, n) {
r = c[e] = [t, n]
}
));
t.push(r[2] = n);
var a, f = document.createElement("script");
f.charset = "utf-8",
f.timeout = 120,
d.nc && f.setAttribute("nonce", d.nc),
f.src = function(e) {
return d.p + "static/js/" + ({
7: "AccountCenter",
8: "Activity",
9: "BestGoods",
10: "Cart",
11: "GoodsDetail",
12: "GoodsDropShipping",
13: "Home",
14: "Mall",
15: "MallSearch",
16: "NotFound",
17: "Order",
18: "Payment",
19: "Search"
}[e] || e) + "." + {
0: "f10cbb13",
1: "1f11793f",
2: "377e6d6e",
3: "35ce66b2",
4: "067dc63d",
5: "faf75b50",
6: "c87ff2b9",
7: "5a36fa8d",
8: "3e335bc4",
9: "419b7116",
10: "3088d3ab",
11: "39a585d4",
12: "d07a6c4a",
13: "20c6d848",
14: "30a72180",
15: "53f0e801",
16: "bd04a08e",
17: "319b16be",
18: "135c3c2b",
19: "66b54e82",
23: "c46b72b3",
24: "bcfa92ac",
25: "dbb47e8b",
26: "8b9ca1c3",
27: "1e9746e3",
28: "73b775ab",
29: "c13c09f3",
30: "ca572efb"
}[e] + ".chunk.js"
}(e);
var i = new Error;
a = function(t) {
f.onerror = f.onload = null,
clearTimeout(u);
var r = c[e];
if (0 !== r) {
if (r) {
var n = t && ("load" === t.type ? "missing" : t.type)
, o = t && t.target && t.target.src;
i.message = "Loading chunk " + e + " failed.\n(" + n + ": " + o + ")",
i.name = "ChunkLoadError",
i.type = n,
i.request = o,
r[1](i)
}
c[e] = void 0
}
}
;
var u = setTimeout((function() {
a({
type: "timeout",
target: f
})
}
), 12e4);
f.onerror = f.onload = a,
document.head.appendChild(f)
}
return Promise.all(t)
}
,
d.m = e,
d.c = n,
d.d = function(e, t, r) {
d.o(e, t) || Object.defineProperty(e, t, {
enumerable: !0,
get: r
})
}
,
d.r = function(e) {
"undefined" !== typeof Symbol && Symbol.toStringTag && Object.defineProperty(e, Symbol.toStringTag, {
value: "Module"
}),
Object.defineProperty(e, "__esModule", {
value: !0
})
}
,
d.t = function(e, t) {
if (1 & t && (e = d(e)),
8 & t)
return e;
if (4 & t && "object" === typeof e && e && e.__esModule)
return e;
var r = Object.create(null);
if (d.r(r),
Object.defineProperty(r, "default", {
enumerable: !0,
value: e
}),
2 & t && "string" != typeof e)
for (var n in e)
d.d(r, n, function(t) {
return e[t]
}
.bind(null, n));
return r
}
,
d.n = function(e) {
var t = e && e.__esModule ? function() {
return e.default
}
: function() {
return e
}
;
return d.d(t, "a", t),
t
}
,
d.o = function(e, t) {
return Object.prototype.hasOwnProperty.call(e, t)
}
,
d.p = "https://mms-static.pddpic.com/wholesale/",
d.oe = function(e) {
throw console.error(e),
e
}
;
var f = window.webpackJsonp = window.webpackJsonp || []
, i = f.push.bind(f);
f.push = t,
f = f.slice();
for (var u = 0; u < f.length; u++)
t(f[u]);
var l = i;
r()
}([]);
如果加载器函数与执行对象在一个文件中的Webpack就会比较好扣,首先,在函数内找到模块加载器的特征位置,代码如下所示:
function d(t) {
if (n[t])
return n[t].exports;
var r = n[t] = {
i: t,
l: !1,
exports: {}
};
return e[t].call(r.exports, r, r.exports, d),
r.l = !0,
r.exports
}
上面这个t传入的可以是索引和对象的key,参数表示的是列表或对象的形参,接下来需要把目标扣出来,自执行函数只是其中的一步,传入的t才是关键,如下跳转:
直接把所有调用模块导出来,放到自执行的[]内,如下所示:
最后我们将算法的调用集成到Python程序中测试一下效果,如下: