一.前置的JS基础。
请参考我创作文章的JS基础
JS逆向爬虫需要掌握的最基础JS知识_js逆向需要什么基础-优快云博客
只能说够用,着重理解定时器,promise,ansinc/await
二.实战案例
案例一:中国五矿中国五矿集团有限公司供应链管理平台
接口:https://ec.minmetals.com.cn/open/homepage/zbs/by-lx-page
发现是载荷加密
1.搜索关键词
发现此方法有很多数,故不采用
2.hook
前置知识:JS逆向的常见hook技术(实战案例)_js逆向hook载荷里面的参数-优快云博客
(function() {
var _stringify = JSON.stringify;
JSON.stringify = function(ps) {
console.log("Hook JSON.stringify ——> ", ps);
debugger;
return _stringify(ps); // 不改变原有的执行逻辑
}
})();
轻松找的加密位置
3.搜索url关键词
发现也找到加密的位置
会发现以上几种方法很容易就找到加密的位置,一般来说这样的网站没难度,接下来讲xhr调试异步跟栈。
4.XHR
跳到最后一个栈,发现异步
function s(A) { Dn(a, n, r, s, i, "next", A) }
往异步跟栈,发现执行的位置是这里
i.done ? e(o) : Promise.resolve(o).then(n, r)s
干货来了!
也就是 i.done ? e(o) : Promise.resolve(o).then(n, r)
执行 function s(A) { Dn(a, n, r, s, i, "next", A) }
n 就相当于函数s(A)
A相当于o
下断点,重新跟栈
o为pending状态,即还没运行完毕
function Dn(A, e, t, n, r, a, s) {
try {
var i = A[a](s)
, o = i.value
} catch (g) {
return void t(g)
}
i.done ? e(o) : Promise.resolve(o).then(n, r)
o从哪里来?
仔细观察,o = i.value,即o从i里出来,i从A里出来
下断点重新触发
进去函数
方法为
(function(e) { return this._invoke(t, e) })
在进去函数
这个函数会出现在大多数网站上,比较难的是对这个逻辑进行混淆 ,不管三七二十一看return,看var l = d(e, t, n);
return function(o, i) {
if (r === p)
throw new Error("Generator is already running");
if (r === m) {
if ("throw" === o)
throw i;
return z()
}
n.method = o,
n.arg = i;
while (1) {
var a = n.delegate;
if (a) {
var s = O(a, n);
if (s) {
if (s === v)
continue;
return s
}
}
if ("next" === n.method)
n.sent = n._sent = n.arg;
else if ("throw" === n.method) {
if (r === h)
throw r = m,
n.arg;
n.dispatchException(n.arg)
} else
"return" === n.method && n.abrupt("return", n.arg);
r = p;
var l = d(e, t, n);
if ("normal" === l.type) {
if (r = n.done ? m : f,
l.arg === v)
continue;
return {
value: l.arg,
done: n.done
}
}
"throw" === l.type && (r = m,
n.method = "throw",
n.arg = l.arg)
}
}
找return的位置
return {
value: l.arg,
done: n.done
}
value为 一开始i的值,也是o的值
然后找l的值
var l = d(e, t, n);下断点进去,
e.call(t,n)相当于函数e(e,n)进去e函数
也就是相当于 var l = d(e, t, n);d函数d是调用e函数传参e和n参数
进去函数e,控制流,这个模板也常出现,和混淆一起出现,就这个控制流,如果你调试出现错误,或者重复调试执行,可以进去很多次控制流,控制流出现的方式不一样,就这个e.call(t,n),执行好几次,可以经过不同的控制流。
A.next = 2 相当于执行case 2:
A.sent 相当于y(e)返回的值,别问为什么,这是经验!!!
如果你重复调试,会出现以下错误结果,这玩意没有用
这个是继续调试的结果
return c.a.wrap((function(A) {
while (1)
switch (A.prev = A.next) {
case 0:
return A.next = 2,
y(e);
case 2:
return t = A.sent,
A.abrupt("return", Xn.post("/open/homepage/zbs/by-lx-page ", {
param: t
}));
case 4:
case "end":
return A.stop()
}
}
往y下断点,跟过去,发现以往的断点重新执行,断点是可以重复执行的
再进去p
注意这个
发现流程跟以上一样
要重新走一遍
这个第二次e调用返回的值就是o = i.value,进去e方法,进去又一个控制流结果显而易见了
加密的位置显而易见了,非对称加密
值得一提这网站需要先请求一次获取密钥
三.总结
这个网站可以说是异步的入门,非常简单,本案例只是梳理一些异步的流程,以后实战中不需要一步一步跟,找好关键断点,比如 var l = d(e, t, n),A.sent 相当于y(e)返回的值,打这个几个断点,调试即可。但是以后会跟混淆结合,所以还是得好好实战。
干货总结:
1.var l = d(e, t, n)找.call(t,n)可以要进去很多遍
2.A.sent 相当于y(e)返回的值
3.A.next = 2相对于跳转case 2
4.可以适当搜索url关键词
5. i.done ? e(o) : Promise.resolve(o).then(n, r)
下一个栈是执行 这个函数
function s(A) { Dn(a, n, r, s, i, "next", A) }
n 就相当于函数s(A),A相当于o