提前说一句: 所有版本均可rpc通杀,一键注入、高并发采集;但是吃机器性能、不太方便,不过是一个很好的临时方案。

这里主要说明补环境方案

Rs5

网址 : aHR0cHM6Ly9iaWRkaW5nLnN5c3UuZWR1LmNuL2luZm9ybWF0aW9uL25vdGljZQ==

Rs5 Cookie分析

ZMRhjlxmTSDe443S: 第一次请求返回。

ghDuiPNsEBSVMaMDUj1PvfwD5Mque8iERsLq96oHPxWAF6P0w79j2_mJj.mLFgiH

ZMRhjlxmTSDe443T:第一次请求返回来的content、自执行函数、和ts.js文件生成,瑞数核心算法、环境检测,全在这里头了。

5l_Zh6CRXjrzYnAPT8.zBxJDG8x4QNmVP5QxNzVbvNSdn_ALUFyqlPqgpo6UpYHYnemQNsm6B9iKxIHk6bMQOq_eqA7PTmdW87OH4FjPVprz0bxrsdoz0Fsls_SEkVsdAaXoFQMo3OuPyipFiN7HW4v3BXexJxkCBkbW_NqckT46BgVnAx1L1pvVRb2T6aKal47UFV3YUMLbsCMXBWtW4rICVpO79DWW_zBqB.v.KkMdRBvzXl.VEM.9rnZ9dv1bjQq4WM7XR9yUMnQzsC03J9XyATeNU8TvtWTQHcmKkPEyXZLI75euA.8C54_CnOslc5.R62X5CRar55FGdcgYWN9UR

请求流程

第一次请求

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
url = 'https://bidding.sysu.edu.cn/information/notice'
headers = {
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7',
'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8',
'Cache-Control': 'no-cache',
'Connection': 'keep-alive',
'Pragma': 'no-cache',
'Referer': 'https://bidding.sysu.edu.cn/information/notice?page=1',
'Sec-Fetch-Dest': 'document',
'Sec-Fetch-Mode': 'navigate',
'Sec-Fetch-Site': 'same-origin',
'Sec-Fetch-User': '?1',
'Upgrade-Insecure-Requests': '1',
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36',
'sec-ch-ua': '"Chromium";v="118", "Google Chrome";v="118", "Not=A?Brand";v="99"',
'sec-ch-ua-mobile': '?0',
'sec-ch-ua-platform': '"macOS"',
}

response = session.get(
url,
cookies=cookies,
headers=headers

)
response.encoding = response.apparent_encoding
print('第一次请求状态码---->',response.status_code)
cookies = response.cookies.get_dict()
Str = response.text
with open('固定.html','w',encoding='utf8') as f:
f.write(Str)

返回状态码是412

返回的文本如下

image-20231028172417957

我们提取出 content,auto_js,ts_url

1
2
3
4
5
6
# 匹配出content
content = re.findall('<meta content="(.*?)"', Str)[0] # content
auto_js = re.findall('r="m">(\(function\(\).*?)</script>', Str,re.S|re.I)[0] # 自执行函数
ts_url = re.findall('src="(.*?js)" r=',Str,re.S|re.I)[0] # js文件
ts_url = f'https://bidding.sysu.edu.cn{ts_url}'
logger.debug(f'ts_url:{ts_url}')

下一步就是结合这三个条件,生成我们要的ZMRhjlxmTSDe443T打出第二次请求

补环境结构

env就是我们要补的环境,nodejs 执行这段代码后,会对document.cookie赋值,也就是ZMRhjlxmTSDe443T,我们导出即可

image-20231028172945103

补环境过程

首先把content、自执行函数、ts文件放入js代码中,这步很简单,会复制粘贴就行

image-20231028173420494

我们只需要在补环境那块,填入我们的环境代码即可。

那么,现在开始正式补环境!

首先,最基本的,window location document navigator 先补进去

location我们把最常见的那几个维度的字段,先提前补进去

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
setInterval = function(){};
setTimeout = function(){};
window = global;
window.top = window;
window.self = window;
location = {
href: 'https://bidding.sysu.edu.cn/information/notice?page=1',
protocol: "https:",
origin: "https://bidding.sysu.edu.cn",
hostname: "bidding.sysu.edu.cn",
port: "",
host: "bidding.sysu.edu.cn",
search: "?page=1",
hash: "",
pathname: "/information/notice",
};
navigator = {
userAgent:
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36',
webdriver: false,
platform: "MacIntel",
languages: ["zh-CN", "zh", "en"],
appVersion:
"5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36",
webkitPersistentStorage: {},
getBattery: function(){console.log('navigator.getBattery--->',arguments);},
connection: {
downlink: 1.3,
effectiveType: "3g",
rtt: 550,
saveData: false,
},
};
document = {
charset: "UTF-8",
characterSet: "UTF-8",
};

不管哪个版本的瑞数,我们都能这样先补一下

然后上代理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
window = new Proxy(window, {
set(target, property, value, receiver) {

console.log("设置属性set window", property, typeof value);
return Reflect.set(...arguments);
},
get(target, property, receiver) {

console.log("获取属性get window", property, typeof target[property]);
if (target[property]==undefined){
// debugger;
}
return target[property]
}
});

function proxy(proxy_array) {
for (let i = 0; i < proxy_array.length; i++) {
eval(
proxy_array[i] +
`= new Proxy(` +
proxy_array[i] +
`, {
get(target, key) {
if(key == 'parentElement'){
// debugger;
}
console.log('----------------------')
console.log( '【` +
proxy_array[i] +
`】取属性 ' + key + ' 值: ' + target[key] + ', 详细位置debugger查看');
console.log('----------------------')
if (target[key]==clearInterval){
debugger;
}
return target[key];
}
});`
);
}
}
// 数组中放入需要代理的对象
var proxy_array = [
"document",
"navigator",
"location",
];
proxy(proxy_array);

代理也是固定的,放到补的环境下面即可

下一步,开始调试,mac用户按 fn+F5开始调试即可

提前约定一下,遇到如下图这种windows 某个属性 undefind的,如果是函数,我们就暂时补充一个空函数,打印入参即可,如果是字段,先去官网调试下是什么类型的,一般就是对象类型或者字符串,直接补空的即可。

如果是$开头的属性呢,直接跳过就好啦,因为正常来说windows 不会有这些属性

image-20231028174313663

例如上图,我们就可以这么补

1
2
3
window.execScript = eval;
window.XMLHttpRequest = function(){console.log('window.XMLHttpRequest--->',arguments);};
window.ActiveXObject = function(){console.log('window.ActiveXObject--->',arguments);};

后面会有一堆这种的,我就不在一个个说了

补完继续调试

image-20231028174734620

很明显了,需要补document.createElement

我们先定义一个createElement,然后打印参数,看看需要补那些参数

1
2
3
4
var createElement = function(){
console.log('createElement传入参数--->',arguments);
}
document.createElement = createElement;

image-20231028174951903

是不是很明显了,传入了div,那我们就要模拟出来一个在传入div时候的返回值

然后注意到缺失了getElementsByTagName

我来说下怎么回事:

正常流程是:createElement会创建一个div对象,然后div对象又执行了它的getElementsByTagName函数

现在是:createElement什么都没返回,默认返回了undefind,就导致拿不到getElementsByTagName这个函数了

我们可以这样做

1
2
3
4
5
6
7
8
9
var div  = {
}
var createElement = function(){
console.log('createElement传入参数--->',arguments);
switch(arguments[0]){
case 'div':
return div
}
}

同时,我们把div加入监控数组

1
2
3
4
5
6
7
8
// 数组中放入需要代理的对象
var proxy_array = [
"document",
"navigator",
"location",
"div"
];
proxy(proxy_array);

再次执行

image-20231028175346688

对吧,让我们直接补一个getElementsByTagName,再让它是div的一个属性即可

1
2
3
4
var getElementsByTagName = function(){
console.log('getElementsByTagName传入参数--->',arguments);
}
div.getElementsByTagName = getElementsByTagName;

再次执行

image-20231028175456199

我们可以看到getElementsByTagName原本是传入了一个i参数,然后返回了一个列表对象(getElementsByTagName,注意带s,返回的是列表)

后续在取对象第0个元素时候,取不到,于是就报了这个reading ‘0’的错误~

很简单,我们直接补一个返回值即可

1
2
3
4
5
6
7
var getElementsByTagName = function(){
console.log('getElementsByTagName传入参数--->',arguments);
switch(arguments[0]){
case 'i':
return [];
}
}

那,我们应该怎么补返回值呢,列表里到底要写什么,这个暂时不清楚。

遇到这种情况,我们可以写一份hook代码,看看浏览器的真实环境是怎么执行的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
 // 保存原始的getElementsByTagName函数
const originalGetElementsByTagName = document.getElementsByTagName;

// 创建一个新的钩子函数
document.getElementsByTagName = function(tagName) {
// 打印入参


// 调用原始的getElementsByTagName函数获取元素
const elements = originalGetElementsByTagName.apply(this, arguments);

// 结束打印
if (tagName=='i'){
console.log('调用getElementsByTagName,参数:', tagName);
console.log('获取的元素:', elements);
}


// 返回获取的元素
return elements;
};

// 示例用法
const divElements = document.getElementsByTagName('div');

image-20231028175833829

这个hook代码到后面还有用,我们后面要常用的

那么刷新浏览器之后什么都没输出,那么我们直接让它返回[]就好了,然后继续下一步

image-20231028180027781

前面说过了,直接补

1
2
3
window.addEventListener = function(){console.log('window.addEventListener--->',arguments);};
window.attachEvent = function(){console.log('window.attachEvent--->',arguments);};
window.localStorage = {};

image-20231028180139135直接补

1
document.getElementsByTagName = getElementsByTagName;

image-20231028180224260

这里的meta,参照div的补法即可

image-20231028180337701

补content,parentNode即可

1
2
3
4
5
6
var meta = {
content:content,

parentNode:parentNode

}

image-20231028180509248这里看到对parentNode取了什么值,我们调试看一下是什么,这里的debugger打开

image-20231028180631386

image-20231028180658266

image-20231028180712084

很明显,我们补一个removeChild即可

1
2
3
4
5
var parentNode = {
removeChild:function(){
console.log('removeChild传入参数--->',arguments);
}
}

image-20231028180851008

直接补

1
2
3
document.addEventListener = function(){console.log('document.addEventListener--->',arguments);};
document.attachEvent = function(){console.log('document.attachEvent--->',arguments);};
document.documentElement= {};

image-20231028181016273

按照之前的方式补

image-20231028181112258

直接补

image-20231028181221768

先看第一个: base的href属性到底是什么,这里我们浏览器hook调试一下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
 // 保存原始的getElementsByTagName函数
const originalGetElementsByTagName = document.getElementsByTagName;

// 创建一个新的钩子函数
document.getElementsByTagName = function(tagName) {
// 打印入参


// 调用原始的getElementsByTagName函数获取元素
const elements = originalGetElementsByTagName.apply(this, arguments);

// 结束打印
if (tagName=='base'){
console.log('调用getElementsByTagName,参数:', tagName);
console.log('获取的元素:', elements[0].getAttribute('href'));
}


// 返回获取的元素
return elements;
};

// 示例用法
const divElements = document.getElementsByTagName('div');

image-20231028181340445找不到,那就不补了

补第二个

1
2
3
4
5
var getElementById= function(){
console.log('getElementById传入参数--->',arguments);
}
document.getElementById = getElementById;

补第三个

image-20231028181541900

直接补

1
2
3
4
5
6
var script = {
getAttribute:function(){
console.log('getAttribute传入参数--->',arguments);
}

}

出值了

image-20231028181647292

中间其实也有一些undefind的,比如

image-20231028181737981

我们hook一下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
 // 保存原始的getElementsByTagName函数
const originalGetElementsByTagName = document.getElementsByTagName;

// 创建一个新的钩子函数
document.getElementsByTagName = function(tagName) {
// 打印入参


// 调用原始的getElementsByTagName函数获取元素
const elements = originalGetElementsByTagName.apply(this, arguments);

// 结束打印
if (tagName=='script'){
console.log('调用getElementsByTagName,参数:', tagName);
console.log('获取的元素:', elements[0].getAttribute('r'));
}


// 返回获取的元素
return elements;
};

// 示例用法
const divElements = document.getElementsByTagName('div');

image-20231028181825743

直接补

1
2
3
4
5
6
7
var script = {
getAttribute:function(){
console.log('getAttribute传入参数--->',arguments);
return 'm'
}

}

image-20231028181929675

直接补

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var script = {
getAttribute:function(){
console.log('getAttribute传入参数--->',arguments);
switch(arguments[0]){
case 'r':
return 'm'
}
},
parentElement:{
removeChild:function(){
console.log('removeChild传入参数--->',arguments);
}
}

}

image-20231028182010411

再次出值

我们拿着环境测试一下

image-20231028182147320很不幸,还是400

这时候我们回头把window那些空的属性再过一遍就好了,比如

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
window.name = '';
window.globalStorage = {};

window.indexedDB = {};
window.mozIndexedDB = {};
window.webkitIndexedDB = {};
window.msIndexedDB = {};
window.PointerEvent = function(){console.log('window.PointerEvent--->',arguments);};
window.jesion = {};
window.chrome = {
"app": {
"isInstalled": false,
"InstallState": {
"DISABLED": "disabled",
"INSTALLED": "installed",
"NOT_INSTALLED": "not_installed"
},
"RunningState": {
"CANNOT_RUN": "cannot_run",
"READY_TO_RUN": "ready_to_run",
"RUNNING": "running"
}
}
};
window.Gamepad = function(){console.log('window.Gamepad--->',arguments);};
window.webkitRequestFileSystem = function(){console.log('window.webkitRequestFileSystem--->',arguments);};
window.openDatabase = function(){console.log('window.openDatabase--->',arguments);};

image-20231028182314986

第二次返回200,成功~

至此,Rs5补环境结束

补充

Rs6补环境和Rs vmp补环境就不会再说这么多细节了,会侧重一些特殊的环境检测。

未经允许禁止转载哦

作者:Nohup