参考文章:
1.猿人学爬虫攻防赛 第10题
2.某数和某5秒-反混淆动态注入调试的一种方案
样品网址:https://match.yuanrenxue.com/match/10
打开首页后直接就有5处混淆,第一处是某数套 jsjiami.com.v6,然后后面4处为obfuscator
首先还原这一段jsjiamiv6的混淆,还原后的结果如下
let yuanrenxue_36 = '';
var yuanrenxue_59 = 968;
for (let yuanrenxue_229 = 0; yuanrenxue_229
可以大概看出其中的逻辑主要是对$_ts["dfe1683"]进行解密,接着还原rs的混淆
*******省略很多代码*******
case 29:
yuanrenxue_48.yuanrenxue_110 = new Date().getTime();
var yuanrenxue_35 = yuanrenxue_48["dfe1675"];
yuanrenxue_48["dfe1675"] = yuanrenxue_40;
var yuanrenxue_91 = yuanrenxue_48.yuanrenxue_yuanrenxue_126;
var yuanrenxue_13 = yuanrenxue_31(8);
var yuanrenxue_21 = yuanrenxue_31(8);
var yuanrenxue_15 = yuanrenxue_48.aebi = [];
var yuanrenxue_88 = yuanrenxue_31(71);
var yuanrenxue_65 = yuanrenxue_35.length;
var yuanrenxue_1 = 0;
var yuanrenxue_89 = yuanrenxue_12();
var yuanrenxue_54 = yuanrenxue_12();
var yuanrenxue_67 = yuanrenxue_12();
var yuanrenxue_72 = yuanrenxue_12();
var yuanrenxue_105 = yuanrenxue_12();
yuanrenxue_14 = yuanrenxue_12();
var yuanrenxue_28 = yuanrenxue_12();
if (yuanrenxue_14 > 0) {
yuanrenxue_96 = yuanrenxue_35.substr(yuanrenxue_1, yuanrenxue_28).split(String.fromCharCode(255));
}
yuanrenxue_1 += yuanrenxue_28;
var yuanrenxue_56 = [];
var yuanrenxue_14 = yuanrenxue_12();
for (yuanrenxue_24 = 0; yuanrenxue_24 12000) {
yuanrenxue_48.yuanrenxue_74 = 1;
}
return;
*******省略很多代码*******
整个代码比较多,只贴上部分代码,可以看到["dfe1675"]解密后的代码赋值给了yuanrenxue_18 ,接着["dfe1683"]解密后的代码也是直接赋值给了yuanrenxue_18 ,相当于覆盖了,所以前面的一部分代码就不需要看了,根本没有执行。
接着后面还有4个ob混淆,但是里面的代码并不重要,只是反调试有点烦人,那么接着看yuanrenxue_18的代码,连续拿到两次yuanrenxue_18的代码,查看变化,发现有三处
这里都与后面的一个接口 https://match.yuanrenxue.com/api/offset 的返回值息息相关,说明这个值也是非常重要的。到这里还是没有找到加密参数生成的入口,但是请求发出的事情,参数就自动生成了,那么很有可能xhr下的open,send等方法被改写了
这就可以知道,参数是通过_yrxyA$函数生成的,使用ast在这个函数的结尾动态注入一个【console.log(_yrx2LR);】
这样当我们调用open方法的时候,就可以获取包含加密参数的最终链接,最后使用jsdom把代码跑起来,需要先安装依赖库
npm install jsdom
import requests_html
import json
import re
import base64
import subprocess
import os
import logging
logging.disable(logging.INFO)
def main():
requests = requests_html.HTMLSession()
headers = {
'User-Agent': 'yuanrenxue.project',
'Referer': 'https://match.yuanrenxue.com/match/10',
'X-Requested-With': 'XMLHttpRequest'
}
base_url = 'https://match.yuanrenxue.com'
top_url = base_url + '/match/10'
response = requests.get(top_url, headers=headers)
script = response.html.find('script')
ts_1_url = base_url + script[0].attrs['src']
ts_2_url = base_url + script[1].attrs['src']
ts_3_url = base_url + '/api/offset'
with open('config.json', 'w', encoding='utf-8') as f:
f.write(json.dumps({
'html': response.content.decode(),
'url': 'https://match.yuanrenxue.com/match/10'
}))
with open('html.html', 'wb') as f:
f.write(response.content)
yuanrenxue_59 = int(re.findall('(?
这里因为每次请求接口都会返回一个新的offset,所以这里每次请求后都需要重新加载
非常好,可以成功请求5页的数据了。当然,这个方法运用在真实某数下也是可以的,例子如下
RS4代混淆
*******省略很多代码*******
case 78:
if (_$JX === undefined || _$JX === "") {
return;
}
if (_$8k.execScript) {
ret = _$8k.execScript(_$JX);
return ret;
}
_$YA = _$8k.eval;
ret = _$YA.call(_$8k, _$JX);
return ret;
*******省略很多代码*******
RS5代混淆
*******省略很多代码*******
case 73:
if (_$r1 === undefined || _$r1 === "") {
return;
}
var _$_P;
if (_$Z8["execScript"]) {
_$_P = _$Z8["execScript"](_$r1);
return _$_P;
}
_$RD = _$Z8["eval"];
_$_P = _$RD["call"](_$Z8, _$r1);
return _$_P;
*******省略很多代码*******
RS6代混淆
*******省略很多代码*******
case 101:
_$_r = undefined;
if (_$hi === _$_r || _$hi === "") {
return;
}
_$_r = _$fx;
if (_$_r.execScript) {
_$_n = _$_r.execScript(_$hi);
return _$_n;
}
_$_d = _$_r.eval;
_$_n = _$_d.call(_$_r, _$hi);
return _$_n;
case 41:
_$_n = _$$X(38);
_$_d = _$_z;
_$cq = _$_d.nsd;
_$$7 = _$by;
_$_d.lcd = _$$7;
_$_d.nsd = _$$7;
_$cy = _$$X(114, _$cq);
_$bb = _$$X(0, 711, _$$X(114, _$cq));
_$$d = [];
_$_d.cp = _$$d;
_$$d[1] = _$bb;
_$aJ = _$_d.aebi = [];
_$_d.scj = [{
"0": 0,
"1": 1,
"2": 2,
"3": 3
}, {
"0": 0,
"1": 0,
"2": 0,
"3": 0,
"4": 0
}, {
"0": 0,
"1": -545,
"2": -538,
"3": 174
}, {
"0": 0,
"1": 3,
"2": 3,
"3": 0,
"4": 0,
"5": -241,
"6": -241
}];
_$d8 = "省略代码";
_$g$ = _$d8.length;
_$_t = 0;
_$$d[0] = "省略代码";
_$$d[2] = "省略代码";
_$$d[6] = "";
_$$r = _$_R();
_$$n = _$_R();
_$$b = _$_R();
_$er = _$_R();
_$dp = _$_R();
_$a5 = _$_R();
_$iH = _$_R() * 55295 + _$_R();
_$_d = _$bF;
if (_$a5 > 0) {
_$gj = _$d8.substr(_$_t, _$iH).split(_$_d.fromCharCode(257));
}
_$_t += _$iH;
_$a5 = _$_R();
_$aN = 0;
for (; _$aN