AST反混淆实战:猿人学爬虫比赛第二题详细题解
缘起
应星友要求,写下此文,哎,有钱能使鬼推磨。
实战地址:
http://match.yuanrenxue.com/match/2
抓包分析
由于谷歌浏览器某些请求不会显示,建议使用火狐浏览器来抓包分析。
这是一个典型的cookie反爬,最后一个红框处是数据接口。如果不看题目,有经验的人一眼就能看出来。
第一次请求,返回的是一段js代码:
第二次请求的是同一地址,这时候带上了cookie:
根据经验,第二次请求的cookie,肯定是第一次请求计算的,因为第一次请求结果中并没有直接设置cookie。
注意记录此时的 cookie 值:
m : "9c8b2ba4362ff5a7023d8db7041dcd04|1603517539000"
|后面明显是个时间戳。
AST化简代码,静态分析
将第一次请求的js代码保存为encode.js,去掉 script标签。
保存后,使用一键解ob混淆工具还原代码,命令:
node decode_obfuscator.js encode.js
打开保存后的结果 decode_result.js,代码很短,一下就看到了 cookie设置的地方:
是在 _0x721154 这个函数里设置的,后面直接就调用了,实参是 函数 _0x5015e3 ,它的返回值是一个 时间戳,也就是 |后面的值。
把 _0x721154 这个函数改造一下,去掉DOM相关的操作,让它直接返回结果:
-
function _0x721154(_0x1243f6, _0x167ea5) {
-
return "m" + _0x3445fe() + "=" + _0x531a93(_0x1243f6) + "|" + _0x1243f6 + "; path=/";
-
}
现在实参明确了,返回结果也明确了,先来看 _0x3445fe 这个函数
去除垃圾代码
_0x3445fe 这个函数 定义如下:
-
function _0x3445fe(_0x22e65, _0x533ac1) {
-
var _0x537cb8 = 0;
-
-
-
var _0x385b2c = _0x2d77f8(this, function () {
-
var _0x245ea0 = function () {
-
var _0x56862a = _0x245ea0["constructor"]("return /\" + this + \"/")()["compile"]("^([^ ]+( +[^ ]+)+)+[^ ]}");
-
-
-
return !_0x56862a["test"](_0x385b2c);
-
};
-
-
-
return _0x245ea0();
-
});
-
-
-
_0x385b2c();
-
-
-
_0x449be1();
-
-
-
qz = [10, 99, 111, 110, 115, 111, 108, 101, 32, 61, 32, 110, 101, 119, 32, 79, 98, 106, 101, 99, 116, 40, 41, 10, 99, 111, 110, 115, 111, 108, 101, 46, 108, 111, 103, 32, 61, 32, 102, 117, 110, 99, 116, 105, 111, 110, 32, 40, 115, 41, 32, 123, 10, 32, 32, 32, 32, 119, 104, 105, 108, 101, 32, 40, 49, 41, 123, 10, 32, 32, 32, 32, 32, 32, 32, 32, 102, 111, 114, 40, 105, 61, 48, 59, 105, 60, 49, 49, 48, 48, 48, 48, 48, 59, 105, 43, 43, 41, 123, 10, 32, 32, 32, 32, 32, 32, 32, 32, 104, 105, 115, 116, 111, 114, 121, 46, 112, 117, 115, 104, 83, 116, 97, 116, 101, 40, 48, 44, 48, 44, 105, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 125, 10, 32, 32, 32, 32, 125, 10, 10, 125, 10, 99, 111, 110, 115, 111, 108, 101, 46, 116, 111, 83, 116, 114, 105, 110, 103, 32, 61, 32, 39, 91, 111, 98, 106, 101, 99, 116, 32, 79, 98, 106, 101, 99, 116, 93, 39, 10, 99, 111, 110, 115, 111, 108, 101, 46, 108, 111, 103, 46, 116, 111, 83, 116, 114, 105, 110, 103, 32, 61, 32, 39, 402, 32, 116, 111, 83, 116, 114, 105, 110, 103, 40, 41, 32, 123, 32, 91, 110, 97, 116, 105, 118, 101, 32, 99, 111, 100, 101, 93, 32, 125, 39, 10];
-
eval(_0x19be63(qz));
-
-
-
try {
-
if (global) {
-
console["log"]("\u4EBA\u751F\u82E6\u77ED\uFF0C\u4F55\u5FC5python\uFF1F");
-
} else {
-
while (1) {
-
console["log"]("\u4EBA\u751F\u82E6\u77ED\uFF0C\u4F55\u5FC5python\uFF1F");
-
debugger;
-
}
-
}
-
} catch (_0x1d08b1) {
-
return navigator["vendorSub"];
-
}
-
}
来看 _0x385b2c 这个函数:
-
var _0x385b2c = _0x2d77f8(this, function () {
-
var _0x245ea0 = function () {
-
var _0x56862a = _0x245ea0["constructor"]("return /\" + this + \"/")()["compile"]("^([^ ]+( +[^ ]+)+)+[^ ]}");
-
-
-
return !_0x56862a["test"](_0x385b2c);
-
};
-
-
-
return _0x245ea0();
-
});
-
-
-
_0x385b2c();
这个函数在声明之后马上就执行了,没有实参,虽然有返回值,但是并没有赋值给其他变量。 再看函数体,没有对任何全局变量进行操作,因此,可以直接进行删除!
按照这个思路,后面的 _0x449be1(); 调用同样可以删除,没啥用。
再看 try语句:
-
try {
-
if (global) {
-
console["log"]("\u4EBA\u751F\u82E6\u77ED\uFF0C\u4F55\u5FC5python\uFF1F");
-
} else {
-
while (1) {
-
console["log"]("\u4EBA\u751F\u82E6\u77ED\uFF0C\u4F55\u5FC5python\uFF1F");
-
debugger;
-
}
-
}
-
} catch (_0x1d08b1) {
-
return navigator["vendorSub"];
-
}
浏览器环境没有 global 这个对象,那就会执行 catch语句,返回了:
navigator["vendorSub"]
这个值,直接在控制台运行得出它是一个空值。因此,直接替换成这样就好:
return "";
这样就清爽多了:
-
function _0x3445fe(_0x22e65, _0x533ac1) {
-
var _0x537cb8 = 0;
-
qz = [10, 99, 111, 110, 115, 111, 108, 101, 32, 61, 32, 110, 101, 119, 32, 79, 98, 106, 101, 99, 116, 40, 41, 10, 99, 111, 110, 115, 111, 108, 101, 46, 108, 111, 103, 32, 61, 32, 102, 117, 110, 99, 116, 105, 111, 110, 32, 40, 115, 41, 32, 123, 10, 32, 32, 32, 32, 119, 104, 105, 108, 101, 32, 40, 49, 41, 123, 10, 32, 32, 32, 32, 32, 32, 32, 32, 102, 111, 114, 40, 105, 61, 48, 59, 105, 60, 49, 49, 48, 48, 48, 48, 48, 59, 105, 43, 43, 41, 123, 10, 32, 32, 32, 32, 32, 32, 32, 32, 104, 105, 115, 116, 111, 114, 121, 46, 112, 117, 115, 104, 83, 116, 97, 116, 101, 40, 48, 44, 48, 44, 105, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 125, 10, 32, 32, 32, 32, 125, 10, 10, 125, 10, 99, 111, 110, 115, 111, 108, 101, 46, 116, 111, 83, 116, 114, 105, 110, 103, 32, 61, 32, 39, 91, 111, 98, 106, 101, 99, 116, 32, 79, 98, 106, 101, 99, 116, 93, 39, 10, 99, 111, 110, 115, 111, 108, 101, 46, 108, 111, 103, 46, 116, 111, 83, 116, 114, 105, 110, 103, 32, 61, 32, 39, 402, 32, 116, 111, 83, 116, 114, 105, 110, 103, 40, 41, 32, 123, 32, 91, 110, 97, 116, 105, 118, 101, 32, 99, 111, 100, 101, 93, 32, 125, 39, 10];
-
eval(_0x19be63(qz));
-
-
return "";
-
}
这个函数后面是一个 定时器语句,因为后面有调用 _0x3445fe 这个函数,因此这行调用也可以删除:
setInterval(_0x3445fe(), 500);
定你妹呀!
运行得到结果
好了,经过上面的操作,似乎可以运行了。注意加打印并传入实参,方便比对结果:
console.log(_0x721154("1603517539000"));
将上面的代码添加到自执行函数的最好一行,运行报错:
报错位置在 _0x3445fe 函数的 下面代码处:
eval(_0x19be63(qz));
有个history,估计也是dom相关的,先屏蔽掉,再运行:
不报错了,比对之前的cookie值,一模一样。
这就出结果了,简直不要太简单。完!
文章来源: blog.csdn.net,作者:悦来客栈的老板,版权归原作者所有,如需转载,请联系作者。
原文链接:blog.csdn.net/qq523176585/article/details/109507934
- 点赞
- 收藏
- 关注作者
评论(0)