JS逆向 - 盼之(decode__1174、sign)
概要
提示:仅供学习,不得用做商业交易,如有侵权请及时联系
逆向:JS逆向 - 盼之(decode__1174、sign)
URL:aHR0cHM6Ly93d3cucHpkcy5jb20vZ29vZHNMaXN0LzgvNg==
整体架构流程
提示:过debugger ---- 魔改浏览器
点击下一页发送POST请求

魔改浏览器网上自己找下,或者私我!!!
技术名词解释
提示:观察需要加密的参数-分析加密位置
1、请求载荷:

2、请求头:

3、分析请求头加密位置:全局搜索


const CryptoJS = require('crypto-js');
function get_header(o) {
I = Date.now();
for (a = I,
"",
s = "",
f = new Array(1,2,3,4,5,6,7,8,9),
l = 0; l < 6; l++)
d = Math.floor(9 * Math.random()),
s += f[d];
if (c = Number(s), p = [], 'post')
p.push("PZTimestamp=" + a + "&Random=" + c + "&2147483647=" + encodeURIComponent(JSON.stringify(o)))
E = p.join("&") + "&accessKey=3qXyB7uf",O = void 0,O = E.replace(/[(]/g, "%28"),
E = O = (O = (O = (O = (O = O.replace(/[)]/g, "%29")).replace(/[']/g, "%27")).replace(/[*]/g, "%2A")).replace(/[~]/g, "%7E")).replace(/[!!]/g, "%21"),
b = CryptoJS.MD5(E).toString();
return {
Timestamp: a+'',
strMd5: b,
Random: c+''
}
}
技术细节
提示:分析decode__1174的生成
1、堆栈断点,点击下一页触发断点:

2、观察参数是否生成:

3、往上跟一个栈,发现发送了一个send,那么可能是重写了xhr的send方法,然后通过一个对象去接收new URLSearchParams拿到href,去拼接的decode__1174

4、单步进去send方法,继续观察什么时候生成的

5、到这里我们可以看到,赋值了一个新对象,里面有H,猜测可能会对它进行拼接,继续往下跟栈

6、当我们一步一步跟栈下面,发现运行Ri这个函数,发现页面刷新了,xhr的值也拼接了,那么decode__1174肯定是这个函数生成的,进入Ri函数分析

7、刚进入就判断了window下面有没有该属性:_waf_bd8ce2ce37

其实这个值就是当我第一次请求,或者请求失败时返回的HTML里面的script

8、继续往下走,会发现去判断了xhr里面是否存在某些属性:

提示:补环境时,XMLHttpRequest的prototype一定得加上_waf_hook
9、当我们运行完R[ZC(M5.d)](XY, Xg[0x17 * -0x151 + -0x12af + 0x2d12 + ME], Xi[ZC(M5.n)], Xg[-0x1955 + 0x268f + -0xd3a], 0x1 * -0x12eb + -0x43 * -0x2f + 0x3 * 0x235),Xj里面就拼接了decode__1174

10、到这里我们可以知道,decode_1174肯定时XY函数生成,跟进去,里面一大堆的switch,这里我就不一步一步讲了,直接说位置

11、到这里你会发现值生成了,'28178cb220-'的值是固定的,那么最后只需要还原R[ZJ(M4.X6)](J, Xb)是怎么来的就行了
12、Xb是加密的明文,首页得知道它怎么来的,往上跟就是case 3的时候生成的

明文:[R[ZJ(M4.v)](XX, Xb), R[ZJ(M4.F)](XX, XQ), R[ZJ(M4.p)](X0), R[ZJ(M4.e)](new M['E'][(ZJ(M4.k))]()[ZJ(M4.G)](), ''), XV[ZJ(M4.J) + ZJ(M4.d)], XV[ZJ(M4.n) + ZJ(M4.S)], R[ZJ(M4.c)](f)]
- R[ZJ(M4.v)](XX, Xb):Xb ---- Xm、Xh进行md5再通过计算拼接得到,而Xm、Xh是通过_waf_bd8ce2ce37、请求方式、api、data…拼接的encodeURIComponent


提示:坑点,Math.random重写了一份固定值,计算时用的其实是固定值
// 固定0.6398672226746067
func_chufa = function (a,b) {
return a / b;
}
func_yushu = function (a,b) {
return a % b;
}
func_jiafa = function (a,b) {
return a + b;
}
func_chengfa = function (a,b) {
return a * b;
}
function set_random(Xi) {
var XM = {};
XM["qTmGq"] = "function random() { [native code] }";
var Xg = XM;
F = -0x139d5b97 + -0xed0f55d + 0x5fd2a01a;
// Error检测
var XR = 1436544;
var Xy = -0x17603115 + -0xf38cfa0f + -0x6e99ab * -0x412 + 997
, XA = function () {
return func_chufa(F = func_yushu(func_jiafa(func_chengfa(XR, F), Xi), Xy), Xy);
};
return XA['toString'] = function () {
return Xg["qTmGq"];
}, XA;
}
Math.random_ = Math.random;
Math.random = set_random(1693719615);
- RZJ(M4.p):这个值,确实是Math.random没重写之前的方法进行操作一个数组,然后操作0和1得到的一个数,直接扣就行
- RZJ(M4.p), R[ZJ(M4.e)](new M[‘E’](ZJ(M4.k))ZJ(M4.G), ‘’):时间戳 + ‘’
- XV[ZJ(M4.J) + ZJ(M4.d)]:window._waf_bd8ce2ce37
- XV[ZJ(M4.n) + ZJ(M4.S)]:window._waf_a86dfdc5f2 (当前js执行过程中生成的时间戳)
- RZJ(M4.c):固定值 2105840676a198dee460b7
- 最后通过join拼接的 “|”

13、这里直接给出最后加密的函数:
var jiam = function (XM) {
var Xg = 6;
var x = ['T', 'J', 'P', 'g', 'l', 'M', '7', 'H', 'i', '8', 'k', '1', '0', 'h', 'O', 't', '3', 'Z', 'X', '2', '4', 'n', 'B', 'b', 'S', 'j', 'q', 'w', 'r', 'm', 'C', 'N', '6', 'p', 'I', 'E', 'e', 'u', 'x', 'Q', 'y', 'f', '/', '5', '_', '=', 'K', 'o', 'U', 'd', 'Y', 's', 'v', 'D', 'z', 'a', 'c', 'W', 'G', 'R', 'V', 'L', '9', 'A', 'F'];
var Xy = function (XM) {
return x[XM];
};
var XA, Xh, Xm, XV = {}, Xb = {}, XQ = '', Xw = '', XI = '', Xz = 2, Xf = 3, Xx = 2, XH = [], Xv = 0, XF = 0;
for (Xm = 0; Xm < XM['length']; Xm += 1)
if (XQ = XM["charAt"](Xm),
Object['prototype']['hasOwnProperty']['call'](XV, XQ) || (XV[XQ] = Xf,
Xf += 1,
Xb[XQ] = !(0)),
Xw = XI + XQ,
Object['prototype']['hasOwnProperty']['call'](XV, Xw))
XI = Xw;
else {
if (Object['prototype']['hasOwnProperty']['call'](Xb, XI)) {
if (XI['charCodeAt'](0) < 256) {
for (XA = 0; XA < Xx; XA++)
Xv <<= 1,
(XF == (Xg - 1)) ? (XF = 0,
XH['push'](Xy(Xv)),
Xv = 0) : XF++;
for (Xh = XI['charCodeAt'](0),
XA = 0; XA < 8; XA++)
Xv = ((Xv << 1) | (1 & Xh)),
(XF == (Xg - 1)) ? (XF = 0,
XH['push'](Xy(Xv)),
Xv = 0) : XF++,
Xh >>= 1;
} else {
for (Xh = 1,
XA = 0; XA < Xx; XA++)
Xv = ((Xv << 1) | Xh),
(XF == (Xg - 1)) ? (XF = 0,
XH['push'](Xy(Xv)),
Xv = 0) : XF++,
Xh = 0;
for (Xh = XI['charCodeAt'](0),
XA = 0; XA < 16; XA++)
Xv = ((Xv << 1) | (1 & Xh)),
(XF == (Xg - 1)) ? (XF = 0,
XH['push'](Xy(Xv)),
Xv = 0) : XF++,
Xh >>= 1;
}
(0 == --Xz) && (Xz = Math['pow'](2, Xx),
Xx++),
delete Xb[XI];
} else {
for (Xh = XV[XI],
XA = 0; XA < Xx; XA++)
Xv = ((Xv << 1) | (1 & Xh)),
(XF == (Xg - 1)) ? (XF = 0,
XH['push'](Xy(Xv)),
Xv = 0) : XF++,
Xh >>= 1;
}
(0 == --Xz) && (Xz = Math['pow'](2, Xx),
Xx++),
XV[Xw] = Xf,
Xf += -0x17bb + -0xc7 * -0x1c + 0x1f8,
XI = String(XQ);
}
if ('' !== XI) {
if (Object['prototype']['hasOwnProperty']['call'](Xb, XI)) {
if (XI['charCodeAt'](0) < 256) {
for (XA = 0; XA < Xx; XA++)
Xv <<= -0xc3 * -0x15 + 0x4a * 0x52 + -0x27b2 * 0x1,
(XF == (Xg - 1)) ? (XF = -0xa67 + 0x11fc * 0x1 + -0x1 * 0x795,
XH['push'](Xy(Xv)),
Xv = 0x1 * -0xb60 + -0x1f4f + 0x2aaf) : XF++;
for (Xh = XI['charCodeAt'](0),
XA = 0; XA < 8; XA++)
Xv = ((Xv << 1) | (1 & Xh)),
(XF == (Xg - 1)) ? (XF = 0,
XH['push'](Xy(Xv)),
Xv = 0) : XF++,
Xh >>= 1;
} else {
for (Xh = -0x8ec + -0x13a1 + 0x1c8e,
XA = 0; XA < Xx; XA++)
Xv = ((Xv << 1) | Xh),
(XF == (Xg - 1)) ? (XF = 0,
XH['push'](Xy(Xv)),
Xv = -0x7 * -0xd9 + -0x232 * 0x5 + 0x1 * 0x50b) : XF++,
Xh = -0xe95 + 0x3ed + -0x2aa * -0x4;
for (Xh = XI['charCodeAt'](0),
XA = 0; XA < 16; XA++)
Xv = ((Xv << 1) | (1 & Xh)),
(XF == (Xg - 1)) ? (XF = 0x48a + -0x1738 + 0x12ae,
XH['push'](Xy(Xv)),
Xv = 0) : XF++,
Xh >>= 0x1e29 + 0x225e + 0xac1 * -0x6;
}
(0 == --Xz) && (Xz = Math['pow'](0x973 + 0xa * -0x368 + 0x1 * 0x189f, Xx),
Xx++),
delete Xb[XI];
} else {
for (Xh = XV[XI],
XA = -0x18a4 * -0x1 + 0xb55 + -0x23f9; XA < Xx; XA++)
Xv = ((Xv << 1) | (1 & Xh)),
(XF == (Xg - 1)) ? (XF = -0x1d03 + -0xcfd + 0x2a0 * 0x10,
XH['push'](Xy(Xv)),
Xv = -0x98f + 0x1 * -0x106b + 0x19fa) : XF++,
Xh >>= 0x151 * 0x1d + 0x120e + -0x1c1d * 0x2;
}
(0 == --Xz) && (Xz = Math['pow'](0x1a4f + 0x29 * -0x40 + -0x100d, Xx),
Xx++);
}
for (Xh = 0xb40 + -0x2252 + 0x1714,
XA = -0x1bd * 0xd + -0x209a + 0x3733; XA < Xx; XA++)
Xv = ((Xv << 1) | (1 & Xh)),
(XF == (Xg - 1)) ? (XF = 0x1687 + -0x33 * -0x32 + -0x207d,
XH['push'](Xy(Xv)),
Xv = 0) : XF++,
Xh >>= 1;
for (; ; ) {
if (Xv <<= 1,XF == (Xg - 1)) {
XH['push'](Xy(Xv));
break;
}
XF++;
}
return XH['join']('');
}

14、最后扣完纯算:也才200行

15、py调用

小结
提示:学习交流主页,星球持续更新中:(+星球主页+v)
更多推荐


所有评论(0)