前言:
最近学习js逆向案例,本文仅以初学者思路记录学习,内容比较繁多~
目标地址:
aHR0cHM6Ly9hcHBhcGkuY25obmIuY29tL3JlY3EvYXBpL3RyYW5zZm9ybS9zdXBwbHkvdjUwMS9pbmRleA==
一、加密参数定位
X-Client-Sign无法通过关键字搜索,所以先通过跟栈方式定位参数。
一直跟栈到此处,发现X-Client-Sign是生成的,再往下跟一下异步的栈。
通过这两张对比图,可以发现第一步是没生成header值,进入到异步之后 n作为参数是生成了加密参数值。所以大概率是在return (0,
M.default)(this.$context, t.headers)这串代码中构建了加密值。
return (0,M.default)(this.$context, t.headers).then((function(n) {...}
//这段代码是异步调用,需要先执行(0,M.default)(this.$context, t.headers) 并返回结果后,再继续执行then后面的代码。
可以控制台执行确定下返回结果。
执行结果返回Promise,可以用箭头函数获取异步执行结果。
(0,
M.default)(this.$context, t.headers).then(res=>console.log(res)) 回车后,放开断点,会在控制台显示该代码的执行结果
OK,我们成功定位到X-Client-Sign参数的加密位置。下面需要分析加密函数。
二、分析加密函数。
e.default = function(t) {
var header = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : {}
, e = new Date
, n = t.filterManager
, h = t.classes
, d = void 0 === h ? {} : h
, m = n.filters
, v = d.HeaderAdapter || {}
, y = [];
function w(t) {
var header = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : {}
, e = arguments[2];
return f.default.isObject(t) && f.default.isFunction(t.then) ? y.push({
promise: t,
field: e
}) : header = _(header, t, e),
header
}
function _(source, t, e) {
return f.default.isObject(t) ? source = (0,
c.default)(t, source) : e && (source[e] = t),
source
}
function M() {
if (y.length) {
var t = y.map((function(t) {
return t.promise
}
));
return r.default.all(t).then((function(t) {
return y.forEach((function(e, i) {
header = _(header, t[i], e.field)
}
)),
header
}
))
}
return r.default.resolve(header)
}
return m && m.length && m.forEach((function(filter) {
header = w(filter.getHeaders(), header)
}
)),
(0,
o.default)(v).forEach((function(n) {
var r = v[n];
header = w(f.default.isFunction(r) ? r(t, e) : r, header, n)
}
)),
M().then((function(head) {
return (0,
l.default)(t, head)
}
))
}
这段代码就生成了headers里的加密参数。一开始作者一步步分析,奈何JS水平太差,索性直接在最后加断点,我们只需要关注header这个参数即可。
这里虽然构建出了大部分header参数,但是缺少关键参数X-Client-Sign,所以M并不是关键加密函数,不放心的话可以控制台执行M().then(res=>console.log(res)),放开断点查看返回结果。
确定了M函数并不是关键参数X-CLIENT-SIGN的加密函数。所以猜测后面then之后的才是。继续加断点跟栈。
控制台执行,发现返回了关键加密参数X-CLIENT-SIGN
加密函数定位成功,下面开始进行JS代码还原。
三.JS逆向 纯算还原
e.default = function(t, head) {
var e, n, l = ["w4jDq38=", "ST7CoA==", "GGDChQ==", "YQ1u", "azJe", "w4jClzc=", "wqrDpCM=", "woUiw5E=", "w6jDlUc=", "wovDrgI=", "FMKcfQ==", "wonCuMKH", "w5NwHQ==", "w4jCiWY=", "wrcHMw==", "w7kLQA==", "Z8OiwqU=", "IsKcwpk=", "IcKYIQ==", "w7Vzw5c=", "wqAbw4Q=", "djYB", "R8KzwpY=", "w5fDssKG", "fxpw", "wq8owrI=", "ZcKuwpw=", "wq4ewqo=", "wo5ow4E=", "Wmc/", "w7TDgCQ=", "woHDo8OY", "wo3DpcKT", "PnVd", "wqkcRw==", "w7PDm8KB", "wqtTXg==", "wpjDrSw=", "wokkPw==", "w550w6o=", "fDlM", "QMO7wrU=", "EmzDlA==", "PzrDkg==", "wpVzHA==", "w5UTwr4=", "wq4DwpA=", "woptdg==", "w7XDt8Km", "w7wHw5w=", "woMMw7w=", "wpoUGQ==", "AGNe", "AXfDrw==", "w6vDqi0=", "w7Rcw4U=", "SWA3", "wpzClTI=", "wrAoEw==", "w6XDkMKq", "wrEkJQ==", "wqLDnS8=", "w7I2w7o=", "BWzDqQ==", "w41ANg==", "w4JQw5I=", "wrPDglM=", "wofDscO/", "w5EZw60=", "wpxuwo8=", "c3Rl", "w4jCig0=", "wot8eg==", "wpjDu8Kw", "MUvDrw==", "MsKPIw==", "wow2BA==", "J8KawpA=", "X8O7wpo=", "LGlG", "LmVX", "wonCpcK9", "EsKaQA==", "woXDg8Oj", "FMKQdw==", "w55TRA==", "M8KYJw==", "dMKkw54=", "w6IJw6k=", "wpDCkmA=", "CsKQfQ==", "w7DDgxY=", "ZsKbQw==", "Cll6", "w55HQg==", "wrBLMg==", "wrB+MQ==", "wqtPw6M=", "w7nCtw0=", "w4pZGg==", "wpVwQg==", "HVRE", "wrzDtik=", "w6lOYQ==", "PGNj", "a3Rt", "wrgtw7o=", "VcOPHw=="];
e = l,
n = 130,
function(t) {
for (; --t; )
e.push(e.shift())
}(++n);
var d, m, v, y, w, _, M, S, x, k, E, C, O, A, R, j, T, I, P, L, B, N, D, F, $ = function t(e, n) {
var r, o = l[e -= 0