逆向目标
- 网址:
https://match.yuanrenxue.cn/match/5
- 接口:
https://match.yuanrenxue.cn/api/match/5?page=2&m=1709806560791&f=1709806560000
- 参数:
Cookie(m、RM4hZBv0dDon443M)
payload(m、f)
逆向过程
老规矩,上来先分析网络请求
网页上分析请求有点不太清楚,我们直接转为 python
代码来分析,观察右侧python代码,加密的几个参数就清楚了 cookie(m、RM4hZBv0dDon443M)
和 params(m、f)
逆向分析
我们先进启动器跟栈观察发现加密参数都已经生成完成了,那我们先随便找个加密参数搜索一下看能不能找到window._$is
的赋值语句,直接搜索_$is
,返现只有一个匹配结果
这是一个window
的属性,我们又没有搜索到赋值语句,所以可以断定是在某个js语句
中执行了这个操作,那我们在当前文件继续查看分析这个文件,可以看到在实际的网络请求的逻辑上面就有一段自执行的函数代码
<script>
function _$KS() {
if (eval["toString"]() === "function eval() { [native code] }") {
if ($_zw["length"] === 25) {
$_ow = "";
for (var h = 0; h < window["$$$"]["length"]; h++) {
$_ow += String["fromCharCode"](window["$$$"][h]["charCodeAt"]() - 76);
}
eval($_ow);
} else {
$_ow = "";
for (var h = 0; h < window["$$$"]["length"]; h++) {
$_ow += String["fromCharCode"](window["$$$"][h]["charCodeAt"]() - 76);
}
eval($_ow);
}
} else {
$_ow = "";
for (var h = 0; h < window["$$$"]["length"]; h++) {
$_ow += String["fromCharCode"](window["$$$"][h]["charCodeAt"]() - 2331 - parseInt(h["toString"]()["slice"](0, 1)) * 2);
}
eval($_ow);
}
}
_$KS();
</script>
我们简单分析下这段代码,eval["toString"]() === "function eval() { [native code] }"
的值为true
,然后在控制台看下$_zw
的length
值为27
,所以具体执行的是哪个分支就很清楚了,直接断点调试,发现断住了
接下来就是大家喜闻乐见的常规hook
操作了,既然是 cookie加密
我们就先 hook cookie
的m
参数
(function () {
'use strict';
var cookie_cache = document.cookie;
Object.defineProperty(document, 'cookie', {
get: function () {
return cookie_cache;
},
set: function (val) {
console.log('Setting cookie', val);
//if (val.indexOf('RM4hZBv0dDon443M') !== -1) {
if (val.indexOf('m') !== -1) {
debugger;
}
var cookie = val.split(";")[0];
var ncookie = cookie.split("=");
var flag = false;
var cache = cookie_cache.split("; ");
cache = cache.map(function (a) {
if (a.split("=")[0] === ncookie[0]) {
flag = true;
return cookie;
}
return a;
})
cookie_cache = cache.join("; ");
if (!flag) {
cookie_cache += cookie + "; ";
}
return cookie_cache;
}
});
})();
如下图,断点断在了如下位置
直接跟栈分析就行了
_$Wa = _0x12eaf3();
_0x3d0f3f[_$Fe] = 'm=' + _0x474032(_$Wa) + ';\x20path=/';
控制台打印_$Wa
的值为1709864112000
,是个 13
位的时间戳,再看_0x12eaf3
的函数定义
function _0x12eaf3() {
return _0x35bb1d[_$UH[0xff]](new _0x35bb1d());
}
/*
控制台打印观察混淆后的变量值,如下
*/
_$UH[0xff]
>> 'parse'
_0x35bb1d
>> ƒ Date() {
[native code] }
再来看_0x474032
这个函数
一层层跟下去就可以发现具体的调用顺序了,如下图
调用顺序都有了,接下来我们要开始扣代码了,把上图所有涉及到的调用函数都扣下来,然后我们在本地nodejs
中调试
function _0x1ee7ec(_0x206333) {
return _0x12b47d(_0x11a7a2(_0x35f5f2(_0x206333), 0x8 * _0x206333[_$UH[0x6c]]));
}
function _0x499969(_0x82fe7e) {
var _0x5bdda4, _0x322a73, _0xd0b5cd = '0123456789abcdef', _0x21f411 = '';
for (_0x322a73 = 0x0; _0x322a73 < _0x82fe7e[_$UH[0x6c]]; _0x322a73 += 0x1)
_0x5bdda4 = _0x82fe7e[_$UH[0xf]](_0x322a73),
_0x21f411 += _0xd0b5cd['charAt'](_0x5bdda4 >>> 0x4 & 0xf) + _0xd0b5cd['charAt'](0xf & _0x5bdda4);
return _0x21f411;
}
function _0x2b8a17(_0x36f847) {
return unescape(encodeURIComponent(_0x36f847));
}
function _0x41873d(_0x5a6962) {
return _0x1ee7ec(_0x2b8a17(_0x5a6962));
}
function _0x37614a(_0x32e7c1) {
return _0x499969(_0x41873d(_0x32e7c1));
}
function _0x474032(_0x233f82, _0xe2ed33, _0x3229f9) {
return _0xe2ed33 ? _0x3229f9 ? v(_0xe2ed33, _0x233f82) : y(_0xe2ed33, _0x233f82) : _0x3229f9 ? _0x41873d(_0x233f82) : _0x37614a(_0x233f82);
}
function _0x12b47d(_0x149183) {
var _0xabbcb3, _0x1145c3 = '', _0x4fce58 = 0x20 * _0x149183[_$UH[0x6c]];
for (_0xabbcb3 = 0x0; _0xabbcb3 < _0x4fce58; _0xabbcb3 += 0x8)
_0x1145c3 += _0x30bc70[_$UH[0x114]](_0x149183[_0xabbcb3 >> 0x5] >>> _0xabbcb3 % 0x20 & 0xff);
return _0x1145c3;
}
function _0x35f5f2(_0x243853) {
var _0x139b8b, _0xa791a1 = [];
for (_0xa791a1[(_0x243853[_$UH[0x6c]] >> 0x2) - 0x1] = void 0x0,
_0x139b8b = 0x0; _0x139b8b < _0xa791a1[_$UH[0x6c]]; _0x139b8b += 0x1)
_0xa791a1[_0x139b8b] = 0x0;
var _0x41a533 = 0x8 * _0x243853[_$UH[0x6c]];
for (_0x139b8b = 0x0; _0x139b8b < _0x41a533; _0x139b8b += 0x8)
_0xa791a1[_0x139b8b >> 0x5]