先来看看代码(部分截图):
复制出来,JS代码部分:
var arg1 = '960909806AA7476E288448504031715EAED08F66';
var _0x4818 = ['\x63\x73\x4b\x48\x77\x71\x4d\x49', '\x5a\x73\x4b\x4a\x77\x72\x38\x56\x65\x41\x73\x79', '\x55\x63\x4b\x69\x4e\x38\x4f\x2f\x77\x70\x6c\x77\x4d\x41\x3d\x3d', '\x4a\x52\x38\x43\x54\x67\x3d\x3d', '\x59\x73\x4f\x6e\x62\x53\x45\x51\x77\x37\x6f\x7a\x77\x71\x5a\x4b\x65\x73\x4b\x55\x77\x37\x6b\x77\x58\x38\x4f\x52\x49\x51\x3d\x3d', '\x77\x37\x6f\x56\x53\x38\x4f\x53\x77\x6f\x50\x43\x6c\x33\x6a\x43\x68\x4d\x4b\x68\x77\x36\x48\x44\x6c\x73\x4b\x58\x77\x34\x73\x2f\x59\x73\x4f\x47', '\x66\x77\x56\x6d\x49\x31\x41\x74\x77\x70\x6c\x61\x59\x38\x4f\x74\x77\x35\x63\x4e\x66\x53\x67\x70\x77\x36\x4d\x3d', '\x4f\x63\x4f\x4e\x77\x72\x6a\x43\x71\x73\x4b\x78\x54\x47\x54\x43\x68\x73\x4f\x6a\x45\x57\x45\x38\x50\x63\x4f\x63\x4a\x38\x4b\x36', '\x55\x38\x4b\x35\x4c\x63\x4f\x74\x77\x70\x56\x30\x45\x4d\x4f\x6b\x77\x34\x37\x44\x72\x4d\x4f\x58', '\x48\x4d\x4f\x32\x77\x6f\x48\x43\x69\x4d\x4b\x39\x53\x6c\x58\x43\x6c\x63\x4f\x6f\x43\x31\x6b\x3d',
...........中间省略很多JS代码.............
function setCookie(name, value) {
var expiredate = new Date();
expiredate.setTime(expiredate.getTime() + (3600 * 1000));
document.cookie = name + "=" + value + ";expires=" + expiredate.toGMTString() + ";max-age=3600;path=/";
}
function reload(x) {
setCookie("acw_sc__v2", x);
document.location.reload();
}
然后看看正确请求页面的cookie信息,果然有这个参数,
复制所有正确的cookie用程序跑一下。
页面正确,再把acw_sc__v2这个参数改一下,又回到了解放前,结合JS代码,得出页面反爬跟 acw_sc__v2有关。
看看JS中的最后几段代码:
function setCookie(name, value) {
var expiredate = new Date();
expiredate.setTime(expiredate.getTime() + (3600 * 1000));
document.cookie = name + "=" + value + ";expires=" + expiredate.toGMTString() + ";max-age=3600;path=/";
}
function reload(x) {
setCookie("acw_sc__v2", x);
document.location.reload();
}
代码一看就知道,这些功能是干嘛的。
再看看document.location.reload();中的reload() 在那里加载了,搜索一下,在这里。
分析一下,看来arg2参数是我们需要的 acw_sc_v2了。
没办法了,那就干吧。。。。。。
先把JS代码整理一下,我使用 https://beautifier.io/ 来优化。解密"\x5a\x73\x4b\x4a\x77\x72\x38\x56\x65\x41\x73\x79"这种参数,也可以用console.log、alert等
整理后:
很明显,部分编码变了,格式也整齐了,但是还是看不懂。
没办法了,那就跑一下吧,直接飙升,浏览器一直转,后来看了代码之后,有一个无限循环。再看看cpu使用情况
好吧,来解读代码吗:
参数:
var arg1 = 'D903259129C2726AE4093900A0687AAEADDBE11F';
var _0x4818 = ['csKHwqMI', 'ZsKJwr8VeAsy', 'UcKiN8O/wplwMA==', 'JR8CTg==', 'YsOnbSEQw7ozwqZKesKUw7kwX8ORIQ==', 'w7oVS8OSwoPCl3jChMKhw6HDlsKXw4s/YsOG', 'fwVmI1AtwplaY8Otw5cNfSgpw6M=', 'OcONwrjCqsKxTGTChsOjEWE8PcOcJ8K6', 'U8K5LcOtwpV0EMOkw47DrMOX', 'HMO2woHCiMK9SlXClcOoC1k=', 'asKIwqMDdgMuPsOKBMKcwrrCtkLDrMKBw64d', 'wqImMT0tw6RNw5k=', 'DMKcU0JmUwUv', 'VjHDlMOHVcONX3fDicKJHQ==', 'wqhBH8Knw4TDhSDDgMOdwrjCncOWwphhN8KCGcKqw6dHAU5+wrg2JcKaw4IEJcOcwrRJwoZ0wqF9YgAV', 'dzd2w5bDm3jDpsK3wpY=', 'w4PDgcKXwo3CkcKLwr5qwrY=', 'wrJOTcOQWMOg', 'wqTDvcOjw447wr4=', 'w5XDqsKhMF1/', 'wrAyHsOfwppc', 'J3dVPcOxLg==', 'wrdHw7p9Zw==', 'w4rDo8KmNEw=', 'IMKAUkBt', 'w6bDrcKQwpVHwpNQwqU=', 'd8OsWhAUw7YzwrU=', 'wqnCksOeezrDhw==', 'UsKnIMKWV8K/', 'w4zDocK8NUZv', 'c8OxZhAJw6skwqJj', 'PcKIw4nCkkVb', 'KHgodMO2VQ==', 'wpsmwqvDnGFq', 'wqLDt8Okw4c=', 'w7w1w4PCpsO4wqA=', 'wq9FRsOqWMOq', 'byBhw7rDm34=', 'LHg+S8OtTw==', 'wqhOw715dsOH', 'U8O7VsO0wqvDvcKuKsOqX8Kr', 'Yittw5DDnWnDrA==', 'YMKIwqUUfgIk', 'aB7DlMODTQ==', 'wpfDh8Orw6kk', 'w7vCqMOrY8KAVk5OwpnCu8OaXsKZP3DClcKyw6HDrQ==', 'wow+w6vDmHpsw7Rtwo98LC7CiG7CksORT8KlW8O5wr3Di8OTHsODeHjDmcKlJsKqVA==', 'NwV+', 'w7HDrcKtwpJawpZb', 'wpQswqvDiHpuw6I=', 'YMKUwqMJZQ==', 'KH1VKcOqKsK1', 'fQ5sFUkkwpI=', 'wrvCrcOBR8Kk', 'M3w0fQ==', 'w6xXwqPDvMOFwo5d'];
这里我分为三个部分。
第一部分(匿名函数):此函数是用于对大数组 _0x4818 进行操作。
(function(_0x4c97f0, _0x1742fd) {
var _0x4db1c = function(_0x48181e) {
while (--_0x48181e) {
_0x4c97f0['push'](_0x4c97f0['shift']());
}
};
.....
_0x3cd6c6();
}(_0x4818, 0x15b));
这个函数中要注意这段代码(其实知道正则的应该看得出,正则不匹配换行,而我们代码已经格式化了):
// 用于防代码格式化
var _0x4a2aed = function() {
var _0x124d17 = new RegExp('\\w+ *\\(\\) *{\\w+ *[\'|\"].+[\'|\"];? *}');
return _0x124d17['test'](_0xb8360b['removeCookie']['toString']());
};
通过修改之后,后加大数组 _0x4818 的值为:
var _0x4818 = ["wqImMT0tw6RNw5k=", "DMKcU0JmUwUv", "VjHDlMOHVcONX3fDicKJHQ==", "wqhBH8Knw4TDhSDDgMOdwrjCncOWwphhN8KCGcKqw6dHAU5+wrg2JcKaw4IEJcOcwrRJwoZ0wqF9YgAV", "dzd2w5bDm3jDpsK3wpY=", "w4PDgcKXwo3CkcKLwr5qwrY=", "wrJOTcOQWMOg", "wqTDvcOjw447wr4=", "w5XDqsKhMF1/", "wrAyHsOfwppc", "J3dVPcOxLg==", "wrdHw7p9Zw==", "w4rDo8KmNEw=", "IMKAUkBt", "w6bDrcKQwpVHwpNQwqU=", "d8OsWhAUw7YzwrU=", "wqnCksOeezrDhw==", "UsKnIMKWV8K/", "w4zDocK8NUZv", "c8OxZhAJw6skwqJj", "PcKIw4nCkkVb", "KHgodMO2VQ==", "wpsmwqvDnGFq", "wqLDt8Okw4c=", "w7w1w4PCpsO4wqA=", "wq9FRsOqWMOq", "byBhw7rDm34=", "LHg+S8OtTw==", "wqhOw715dsOH", "U8O7VsO0wqvDvcKuKsOqX8Kr", "Yittw5DDnWnDrA==", "YMKIwqUUfgIk", "aB7DlMODTQ==", "wpfDh8Orw6kk", "w7vCqMOrY8KAVk5OwpnCu8OaXsKZP3DClcKyw6HDrQ==", "wow+w6vDmHpsw7Rtwo98LC7CiG7CksORT8KlW8O5wr3Di8OTHsODeHjDmcKlJsKqVA==", "NwV+", "w7HDrcKtwpJawpZb", "wpQswqvDiHpuw6I=", "YMKUwqMJZQ==", "KH1VKcOqKsK1", "fQ5sFUkkwpI=", "wrvCrcOBR8Kk", "M3w0fQ==", "w6xXwqPDvMOFwo5d", "csKHwqMI", "ZsKJwr8VeAsy", "UcKiN8O/wplwMA==", "JR8CTg==", "YsOnbSEQw7ozwqZKesKUw7kwX8ORIQ==", "w7oVS8OSwoPCl3jChMKhw6HDlsKXw4s/YsOG", "fwVmI1AtwplaY8Otw5cNfSgpw6M=", "OcONwrjCqsKxTGTChsOjEWE8PcOcJ8K6", "U8K5LcOtwpV0EMOkw47DrMOX", "HMO2woHCiMK9SlXClcOoC1k=", "asKIwqMDdgMuPsOKBMKcwrrCtkLDrMKBw64d"];
第二部分(解密字符串函数):在第三部分,用到很多。
var _0x55f3 = function(_0x4c97f0, _0x1742fd) {
var _0x4c97f0 = parseInt(_0x4c97f0, 0x10);
var _0x48181e = _0x4818[_0x4c97f0];
if (!_0x55f3['atobPolyfillAppended']) {
(function() {
var _0xdf49c6 = Function('return (function () ' + '{}.constructor(\"return this\")()' + ');');
.....
_0x48181e = _0x55f3['rc4'](_0x48181e, _0x1742fd);
_0x55f3['data'][_0x4c97f0] = _0x48181e;
} else {
_0x48181e = _0x55f3['data'][_0x4c97f0];
}
return _0x48181e;
};
涉及算法,不多解释,知道它解密字符串就行了。爬友们在使用时,注意一下参数和返回值。跟着断点一步一步调试会很清楚。
调用解密算法:
第三部分(就叫分配任务函数吧):通过上面的分析,我们知道,arg2就是最终值,那么我们可以安心的改造了。
var l = function() {
while (window[_0x55f3('0x1', 'XMW^')] || window['__phantomas']) {};
var _0x5e8b26 = _0x55f3('0x3', 'jS1Y');
String[_0x55f3('0x5', 'n]fR')][_0x55f3('0x6', 'Pg54')] = function(_0x4e08d8) {
......
var _0x23a392 = arg1[_0x55f3('0x19', 'Pg54')]();
arg2 = _0x23a392[_0x55f3('0x1b', 'z5O&')](_0x5e8b26);
setTimeout('reload(arg2)', 0x66a);
};
在这里,我们可以发现,这里很多地方使用了第二部分的解密函数,那么,我们把它们放在一起,并将arg2返回。执行一下看看,
呃,这个参数是出来了,就不知道对不对。由于在编写过程中,多次请求,arg1早也发生变化,所以不能确定。
那么重新获取一下确定的值试试。
arg1参数:
var arg1='8ADE81CCE2F549649B0AF8E0372F79F2CBD7A216';
终端acw_sc__v2参数:
程序解析出来的参数:
对比下,看来是对的。
通过上面的程序分析与验证,那么就把代码改改,使用python执行了。
通过多次请求发现,反爬JS代码,参数变化只有arg1在一直变,其它都是固定的。
那么,我们只实现第三部分就行了,把第三部分需要的参数进行,修改比如_0x55f3,大数组。
那么结合python执行代码呗:
结果发现返回来是arg2空的,在浏览器控制台没问题,在python中运行有问题,那么唯一的解释是 execjs执行代码有问题,再改呗。
最后改成了这样:
返回打印下:
成功!
使用返回的acw_sc__v2值,再次访问试试:
成功!
参考:
https://github.com/insoxin/sojson.v5/blob/master/Ideas.md
https://mp.weixin.qq.com/s/mZ-MBC2KbIlbXIKvamwq7Q