补环境扣代码过瑞数4

参考网址:http://www.fangdi.com.cn/index.html

加密入口

正常F12会有两个debugger,直接永不在此暂停过掉

image-20230603104101440

image-20230603104232829

FSSBBIl1UgzbN7N80T 的值是4开头就是瑞数4的标志,我们直接用hook的形式去获取cookie

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
// ==UserScript==
// @name 获取cookie
// @namespace 42
// @version 0.1
// @description Hook Crypto
// @match http://www.fangdi.com.cn/*
// @grant none
// @run-at document-start
// ==/UserScript==

(function() {
// 严谨模式 检查所有错误
'use strict';
// document 为要hook的对象 这里是hook的cookie
var cookieTemp = "";
Object.defineProperty(document, 'cookie', {
// hook set方法也就是赋值的方法
set: function(val) {
// 这样就可以快速给下面这个代码行下断点
// 从而快速定位设置cookie的代码
console.log('Hook捕获到cookie设置->', val);
debugger;
cookieTemp = val;
return val;
},
// hook get 方法也就是取值的方法
get: function()
{
return cookieTemp;
}
});
})();

image-20230603104637975

这里是假cookie 真实的cookie是下面的 _$T4(768, 1)

image-20230603104825221

image-20230603104916069

真实cookie

image-20230603105544374

再下一个堆栈 我们能看到一个自执行的函数,然后再上一层,我们能看到一个eval.call方法 $7S.call(_$qn, _$Ha) ,执行之后就得到一个vm虚拟机的代码,就是上面的自执行代码,执行这里的代码 会生成我们要的80Tcookie

image-20230603105820731

当前页面是一个html页面,也就是抓包返回的202页面

image-20230603110055326

我们手动修改一下html页面,回到首页,选择html页面,保存以备替代,然后我们就可以再覆盖页面找到index.html

image-20230603110449688

image-20230603110958554

我们搜索一下 call 关键字,因为代码是会混淆,但是关键字不会,搜索出来只有一处,也就是上面的 $7S.call(_$qn, _$Ha),再拉到最上面,能看到它加载了一个js,上面还有一个meta标签,里面的内容是一段看不懂的代码,每次都是变化的。引用的 js文件 直接打开看是乱码的,而自执行 JS 的主要作用是将这 JS 乱码还原成 VM 里的 1w+ 行的正常代码,并且定义了一个全局变量 window.$_ts 并赋了许多值

image-20230603111111107

image-20230603113124060

我们添加一个脚本断点,刷新页面,多运行几次,最后来到这里,这里也就是202请求后返回的js文件,我们可以把它复制下来,也可以直接从抓包处下载,然后我们再把首页下面的js代码复制下来

image-20230603113251534

image-20230603114302640

image-20230603114523466

我们可以看到第一行代码有个 $_ts = window['$_ts'];,这个window.$_ts作用非常大,里面赋值了很多东西,我们可以运行一下,提示没有window,我们追着报错把需要的补上,一个是补window,一个是把eval方法给补上

image-20230603114855521

image-20230603125728891

image-20230603151744596

这里的目的是为了让加载的js代码以eval的形式执行出来

1
2
3
4
5
6
7
8
9
var eval_js = ''
window = {
$_ts: {},
eval: function (data) {
eval_js = data;
return {
toString: function () {
return eval_js;
}}}}

最后再打印一下,看下结果,和浏览器打印出来的结果一样,eval_js既是vm中的代码

image-20230603151852209

扣取流程

接着,我们回到cookie生成的位置,将这段代码扣下来,我们最终要的cookie是在这里生成的

image-20230603152520939

然后我们再看一下vm里面的代码,上面从$ts中取出了很多变量,并进行了赋值,这种赋值操作一直持续到了308行,我们把这些代码扣下来

image-20230603161439098

image-20230603161721158

随后 我们运行一下,报错,我们再网页看一下这个是什么,这里是以单引号的形式将传入的字符串进行分割,返回一个大数组,我们将这个方法扣下来,然后还有上面一个方法也要扣下来,这里每一次扣都需要小心,如果页面刷新了,就会导致代码不一样,所以最好不要刷新页面,

image-20230603162310820

image-20230603163537731

image-20230603163759707

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
function _$9o(_$XZ) {
var _$fw = _$XZ.length;
var _$_B, _$yV = new Array(_$fw - 1), _$Pp = _$XZ.charCodeAt(0) - 97;
for (var _$1C = 0, _$6e = 1; _$6e < _$fw; ++_$6e) {
_$_B = _$XZ.charCodeAt(_$6e);
if (_$_B >= 40 && _$_B < 92) {
_$_B += _$Pp;
if (_$_B >= 92)
_$_B = _$_B - 52;
} else if (_$_B >= 97 && _$_B < 127) {
_$_B += _$Pp;
if (_$_B >= 127)
_$_B = _$_B - 30;
}
_$yV[_$1C++] = _$_B;
}
return _$li.apply(null, _$yV);
}
// 分割函数 返回数组
function _$fw(_$XZ) {
var _$fw = _$li(96);
_$AE = _$9o(_$XZ).split(_$fw);
}

接着报错没有 location,我们再浏览器中找到对应代码,断点过来,能发现是window下面的top的location, 我们再控制台打印location并复制过来,然后再window变量下添加location

image-20230603164337760

image-20230603164831116

image-20230603164513643

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
location = {
"ancestorOrigins": {},
"href": "http://www.fangdi.com.cn/",
"origin": "http://www.fangdi.com.cn",
"protocol": "http:",
"host": "www.fangdi.com.cn",
"hostname": "www.fangdi.com.cn",
"port": "",
"pathname": "/",
"search": "",
"hash": ""
}
window = {
$_ts: {},
eval: function (data) {
eval_js = data;
return {
toString: function () {
return eval_js;
}
}
},
top: function (){
return location;
}
}

接着运行,补报错

接下来不在详细演示,这里提供报错的位置和需要注意的地方

190行 _$eB() 需要补充document 的 createElement方法,以及下面的 getElementsByTagName

image-20230603165937269

480行 _$7Q 报错 ,这里也是一大段赋值的操作,下面有一个大循环,也是vm生成的地方,所以把3200行以下的代码全部抠出来

image-20230603171757340

336 _$zk() 报错,需要再document下补characterSet方法 和 “charset”方法

image-20230603174703707

337、338 _$yH _$kS 补上就行

195 _$6t 196 _$Y2 _$Fn 顺便补上 window 下的addEventListener 和下面的 “attachEvent”

image-20230603185705753

830 _$iq[_$AE[21]] document 补上 getElementById

image-20230603190758814

202 _$vn(); 补上 localStorage

image-20230603191210872

203 _$Hj -> 1240 _$B7 _$OA _$4T _$T8 进去之后这些方法都没有,补上就行

image-20230603205814938

204 _$k7 没有的都补上

image-20230603210129456

212 _$Lu(); 213 _$FO() 218 _$HD 220 _$FJ _$Gg 这里需要再document下补上 getElementsByTagName 以及补上5个mate参数,最后一个是html页面meta标签加载的内容,同时还要再补上它的parentNode下的removeChild方法

image-20230603211744200

image-20230603211752502

image-20230603212726610

221 _$aN() 1462 _$kQ 1470 _$1E 1367 _$eL 正常补就行

223 _$Uf 不要将window下面三个属性给补上

image-20230603214836351

image-20230603215236521

image-20230603215434016

当我们打上断点进入 _$Uf 的 判断逻辑是,我们的代码并没有进入,而浏览器中则进入了if条件中

image-20230603215736453

image-20230603215811067

原因则在于 _$XZ 是window,而我们的window下的top并没有指向window,所以我们要用defineProperty 方法修改它

image-20230603220030089

image-20230603220056713

1
2
Object.defineProperty(window, "location", {value: location, writable: true, configurable: true});
Object.defineProperty(window, "top", {value: window, writable: true, configurable: true});

继续往下执行,浏览器中跳过了return,而我们这边则进入了return,原因在于我们上面传入的是个undefine,而实际上这里应该要是一个string,而这里是window.name,所以还需要再window下把name加上

image-20230603221748147

image-20230603221755826

image-20230603222039696

同样往下执行还有一个 openDatabase 需要补上,还有一个escape

image-20230603222714307

image-20230603222953537

接着 继续

228 _$xZ(); 229 _$nq _$Yd 236 _$a8 补上

image-20230603223507482

接下来 报错 userAgent,说明需要补上 navigator

image-20230603224018017

接着

4891 _$C_ 5068 _$0P _$VK 2333 _$ic 2337 _$f0 补上

然后,这是一个window下的定时器,我们没有,补上

image-20230603225609120

image-20230603225617896

继续

275 _$Mc 这一段代码比较长

这里是 addEventListener 和 attachEvent ,我们之前补了,但是是再window下,但是这里是再document,所以还需要再document下加上 addEventListener 和 attachEvent

image-20230603230255517

image-20230603230313923

继续,这里的所有方法都要补上

image-20230603230847682

继续

3606 _$Ia 3189 _$MT 305 _$MZ(); 同时在这里呢 document 下的getElementsByTagName需要再返回script数组,

image-20230603232600351

image-20230603232711503

308 _$FG(); 4956 _$3f 一直补,直到报错到这里,这里是window下没有math方法,需要补上

image-20230603233805785

image-20230603233840593

接着 ,这一段直接缺啥补啥就好,比较长,慢慢补,直到没有报错

3533 _$$r 3476 _$jK 4675 _$gp 2025 _$84 4716 _$q2 4047 _$kH 4838 _$Eo 1808 _$Xa 1821 _$kr

补的过程中需要慢慢调试,同时验证再node环境下的值和浏览器中的值是否存在差异

如果都没有问题,最终我们也是可以拿到cookie的

image-20230606145625194

由于代码太长,这里给到补充浏览器环境所需要的各项配置,需要注意的是,document 下 的 content和每次加载的js文件都需要再每次请求的时候进行替换,要不然生成的cookie没用

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
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
location = {
"ancestorOrigins": {},
"href": "http://www.fangdi.com.cn/",
"origin": "http://www.fangdi.com.cn",
"protocol": "http:",
"host": "www.fangdi.com.cn",
"hostname": "www.fangdi.com.cn",
"port": "",
"pathname": "/",
"search": "",
"hash": ""
}
navigator = {
appCodeName: "Mozilla",
appName: "Netscape",
appVersion: "5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.0.0 Safari/537.36 Edg/113.0.1774.57",
hardwareConcurrency: 16,
language: "zh-CN",
platform: "Win32",
product: "Gecko",
productSub: "20030107",
userAgent: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.0.0 Safari/537.36 Edg/113.0.1774.57",
vendor: "Google Inc.",
}

// document 下 的 content也是需要替换
window = {
$_ts: {},
name: "",
eval: function (data) {
eval_js = data;
return {
toString: function () {
return eval_js;
}
}
},
top: function () {
// return location;
},
document: {
createElement(tagName) {
if (tagName == "div") {
return {
getElementsByTagName: function (name) {
if (name == "i") {
return {
length: 0,
}
}
},
innerHTML: function () {
return ''
},
}
}
},
characterSet: "UTF-8",
charset: "UTF-8",
getElementById(elementId) {
if (elementId == "__anchor__") {
return null;
}
},
getElementsByTagName(name) {
if (name == "meta") {
return [
{"charset": "utf-8"},
{"http-equiv": "X-UA-Compatible"},
{"name": "keywords"},
{"name": "description"},
{
"content": "{qr0m26649qqq{EUN27LCj.RHAa_koLHI34Zs.qMxzj9bspieV.ucukQWAdnuMWHNz9bKnKhQg7nuBrQWQ6T1.Fqql3650Ddfe167qqr0c80qqVwcrmm9aVASpmll0AAfTW 0wR7HvJ6IsUC410DntKRngA;QyqA82EGtIB6ePNEeYo9NG;iEm6gdSTTpYiqU10OlvsnG;yMG8gk5okQ97gP4eb.IadA;T8F36FaS9AtR4sXBkRr0iG;RTlM3IYjAzboXbIiNSIFRA;t7_svh3Kc3.VU9jOjAJgdq;.8D9Zx78FrKF.Zn4xbfmIG;IMhCM7gXESIqShs5TNMo9A;pvBPF7OtrK6trS5vZYizwa;9qxqLXuEeDQeAlNfAL_l.A;VNeyFcNDtQZhV2sfCxyHqA;kT4JL2WRSOhvUIEcOjSrva;LpFhLGWYI8eFx_X999MLEq;NqssQaVItFB0TevtNxJrkG;AI3RN3R7lP0BBnYsoCO5KG;xrYRhwM6FYW7zCsPL.iecq;0kOXzZzt1eXLrlPo.QQ4xG;ApKNqLIRoybF5rIxSnabBG;hfgZrtz_KscdFC6a3f1wKA;qqr1QHzat_Gu9kiLWyaMYce3xTGOVre3oqqqqqqq|[tnz1ol251U0AYSSJ8YxMc9NZlGrP3prgpvJQ8bZk1qfGkTe7D07w3frwDvA8JmSSUop08DEfKc2cIVEPKcpcQbeu8STIcCwCIP98JK3Llkx1JKmL3pf1ovl_IkrnW27JArz3o2e2RuJjRVq71GNJrmaJAGYrkYaqlcrgJD9j3GVFH0ap11EQESrF8GTerDLT1pSvxKEUlkSXqVQlAfwQA9fVMAJfrbSEDuGmD062D.QQzaUNKheHjC653IT7BpBHr8yJ4fj_ohGmymP0AQQ3jl4L1Qp4yfcfKwSzZf6nRwV8jmXGIip55f49UezDnpqqqYRM5rqL0xDyPmOGCbasu1_qqqqqqqJ1685761368038lVi2dqqhiSSIxIXI1snKF6Pp3Df75MVnHdkzCHw8hqqqt10747904641mUZ_mvB9QH94_boX8Aqqk162iE9VAIpwSmolp8aq!x7z,aac,amr,asm,avi,bak,bat,bmp,bin,c,cab,css,csv,com,cpp,dat,dll,doc,dot,docx,exe,eot,fla,flc,fon,fot,font,gdb,gif,gz,gho,hlp,hpp,htc,ico,ini,inf,ins,iso,js,jar,jpg,jpeg,json,java,lib,log,mid,mp4,mpa,m4a,mp3,mpg,mkv,mod,mov,mim,mpp,msi,mpeg,obj,ocx,ogg,olb,ole,otf,py,pyc,pas,pgm,ppm,pps,ppt,pdf,pptx,png,pic,pli,psd,qif,qtx,ra,rm,ram,rmvb,reg,res,rtf,rar,so,sbl,sfx,swa,swf,svg,sys,tar,taz,tif,tiff,torrent,txt,ttf,vsd,vss,vsw,vxd,woff,woff2,wmv,wma,wav,wps,xbm,xpm,xls,xlsx,xsl,xml,z,zip,apk,plist,ipahSFsIYTX_uWUkxbWqql4096qqq",
parentNode: {
removeChild: function (name) {
}
}
},
]
} else if (name == "script") {
return [{
'type': "text/javascript",
'charset': "iso-8859-1",
'src': "/4QbVtADbnLVIc/d.FxJzG50F.dfe1675.js",
'r': "m",
getAttribute: function (data) {
return "m"

},
parentElement: {
removeChild: function () {
}
},

},
{
'type': "text/javascript", 'r': "m",
getAttribute: function (data) {
return "m"

}, parentElement: {
removeChild: function () {
}
},
}]
}
},
addEventListener(type, listener, options) {
// listener();
eval(listener);
},
attachEvent(type, listener) {
eval(listener);
},
},
addEventListener(type, listener, options) {
eval(listener);
},
attachEvent(type, listener) {
eval(listener);
},
localStorage: {
"__#classType": "localStorage",
getItem(key) {
return this[key]
},
setItem(key, value) {
return this[key] = value;
},
removeItem(key) {
return delete this[key];
}
},
sessionStorage: {
getItem(key) {
return this[key]
},
setItem(key, value) {
return this[key] = value;
},
removeItem(key) {
return delete this[key];
}
},
indexedDB: {},
openDatabase: function (a, b, c, d) {
return {
version: "",
}
},
escape: function (data) {
return escape(data);
},
navigator: navigator,
setInterval: function (func, time) {
eval(func)
},
Math: Math,

}
Object.defineProperty(window, "location", {value: location, writable: true, configurable: true});
Object.defineProperty(window, "top", {value: window, writable: true, configurable: true});

image-20230606145142133