├── CatVm2
├── browser
│ ├── Document.js
│ ├── EventTarget.js
│ ├── HTMLDocument.js
│ ├── HTMLElements
│ │ ├── HTMLDivElement.js
│ │ └── htmlelement.node.js
│ ├── History.js
│ ├── Location.js
│ ├── MimeType.js
│ ├── MimeTypeArray.js
│ ├── Navigator.js
│ ├── Plugin.js
│ ├── PluginArray.js
│ ├── Screen.js
│ ├── Storage.js
│ ├── Window.js
│ └── WindowProperties.js
├── catvm2.node.js
└── tools
│ ├── tools.node.js
│ ├── vm_memory.js
│ ├── vm_print.js
│ ├── vm_proxy.js
│ └── vm_safefunction.js
├── README.md
├── __bak
├── step.js
├── tools.js
├── window.js
└── window_bak.js
├── debugger_bak.js
├── index.js
└── 补环境框架项目结构.png
/CatVm2/browser/Document.js:
--------------------------------------------------------------------------------
1 | // 从浏览器中知道Document是全局的,new Document会返回一个对象
2 | var Document = function Document() { // 构造函数
3 | };
4 | catvm.safefunction(Document);
5 | // 浏览器
6 | Object.defineProperties(Document.prototype, {
7 | [Symbol.toStringTag]: {
8 | value: "Document",
9 | configurable: true
10 | }
11 | });
12 | document = {};
13 | document.__proto__ = Document.prototype;
14 |
15 | ////////// 浏览器代码自动生成部分
16 | document.cookie = '';
17 | document.referrer = location.href || '';
18 | document.getElementById = function getElementById(id) {
19 | debugger;
20 | // 用id匹配当前环境内存中已有的Element,没找到则返回null
21 | return null;
22 | };
23 | catvm.safefunction(document.getElementById);
24 |
25 | document.getElementsByTagName = function getElementsByTagName(tag_name) {
26 | var map_tag = {'body': ["
"]};
27 | debugger;
28 | return map_tag[tag_name]
29 | };
30 | catvm.safefunction(document.getElementsByTagName);
31 |
32 |
33 | document.addEventListener = function addEventListener(type, listener, options, useCapture) {
34 | debugger;
35 | };
36 | catvm.safefunction(document.addEventListener);
37 |
38 |
39 | document.createElement = function createElement(tagName) {
40 | tagName = tagName.toLowerCase();
41 | if (catvm.memory.htmlelements[tagName] == undefined) {
42 | debugger;
43 | } else {
44 | var tagElement = catvm.memory.htmlelements[tagName]();
45 | return catvm.proxy(tagElement);
46 | }
47 | };
48 | catvm.safefunction(document.createElement);
49 | ////////
50 | // 浏览器中document是全局的,因此我们也需要定义一个document
51 |
52 | document = catvm.proxy(document);
53 |
54 |
--------------------------------------------------------------------------------
/CatVm2/browser/EventTarget.js:
--------------------------------------------------------------------------------
1 | var EventTarget = function EventTarget() { // 构造函数
2 |
3 | };
4 | catvm.safefunction(EventTarget);
5 |
6 | // 因为EventTarget是构造函数,而我们要的是原型,因此需要先hook EventTarget.prototype,设置下原型的名字,否则它会使用父亲的名字
7 | Object.defineProperties(EventTarget.prototype, {
8 | [Symbol.toStringTag]: {
9 | value: "EventTarget",
10 | configurable: true
11 | }
12 | })
13 |
14 | EventTarget.prototype.addEventListener = function addEventListener(type,callback) {
15 | debugger; //debugger的意义在于检测到是否检测了该方法
16 | if(!(type in catvm.memory.listeners)){
17 | catvm.memory.listeners[type] = [];
18 | }
19 | catvm.memory.listeners[type].push(callback);
20 | };
21 | catvm.safefunction(EventTarget.prototype.addEventListener);
22 |
23 | EventTarget.prototype.dispatchEvent = function dispatchEvent() {
24 | debugger;
25 | };
26 | catvm.safefunction(EventTarget.prototype.dispatchEvent);
27 |
28 | EventTarget.prototype.removeEventListener = function removeEventListener() {
29 | debugger;
30 | };
31 | catvm.safefunction(EventTarget.prototype.removeEventListener);
32 |
33 | // EventTarget = catvm.proxy(EventTarget);
34 | // EventTarget.prototype = catvm.proxy(EventTarget.prototype);
--------------------------------------------------------------------------------
/CatVm2/browser/HTMLDocument.js:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Big1moster/catvm/d843fcb236f78db4226327a7667217bcd11b8f02/CatVm2/browser/HTMLDocument.js
--------------------------------------------------------------------------------
/CatVm2/browser/HTMLElements/HTMLDivElement.js:
--------------------------------------------------------------------------------
1 | var HTMLDivElement = function HTMLDivElement() { // 构造函数
2 | throw new TypeError("Illegal constructor");
3 | };
4 | catvm.safefunction(HTMLDivElement);
5 |
6 | Object.defineProperties(HTMLDivElement.prototype, {
7 | [Symbol.toStringTag]: {
8 | value: "HTMLDivElement",
9 | configurable: true
10 | }
11 | });
12 | ////////// 浏览器代码自动生成部分
13 |
14 | ////////
15 |
16 |
17 |
18 | // 用户创建div
19 | catvm.memory.htmlelements["div"] = function () {
20 | var div = new (function () {});
21 | //////////////////////////////////////////
22 | div.align = "";
23 | /////////////////////////
24 | div.__proto__ = HTMLDivElement.prototype;
25 | return div;
26 | }
27 |
28 |
--------------------------------------------------------------------------------
/CatVm2/browser/HTMLElements/htmlelement.node.js:
--------------------------------------------------------------------------------
1 | // .node.js文件的用途就是拼接多个文件的js代码
2 | var fs = require('fs');
3 |
4 | function GetCode() {
5 | var code = ""
6 | code += fs.readFileSync(`${__dirname}/HTMLDivElement.js`) + '\r\n';
7 | // code += fs.readFileSync(`${__dirname}/vm_safefunction.js`) + '\r\n';
8 | // code += fs.readFileSync(`${__dirname}/vm_print.js`) + '\r\n';
9 | // code += fs.readFileSync(`${__dirname}/vm_proxy.js`) + '\r\n';
10 | return code;
11 |
12 | }
13 | module.exports = {
14 | GetCode
15 | }
--------------------------------------------------------------------------------
/CatVm2/browser/History.js:
--------------------------------------------------------------------------------
1 | // 从浏览器中知道History是全局的,且原型链只是一层,因此比较好伪造(window有多层所以要伪造多层)
2 | // 浏览器中new会报错,因此我们此处也需要报错
3 | var History = function History() { // 构造函数
4 | throw new TypeError("Illegal constructor");
5 | };
6 | catvm.safefunction(History);
7 | // 浏览器
8 | Object.defineProperties(History.prototype, {
9 | [Symbol.toStringTag]: {
10 | value: "History",
11 | configurable: true
12 | }
13 | });
14 |
15 | history = {
16 | length: 1,
17 | };
18 | history.__proto__ = History.prototype;
19 | ////////// 浏览器代码自动生成部分
20 | History.prototype.back = function back() {
21 | debugger;
22 | };
23 | catvm.proxy(History.prototype.back);
24 | ////////
25 | // 浏览器中history是全局的,因此我们也需要定义一个history
26 |
27 | history = catvm.proxy(history);
28 |
29 |
--------------------------------------------------------------------------------
/CatVm2/browser/Location.js:
--------------------------------------------------------------------------------
1 | var Location = function Location() { // 构造函数
2 | throw new TypeError("Illegal constructor");
3 | };
4 | catvm.safefunction(Location);
5 |
6 | Object.defineProperties(Location.prototype, {
7 | [Symbol.toStringTag]: {
8 | value: "Location",
9 | configurable: true
10 | }
11 | });
12 | location = {};
13 | location.__proto__ = Location.prototype;
14 |
15 | ////////// 浏览器代码自动生成部分
16 | location.href = "https://www.baidu.com";
17 | location.port = "";
18 | location.protocol = 'https:';
19 | location.host = 'www.baidu.com';
20 | ////////
21 |
22 |
23 | location = catvm.proxy(location);
24 |
25 |
--------------------------------------------------------------------------------
/CatVm2/browser/MimeType.js:
--------------------------------------------------------------------------------
1 | // 存储一些值,避免污染全局变量空间
2 | catvm.memory.mimetype = {};
3 |
4 | var MimeType = function MimeType() { // 构造函数
5 | throw new TypeError("Illegal constructor");
6 | };
7 | catvm.safefunction(MimeType);
8 |
9 |
10 |
11 | Object.defineProperties(MimeType.prototype, {
12 | [Symbol.toStringTag]: {
13 | value: "MimeType",
14 | configurable: true
15 | },
16 | });
17 |
18 | ////////// 浏览器代码自动生成部分
19 | MimeType.prototype.description = "";
20 | MimeType.prototype.enabledPlugin = null;
21 | MimeType.prototype.suffixes = "";
22 | MimeType.prototype.type = "";
23 |
24 | for (var _prototype in MimeType.prototype) {
25 | if (typeof (MimeType.prototype[_prototype]) != "function") {
26 | // 相当于Object.defineProperty的get方法,Proxy的get方法,hook原型上的所有方法属性
27 | MimeType.prototype.__defineGetter__(_prototype, function () {
28 | throw new TypeError("Illegal constructor");
29 | });
30 | }
31 | }
32 |
33 | ////////
34 | catvm.memory.mimetype.new = function (data,initPlugin) {
35 | var mimetype = {};
36 | if (data != undefined) {
37 | mimetype.description = data.description;
38 | mimetype.enabledPlugin = initPlugin; // plugin实例
39 | mimetype.suffixes = data.suffixes;
40 | mimetype.type = data.type;
41 | }
42 | // 先赋完值,在指向原型
43 | mimetype.__proto__ = MimeType.prototype;
44 | return mimetype;
45 | };
46 |
47 | // 代理一般挂在实例上
48 | navigator.plugins = catvm.proxy(navigator.plugins);
49 |
50 |
--------------------------------------------------------------------------------
/CatVm2/browser/MimeTypeArray.js:
--------------------------------------------------------------------------------
1 | // 存储一些值,避免污染全局变量空间
2 | catvm.memory.MimeTypeArray = {};
3 | // MimeTypeArray实例,MimeTypeArray这个虽然跟MimeType很像,但是无需被new,浏览器一开始就有该实例 navigator.mimeTypes
4 | catvm.memory.MimeTypeArray._ = {};
5 |
6 |
7 | var MimeTypeArray = function MimeTypeArray() { // 构造函数
8 | throw new TypeError("Illegal constructor");
9 | };
10 | catvm.safefunction(MimeTypeArray);
11 |
12 |
13 | catvm.memory.MimeTypeArray.iterator = function values() {
14 | debugger;
15 | return {
16 | next:function () {
17 | if(this.index_ == undefined){
18 | this.index_ = 0;
19 | }
20 | var tmp = this.self_[this.index_];
21 | this.index_ += 1;
22 | return {value:tmp,done:tmp==undefined};
23 | },
24 | self_:this
25 | }
26 | };
27 | catvm.safefunction(catvm.memory.MimeTypeArray.iterator);
28 |
29 | Object.defineProperties(MimeTypeArray.prototype, {
30 | [Symbol.toStringTag]: {
31 | value: "MimeTypeArray",
32 | configurable: true
33 | },
34 | // 原型上多了个这个,里面是个方法
35 | [Symbol.iterator]: {
36 | value: catvm.memory.MimeTypeArray.iterator,
37 | configurable: true
38 | }
39 | });
40 |
41 | ////////// ///////////////////浏览器代码自动生成部分
42 | MimeTypeArray.prototype.length = 0;
43 | MimeTypeArray.prototype.item = function item(index) {
44 | // debugger;
45 | return this[index];
46 | };
47 | catvm.safefunction(MimeTypeArray.prototype.item);
48 | MimeTypeArray.prototype.namedItem = function namedItem(key) {
49 | // debugger;
50 | return this[key];
51 | };
52 | catvm.safefunction(MimeTypeArray.prototype.namedItem);
53 |
54 |
55 | // 适用于 调用原型的属性会抛出异常的对象
56 | for (var _prototype in MimeTypeArray.prototype) {
57 | if (typeof (MimeTypeArray.prototype[_prototype]) != "function") {
58 | // 相当于Object.defineProperty的get方法,Proxy的get方法,hook原型上的所有方法属性
59 | MimeTypeArray.prototype.__defineGetter__(_prototype, function () {
60 | // this是实例
61 | throw new TypeError("Illegal constructor");
62 | // return this[pr];
63 | });
64 | }
65 | }
66 | ///////////////////////
67 | // catvm.memory.MimeTypeArray.ls = [] // 所有MimeType存放点
68 | // 遍历 PluginArray实例里面的所有Plugin实例
69 | catvm.memory.MimeTypeArray.mimetype_count = 0;
70 | catvm.memory.MimeTypeArray.mimetype_types = {}; // 所有MimeType.type存放点
71 | for (let index = 0; index < catvm.memory.PluginArray._.length; index++) {
72 | let tmp_plugin = catvm.memory.PluginArray._[index];
73 | // 遍历 Plugin实例里面的所有MimeType实例,增加到 MimeTypeArray中
74 | for(let m_index=0;m_index:1:21";
58 | throw e;
59 | // throw new TypeError("Illegal constructor");
60 | });
61 | }
62 | }
63 | ////////
64 |
65 |
66 | navigator = catvm.proxy(navigator);
67 |
68 |
--------------------------------------------------------------------------------
/CatVm2/browser/Plugin.js:
--------------------------------------------------------------------------------
1 | // 存储一些值,避免污染全局变量空间
2 | catvm.memory.plugin = {};
3 |
4 | var Plugin = function Plugin() { // 构造函数
5 | throw new TypeError("Illegal constructor");
6 | };
7 | catvm.safefunction(Plugin);
8 |
9 |
10 | catvm.memory.plugin.iterator = function values() {
11 | // debugger;
12 | return {
13 | next:function () {
14 | if(this.index_ == undefined){
15 | this.index_ = 0;
16 | }
17 | var tmp = this.self_[this.index_];
18 | this.index_ += 1;
19 | return {value:tmp,done:tmp==undefined};
20 | },
21 | self_:this
22 | }
23 | };
24 | catvm.safefunction(catvm.memory.plugin.iterator);
25 |
26 | Object.defineProperties(Plugin.prototype, {
27 | [Symbol.toStringTag]: {
28 | value: "Plugin",
29 | configurable: true
30 | },
31 | // 原型上多了个这个,里面是个方法
32 | [Symbol.iterator]: {
33 | value: catvm.memory.plugin.iterator,
34 | configurable: true
35 | }
36 | });
37 |
38 | ////////// 浏览器代码自动生成部分
39 | Plugin.prototype.name = "";
40 | Plugin.prototype.filename = "";
41 | Plugin.prototype.description = "";
42 | Plugin.prototype.length = 0;
43 | Plugin.prototype.item = function item(index) {
44 | // debugger;
45 | return this[index];
46 | };
47 | catvm.safefunction(Plugin.prototype.item);
48 | Plugin.prototype.namedItem = function namedItem(key) {
49 | // debugger;
50 | return this[key];
51 | };
52 | catvm.safefunction(Plugin.prototype.namedItem);
53 |
54 |
55 | for (var _prototype in Plugin.prototype) {
56 | if (typeof (Plugin.prototype[_prototype]) != "function") {
57 | // 相当于Object.defineProperty的get方法,Proxy的get方法,hook原型上的所有方法属性
58 | Plugin.prototype.__defineGetter__(_prototype, function () {
59 | // this是实例
60 | throw new TypeError("Illegal constructor");
61 | // return this[pr];
62 | });
63 | }
64 | }
65 | /*
66 | { name: 'Chrome PDF Viewer', filename: 'internal-pdf-viewer', description: 'Portable Document Format',MimeTypes:[{"description": "Portable Document Format","suffixes": "pdf","type": "application/pdf"},{"description": "xxxxx","suffixes": "xxxxpdf","type": "xxxxapplication/pdf"}]}
67 | */
68 | ////////
69 | catvm.memory.plugin.new = function (data) {
70 | var plugin = {};
71 | if (data != undefined) {
72 | plugin.description = data.description;
73 | plugin.filename = data.filename;
74 | plugin.name = data.name;
75 | // MimeType
76 | if (data.MimeTypes != undefined) {
77 | for (let index = 0; index < data.MimeTypes.length; index++) {
78 | var mimetypedata = data.MimeTypes[index];
79 | var mimetype = catvm.memory.mimetype.new(mimetypedata, plugin);
80 | plugin[index] = mimetype;
81 | // mimetype.type浏览器显示的是灰色名称,下面这种添加属性会是亮的,因此我们需要换一种添加方式
82 | // plugin[mimetype.type] = mimetype;
83 | Object.defineProperty(plugin, mimetype.type, {
84 | value: mimetype,
85 | writable: true // 是否可以改变
86 | });
87 | }
88 |
89 | plugin.length = data.MimeTypes.length;
90 | }
91 | }
92 | // 先赋完值,在指向原型
93 | plugin.__proto__ = Plugin.prototype;
94 | return plugin;
95 | };
96 |
97 | // 代理一般挂在实例上
98 | navigator.plugins = catvm.proxy(navigator.plugins);
99 |
100 |
--------------------------------------------------------------------------------
/CatVm2/browser/PluginArray.js:
--------------------------------------------------------------------------------
1 | // 存储一些值,避免污染全局变量空间
2 | catvm.memory.PluginArray = {};
3 |
4 | var PluginArray = function PluginArray() { // 构造函数
5 | throw new TypeError("Illegal constructor");
6 | };
7 | catvm.safefunction(PluginArray);
8 |
9 |
10 | catvm.memory.PluginArray.iterator = function values() {
11 | // debugger;
12 | return {
13 | next:function () {
14 | if(this.index_ == undefined){
15 | this.index_ = 0;
16 | }
17 | var tmp = this.self_[this.index_];
18 | this.index_ += 1;
19 | return {value:tmp,done:tmp==undefined};
20 | },
21 | self_:this
22 | }
23 | };
24 | catvm.safefunction(catvm.memory.plugin.iterator);
25 |
26 | Object.defineProperties(PluginArray.prototype, {
27 | [Symbol.toStringTag]: {
28 | value: "PluginArray",
29 | configurable: true
30 | },
31 | // 原型上多了个这个,里面是个方法
32 | [Symbol.iterator]: {
33 | value: catvm.memory.PluginArray.iterator,
34 | configurable: true
35 | }
36 | });
37 | // PluginArray实例, PluginArray这个虽然跟Plugin很像,但是无需被new,浏览器一开始就有该实例 navigator.plugins
38 | catvm.memory.PluginArray._ = {};
39 |
40 | ////////// ///////////////////浏览器代码自动生成部分
41 | PluginArray.prototype.length = 0;
42 | PluginArray.prototype.item = function item(index) {
43 | // debugger;
44 | return this[index];
45 | };
46 | catvm.safefunction(PluginArray.prototype.item);
47 | PluginArray.prototype.namedItem = function namedItem(key) {
48 | // debugger;
49 | return this[key];
50 | };
51 | catvm.safefunction(PluginArray.prototype.namedItem);
52 |
53 | PluginArray.prototype.refresh = function refresh() {
54 | debugger;
55 | };
56 | catvm.safefunction(PluginArray.prototype.refresh);
57 |
58 | // 适用于 调用原型的属性会抛出异常的对象
59 | for (var _prototype in PluginArray.prototype) {
60 | if (typeof (PluginArray.prototype[_prototype]) != "function") {
61 | // 相当于Object.defineProperty的get方法,Proxy的get方法,hook原型上的所有方法属性
62 | PluginArray.prototype.__defineGetter__(_prototype, function () {
63 | // this是实例
64 | throw new TypeError("Illegal constructor");
65 | // return this[pr];
66 | });
67 | }
68 | }
69 | /*
70 | { name: 'Chrome PDF Viewer', filename: 'internal-pdf-viewer', description: 'Portable Document Format',MimeTypes:[{"description": "Portable Document Format","suffixes": "pdf","type": "application/pdf"},{"description": "xxxxx","suffixes": "xxxxpdf","type": "xxxxapplication/pdf"}]}
71 | */
72 | ///////////////////////
73 | catvm.memory.PluginArray.ls = [
74 | {
75 | "name": "PDF Viewer",
76 | "filename": "internal-pdf-viewer",
77 | "description": "Portable Document Format",
78 | "MimeTypes": [
79 | {
80 | "description": "Portable Document Format",
81 | "suffixes": "pdf",
82 | "type": "application/pdf"
83 | },
84 | {
85 | "description": "Portable Document Format",
86 | "suffixes": "pdf",
87 | "type": "text/pdf"
88 | }
89 | ]
90 | },
91 | {
92 | "name": "Chrome PDF Viewer",
93 | "filename": "internal-pdf-viewer",
94 | "description": "Portable Document Format",
95 | "MimeTypes": [
96 | {
97 | "description": "Portable Document Format",
98 | "suffixes": "pdf",
99 | "type": "application/pdf"
100 | },
101 | {
102 | "description": "Portable Document Format",
103 | "suffixes": "pdf",
104 | "type": "text/pdf"
105 | }
106 | ]
107 | },
108 | {
109 | "name": "Chromium PDF Viewer",
110 | "filename": "internal-pdf-viewer",
111 | "description": "Portable Document Format",
112 | "MimeTypes": [
113 | {
114 | "description": "Portable Document Format",
115 | "suffixes": "pdf",
116 | "type": "application/pdf"
117 | },
118 | {
119 | "description": "Portable Document Format",
120 | "suffixes": "pdf",
121 | "type": "text/pdf"
122 | }
123 | ]
124 | },
125 | {
126 | "name": "Microsoft Edge PDF Viewer",
127 | "filename": "internal-pdf-viewer",
128 | "description": "Portable Document Format",
129 | "MimeTypes": [
130 | {
131 | "description": "Portable Document Format",
132 | "suffixes": "pdf",
133 | "type": "application/pdf"
134 | },
135 | {
136 | "description": "Portable Document Format",
137 | "suffixes": "pdf",
138 | "type": "text/pdf"
139 | }
140 | ]
141 | },
142 | {
143 | "name": "WebKit built-in PDF",
144 | "filename": "internal-pdf-viewer",
145 | "description": "Portable Document Format",
146 | "MimeTypes": [
147 | {
148 | "description": "Portable Document Format",
149 | "suffixes": "pdf",
150 | "type": "application/pdf"
151 | },
152 | {
153 | "description": "Portable Document Format",
154 | "suffixes": "pdf",
155 | "type": "text/pdf"
156 | }
157 | ]
158 | }
159 | ]
160 |
161 |
162 | for (let index = 0; index < catvm.memory.PluginArray.ls.length; index++) {
163 | let tmp_plugin = catvm.memory.plugin.new(catvm.memory.PluginArray.ls[index]);
164 | catvm.memory.PluginArray._[index] = tmp_plugin;
165 | // mimetype.type浏览器显示的是灰色名称,下面这种添加属性会是亮的,因此我们需要换一种添加方式
166 | Object.defineProperty(catvm.memory.PluginArray._, tmp_plugin.name, {
167 | value: tmp_plugin,
168 | });
169 | }
170 | catvm.memory.PluginArray._.length = catvm.memory.PluginArray.ls.length;
171 |
172 | catvm.memory.PluginArray._.__proto__ = PluginArray.prototype;
173 | // 代理一般挂在实例上
174 | catvm.memory.PluginArray._ = catvm.proxy(catvm.memory.PluginArray._);
175 | // 依赖注入
176 | navigator.plugins = catvm.memory.PluginArray._;
177 |
--------------------------------------------------------------------------------
/CatVm2/browser/Screen.js:
--------------------------------------------------------------------------------
1 | // 从浏览器中知道Screen是全局的,且原型链只是一层,因此比较好伪造(window有多层所以要伪造多层)
2 | // 浏览器中new会报错,因此我们此处也需要报错
3 | var Screen = function Screen() { // 构造函数
4 | throw new TypeError("Illegal constructor");
5 | };
6 | catvm.safefunction(Screen);
7 | // 浏览器
8 | Object.defineProperties(Screen.prototype, {
9 | [Symbol.toStringTag]: {
10 | value: "Screen",
11 | configurable: true
12 | }
13 | });
14 | screen = {};
15 | screen.__proto__ = Screen.prototype;
16 | ////////// 浏览器代码自动生成部分
17 | Screen.prototype.width = 1494;
18 | Screen.prototype.height = 934;
19 | Screen.prototype.availWidth = 1494;
20 | Screen.prototype.availHeight = 934;
21 | Screen.prototype.colorDepth = 24;
22 | Screen.prototype.pixelDepth = 24;
23 | ////////
24 | // 浏览器中screen是全局的,因此我们也需要定义一个screen
25 |
26 | screen = catvm.proxy(screen);
27 |
28 |
--------------------------------------------------------------------------------
/CatVm2/browser/Storage.js:
--------------------------------------------------------------------------------
1 | // 从浏览器中知道Storage是全局的,且原型链只是一层,因此比较好伪造(window有多层所以要伪造多层)
2 | // 浏览器中new会报错,因此我们此处也需要报错
3 | var Storage = function Storage() { // 构造函数
4 | throw new TypeError("Illegal constructor");
5 | };
6 | catvm.safefunction(Storage);
7 | // 浏览器
8 | Object.defineProperties(Storage.prototype, {
9 | [Symbol.toStringTag]: {
10 | value: "Storage",
11 | configurable: true
12 | }
13 | });
14 | var localStorage = {};
15 | localStorage.__proto__ = Storage.prototype;
16 |
17 | ////////// 浏览器代码自动生成部分
18 |
19 | function get_length() {
20 | return Object.keys(catvm.memory.storage).length;
21 | }
22 |
23 | Storage.prototype.length = get_length();
24 | Storage.prototype.key = function key(index) {
25 | return Object.keys(catvm.memory.storage)[index];
26 | };
27 | catvm.safefunction(Storage.prototype.key);
28 | Storage.prototype.getItem = function getItem(keyName) {
29 | var result = catvm.memory.storage[keyName];
30 | if (result) {
31 | return result;
32 | } else {
33 | return null;
34 | }
35 | };
36 | catvm.safefunction(Storage.prototype.getItem);
37 |
38 | Storage.prototype.setItem = function setItem(keyName, keyValue) {
39 | catvm.memory.storage[keyName] = keyValue;
40 | };
41 | catvm.safefunction(Storage.prototype.setItem);
42 |
43 | Storage.prototype.removeItem = function removeItem(keyName) {
44 | delete catvm.memory.storage[keyName];
45 | };
46 | catvm.safefunction(Storage.prototype.removeItem);
47 |
48 | Storage.prototype.clear = function clear() {
49 | catvm.memory.storage = {};
50 | };
51 | catvm.safefunction(Storage.prototype.clear);
52 |
53 |
54 | ////////
55 |
56 | // 代理一般挂在实例上
57 | localStorage = catvm.proxy(localStorage);
58 | Storage = catvm.proxy(Storage);
59 |
60 |
--------------------------------------------------------------------------------
/CatVm2/browser/Window.js:
--------------------------------------------------------------------------------
1 | window = this;
2 | // debugger;
3 | var Window = function Window() { // 构造函数
4 | // 容易被检测到的 js可以查看堆栈
5 | throw new TypeError("Illegal constructor");
6 | };
7 | catvm.safefunction(Window);
8 |
9 | Object.defineProperties(Window.prototype, {
10 | [Symbol.toStringTag]: {
11 | value: "Window",
12 | configurable: true
13 | }
14 | })
15 | Window.prototype.__proto__ = WindowProperties.prototype;
16 | window.__proto__ = Window.prototype;
17 |
18 | ///////////////////////////// 浏览器代码自动生成部分
19 | Window.prototype.PERSISTENT = 1;
20 | Window.prototype.TEMPORARY = 0;
21 |
22 |
23 | // v8没有setTimeout,浏览器有,但是浏览器把这个方法放到this下面,伪造v8有这个东西,因此我们需要伪造一下
24 | window.setTimeout = function (x, y) {
25 | // x可能是方法也可能是文本
26 | typeof (x) == "function" ? x() : undefined;
27 | typeof (x) == "string" ? eval(x) : undefined;
28 | // 正确应该 生成UUID,并且保存到内存
29 | return 123;
30 | };
31 | catvm.safefunction(window.setTimeout);
32 | // 原型下面可以取这个属性\方法,就直接放原型即可
33 | // 只要是方法就需要catvm.safefunction 进行toSting保护
34 | window.open = function open() {
35 | debugger;
36 | };
37 | catvm.safefunction(window.open);
38 | // 赋值空对象最好使用这种class chrome{} 形式,而不是 {},因为这样我们可以看名字,并且最好挂上代理
39 | window.chrome = catvm.proxy(class chrome {
40 | });
41 | // 打个debugger,因为我们还不知道js有没有调用该方法,也许只是获取了一下,看有没有该方法呢
42 | // 等它真正调用的时候,我们再补全其参数及返回
43 | window.DeviceOrientationEvent = function DeviceOrientationEvent() {
44 | debugger;
45 | };
46 | catvm.safefunction(window.DeviceOrientationEvent);
47 | window.DeviceMotionEvent = function DeviceMotionEvent() {
48 | debugger;
49 | };
50 | catvm.safefunction(window.DeviceMotionEvent);
51 |
52 | // window.localStorage = class localStorage {
53 | // };
54 | // window.localStorage.getItem = function getItem() {
55 | // debugger;
56 | // };
57 | // catvm.safefunction(window.localStorage.getItem);
58 | // window.localStorage.setItem = function setItem() {
59 | // debugger;
60 | // };
61 | // catvm.safefunction(window.localStorage.setItem);
62 | // window.localStorage = catvm.proxy(window.localStorage)
63 | //////////////////////
64 |
65 | // debugger;
66 | window = catvm.proxy(window);
67 | Window = catvm.proxy(Window);
68 |
--------------------------------------------------------------------------------
/CatVm2/browser/WindowProperties.js:
--------------------------------------------------------------------------------
1 | var WindowProperties = function WindowProperties() { // 构造函数
2 |
3 | };
4 | catvm.safefunction(WindowProperties);
5 |
6 | Object.defineProperties(WindowProperties.prototype, {
7 | [Symbol.toStringTag]: {
8 | value: "WindowProperties",
9 | configurable: true
10 | }
11 | })
12 |
13 | // 设置原型的父对象
14 | WindowProperties.prototype.__proto__ = EventTarget.prototype;
15 |
16 |
17 |
--------------------------------------------------------------------------------
/CatVm2/catvm2.node.js:
--------------------------------------------------------------------------------
1 | var fs = require('fs');
2 | // 框架工具模块
3 | var vmtools = require('./tools/tools.node.js');
4 | var vmhtml = require('./browser/HTMLElements/htmlelement.node.js');
5 | function GetCode() {
6 | // 引入框架工具代码
7 | var code = "";
8 | code += vmtools.GetCode() + '\r\n';
9 | // 引入用户框架配置 // 暂时这么写
10 | // code += "catvm.memory.config.proxy = true;\r\n"
11 | // 引入浏览器相关代码
12 | code += fs.readFileSync(`${__dirname}/browser/EventTarget.js`) + '\r\n';
13 | code += fs.readFileSync(`${__dirname}/browser/WindowProperties.js`) + '\r\n';
14 | // 加载BOM环境(优于DOM加载)
15 | code += fs.readFileSync(`${__dirname}/browser/Window.js`) + '\r\n';
16 | code += fs.readFileSync(`${__dirname}/browser/Location.js`) + '\r\n';
17 | code += fs.readFileSync(`${__dirname}/browser/Navigator.js`) + '\r\n';
18 | code += fs.readFileSync(`${__dirname}/browser/History.js`) + '\r\n';
19 | code += fs.readFileSync(`${__dirname}/browser/Screen.js`) + '\r\n';
20 | code += fs.readFileSync(`${__dirname}/browser/Storage.js`) + '\r\n';
21 |
22 | code += fs.readFileSync(`${__dirname}/browser/MimeType.js`) + '\r\n';
23 | code += fs.readFileSync(`${__dirname}/browser/Plugin.js`) + '\r\n';
24 | code += fs.readFileSync(`${__dirname}/browser/PluginArray.js`) + '\r\n';
25 | code += fs.readFileSync(`${__dirname}/browser/MimeTypeArray.js`) + '\r\n';
26 |
27 | // 加载HTML节点
28 | code += vmhtml.GetCode() + '\r\n';
29 | // 加载DOM环境
30 | code += fs.readFileSync(`${__dirname}/browser/Document.js`) + '\r\n';
31 | // 引入用户自定义环境
32 | code += "debugger;\r\n";
33 | return code;
34 |
35 | }
36 |
37 | module.exports = {
38 | GetCode
39 | }
--------------------------------------------------------------------------------
/CatVm2/tools/tools.node.js:
--------------------------------------------------------------------------------
1 | // .node.js文件的用途就是拼接多个文件的js代码
2 | var fs = require('fs');
3 |
4 | function GetCode() {
5 | var code = "";
6 | code += fs.readFileSync(`${__dirname}/vm_memory.js`) + '\r\n';
7 | code += fs.readFileSync(`${__dirname}/vm_safefunction.js`) + '\r\n';
8 | code += fs.readFileSync(`${__dirname}/vm_print.js`) + '\r\n';
9 | code += fs.readFileSync(`${__dirname}/vm_proxy.js`) + '\r\n';
10 | return code;
11 |
12 | }
13 |
14 | module.exports = {
15 | GetCode
16 | }
--------------------------------------------------------------------------------
/CatVm2/tools/vm_memory.js:
--------------------------------------------------------------------------------
1 | // 框架内存管理,用于解决变量名重复问题
2 | // 调试日志 window.catvm 把框架功能集中管理,
3 |
4 | var catvm = {};
5 | // 框架运行内存
6 | catvm.memory = {
7 | config: {print: true, proxy: true}, // 框架配置:是否打印,是否使用proxy
8 | htmlelements:{}, // 所有的html节点元素存放位置
9 | listeners:{}, // 所有事件存放位置
10 | log:[], // 环境调用日志统一存放点
11 | storage:{} // localStorage 全局存放点
12 | }; // 默认关闭打印
13 |
14 |
15 |
--------------------------------------------------------------------------------
/CatVm2/tools/vm_print.js:
--------------------------------------------------------------------------------
1 | // 日志调试功能
2 | catvm.print = {};
3 | catvm.memory.print = []; // 缓存
4 | catvm.print.log = function () {
5 | if (catvm.memory.config.print) {
6 | console.table(catvm.memory.log);
7 |
8 | }
9 | };
10 |
11 | catvm.print.getAll = function () { // 列出所有日志
12 | if (catvm.memory.config.print) {
13 | console.table(catvm.memory.log);
14 |
15 | }
16 | };
--------------------------------------------------------------------------------
/CatVm2/tools/vm_proxy.js:
--------------------------------------------------------------------------------
1 | // 框架代理功能
2 |
3 | catvm.proxy = function (obj) {
4 | // Proxy 可以多层代理,即 a = new proxy(a); a = new proxy(a);第二次代理
5 | // 后代理的检测不到先代理的
6 | if (catvm.memory.config.proxy == false) {
7 | return obj
8 | }
9 | return new Proxy(obj, {
10 | set(target, property, value) {
11 | console.table([{"类型":"set-->","调用者":target,"调用属性":property,"设置值":value}]);
12 | catvm.memory.log.push({"类型":"set-->","调用者":target,"调用属性":property,"设置值":value});
13 | // console.log("set", target, property, value);
14 | return Reflect.set(...arguments); //这是一种反射语句,这种不会产生死循环问题
15 | },
16 | get(target, property, receiver) {
17 | console.table([{"类型":"get<--","调用者":target,"调用属性":property,"获取值":target[property]}]);
18 | catvm.memory.log.push({"类型":"get<--","调用者":target,"调用属性":property,"获取值":target[property]});
19 | // console.log("get", target, property, target[property]);
20 | return target[property]; // target中访问属性不会再被proxy拦截,所以不会死循环
21 | }
22 | });
23 | }
--------------------------------------------------------------------------------
/CatVm2/tools/vm_safefunction.js:
--------------------------------------------------------------------------------
1 | // 主要用来保护伪造的函数,使其更难被识别
2 |
3 | // 主要用来保护伪造的函数,让其更难识破
4 | ;
5 | (() => {
6 | 'use strict';
7 | // 取原型链上的toString
8 | const $toString = Function.toString;
9 | // 取方法名 reload
10 | const myFunction_toString_symbol = Symbol('('.concat('', ')_', (Math.random() + '').toString(36)));
11 | const myToString = function () {
12 | return typeof this == 'function' && this[myFunction_toString_symbol] || $toString.call(this);
13 | };
14 |
15 | function set_native(func, key, value) {
16 | Object.defineProperty(func, key, {
17 | "enumerable": false, // 不可枚举
18 | "configurable": true, // 可配置
19 | "writable": true, // 可写
20 | "value": value
21 | })
22 | }
23 |
24 | delete Function.prototype['toString'];// 删除原型链上的toString
25 | set_native(Function.prototype, "toString", myToString); // 自定义一个getter方法,其实就是一个hook
26 | //套个娃,保护一下我们定义的toString,避免js对toString再次toString,如:location.reload.toString.toString() 否则就暴露了
27 | set_native(Function.prototype.toString, myFunction_toString_symbol, "function toString() { [native code] }");
28 | this.catvm.safefunction = (func) => {
29 | set_native(func, myFunction_toString_symbol, `function ${myFunction_toString_symbol,func.name || ''}() { [native code] }`);
30 | }; //导出函数到globalThis,更改原型上的toSting为自己的toString。这个方法相当于过掉func的toString检测点
31 | }).call(this);
32 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # 补环境框架 - 志远课程完结版
2 | ## 志远补环境课程配套框架源码
3 | ## 此项目已经被开源安全社区OSCS收录并检测安全
4 | [](https://www.oscs1024.com/project/fanchangrui/catvm?ref=badge_small)
5 |
6 | ## 来源
7 | 该项目是我跟着 志远大佬开源课程 一步步敲出来的;
8 | 该项目内容与最后课程实现的效果完全一样,相当于课程配套源码。
9 |
10 |
11 | ### 具体 使用步骤及实现原理,可以参考我的博客文章
12 | [JS逆向之浏览器补环境详解](https://blog.csdn.net/qq_36291294/article/details/127699273)
13 | ### 另外,我使用另一种更完美\更细粒度的思路实现了一个补环境框架,目前可以直接黑盒过瑞数:
14 | [JS逆向之补环境过瑞数详解](https://blog.csdn.net/qq_36291294/article/details/128600583)
--------------------------------------------------------------------------------
/__bak/step.js:
--------------------------------------------------------------------------------
1 | function Person(option) {
2 | //一般传入字面量对象做参数
3 | //new之后自动创建一个空对象,把这个对象的地址给this,即var this = new Object();
4 | //this给空对象绑定属性和行为
5 | this._init(option);
6 | this.name = option.name;
7 | this.eat = function(food) {
8 | console.log("吃" + food)
9 | }
10 | ;
11 | //自动默认return this;如果有存在 return 对象,则不返回this,若return 非对象,则依然return this
12 | }
13 | Person.prototype = {
14 | //所有此对象共享的属性和方法
15 | _init: function(option) {
16 | this.earth = option.earth;
17 | },
18 | run: function(where) {
19 | console.log(this.name + "在" + where + "泡");
20 | }
21 | };
22 | var per = new Person({
23 | name: "dsf"
24 | });
25 | //向构造函数传入字面量对象
26 | per.eat("牛排");
27 | //调用对象方法
28 |
29 |
30 |
31 |
32 | 一般补环境的几个步骤:
33 | 比如补Navigator:
34 | 1、先在浏览器环境观察该对象:Navigator
35 | 能否进行new Navigator,不能的话则在其构造函数定义中抛出异常,能的话不抛;
36 | 查看其原型Navigator.prototype 的属性、方法、原型链,
37 | 发现Navigator原型属性、方法不能通过原型调用,即
38 | Navigator.appVersion 会抛出异常。
39 | 发现 其原型链只有一层,即Navigator.prototype.__proto__ === Object.prototype
40 | 2、在浏览器环境观察其实例对象:navigator
41 | 查看其属性、方法与 原型上的差异,发现差不多,基本都是继承原型的,
42 |
43 | 3、补环境:
44 | 定义Navigator 构造函数,并保护其toString,
45 | 定义navigator对象,将其原型指向Navigator,即navigator.__proto__ = Navigator.prototype;
46 | 如果是多层原型的话,需要多次指向。
47 | 补全原型上的属性、方法:
48 | Navigator.prototype.plugins = [];
49 | Navigator.prototype.languages = ["zh-CN", "zh"];
50 | 补全实例上的属性、方法(不要与继承自原型的属性、方法冲突)
51 |
52 |
53 |
54 | 4、代理该对象 navigator
55 |
56 |
57 |
58 |
59 |
60 | 补一个方法如location.reload()时,
61 | 需要看其是在原型上还是实例上,这会决定我们是在原型上补还是在实例上补(唯一区别),
62 | 通过浏览器环境观察,发现reload是在location实例上定义的,
63 | 因此我们直接在location实例上补该方法:
64 | location = class location{};
65 | //此处必须给个方法名,因为toString会默认调用该方法,可能会检测该方法名,location.reload.toString时,
66 | // 会将该方法定义(包括方法定义中的注释)都输出
67 | // eg:loca.reload.toString()
68 | // 'function reload(){ //此处必须给个方法名,因为toString会默认调用该方法,可能会检测该方法名\n\n}'
69 | location.reload = function reload(){
70 |
71 | };
72 | 定义完方法之后,需要对方法进行保护
73 | func_set_native(location.reload);
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 | 一般补环境的几个步骤:
82 | 比如补Navigator:
83 | 1、先在浏览器环境观察该对象:Navigator
84 | 先查看其原型链,发现只有一层即 Navigator.prototype.__proto__ 为Object原型
85 | 能否进行new Navigator,不能的话则在其构造函数定义中抛出异常,能的话不抛;
86 | var Navigator = function Navigator() { // 构造函数
87 | throw new TypeError("Illegal constructor");
88 | };
89 | 然后保护该方法:
90 | catvm.safefunction(Navigator);
91 | 然后给其原型一个名字:
92 | Object.defineProperties(Navigator.prototype, {
93 | [Symbol.toStringTag]: {
94 | value: "Navigator",
95 | configurable: true
96 | }
97 | }
98 | });
99 | 在浏览器查看其实例navigator是否存在,存在的话我们也要定义一个:
100 | navigator = {};
101 | 然后指定其原型:
102 | navigator.__proto__ = Navigator.prototype;
103 | 此时对比浏览器原型链,确定我们原型已经补完,接下来就是填充navigator的原型方法、属性、实例方法、属性
104 | 对比浏览器上navigator的原型与实例上方法、属性的差异,将原型上的补到我们原型上,实例上的补到实例上,两者都有的优先补到原型上。
105 | Navigator.prototype.plugins = [];
106 | Navigator.prototype.languages = ["zh-CN", "zh"];
107 | ...
108 | 然后在最末尾加上代理:
109 | navigator = catvm.proxy(navigator);
110 | 最终在调试网站js环境代码时,根据log一个个补,浏览器上输出啥,我们就补成啥,如果log输出本来就跟浏览器上的
111 | 一致,则不用动,继续去看下一个log
112 |
113 | 遇到不清楚的属性、方法,去 https://developer.mozilla.org/上查看
--------------------------------------------------------------------------------
/__bak/tools.js:
--------------------------------------------------------------------------------
1 | // 传进来的对象是一个实例还是一个原型
2 | // 思路:遍历原型里面所有的值,拿出来进行封装
3 |
4 | //判断对象的类型
5 | function judge_type(pr,property,_name) {
6 | var code = "";
7 | // Screen.prototype.width = 1494;
8 | var temp = _name+".prototype."+property;
9 | switch (typeof (pr[property])) {
10 | case "function":
11 | code = temp + "= function " +property+"(){debugger;};catvm.safefunction("+temp+");";
12 | break;
13 | case "object":
14 | code = temp + "= catvm.proxy(class " +property+"{});";
15 | break;
16 | default:
17 | // "string"\"boolean"\"undefined"\"number"
18 | code += _name+".prototype."+property + "=" +pr[property];
19 | break;
20 | }
21 | return code;
22 | }
23 |
24 | function getcode(pr,_name) {
25 | var code = "";
26 | for (var property in pr.__proto__) {
27 | console.log(property,typeof property);
28 | // 原型、字段名、别名
29 | code += judge_type(pr,property,_name) + "\r\n";
30 | }
31 | return code;
32 | }
33 |
34 | /*
35 | 浏览器运行我们的脚本:
36 | getcode(localStorage,"Storage")
37 | 生成:
38 | Storage.prototype.length=0
39 | Storage.prototype.clear= function clear(){debugger;};catvm.safefunction(Storage.prototype.clear);
40 | Storage.prototype.getItem= function getItem(){debugger;};catvm.safefunction(Storage.prototype.getItem);
41 | Storage.prototype.key= function key(){debugger;};catvm.safefunction(Storage.prototype.key);
42 | Storage.prototype.removeItem= function removeItem(){debugger;};catvm.safefunction(Storage.prototype.removeItem);
43 | Storage.prototype.setItem= function setItem(){debugger;};catvm.safefunction(Storage.prototype.setItem);
44 | 然后我们再具体实现每个方法
45 | */
--------------------------------------------------------------------------------
/__bak/window.js:
--------------------------------------------------------------------------------
1 | // 环境框架内容(环境头)
2 |
3 | window = this;
4 |
5 | navigator = {
6 | userAgent:"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.107 Safari/537.36"
7 | }
8 | function vmProxy(obj){
9 | // Proxy 可以多层代理,即 a = new proxy(a); a = new proxy(a);第二次代理
10 | // 后代理的检测不到先代理的
11 | return new Proxy(obj, {
12 | set(target, property, value){
13 | console.log(target, property, value);
14 | return Reflect.set(...arguments); //这是一种反射语句,这种不会产生死循环问题
15 | },
16 | get(target,property,receiver){
17 | console.log(target, property, receiver);
18 | return target[property]; // target中访问属性不会被proxy拦截,所以不会死循环
19 | }
20 | });
21 | }
22 | // 主要用来保护伪造的函数,让其更难识破
23 | (() => {
24 | 'use strict';
25 | // 取原型链上的toString
26 | const $toString = Function.toString;
27 | // 取方法名 reload
28 | const myFunction_toString_symbol = Symbol('('.concat('',')_',(Math.random()+'').toString(36)));
29 | const myToString = function(){
30 | return typeof this == 'function' && this[myFunction_toString_symbol] || $toString.call(this);
31 | };
32 | function set_native(func,key,value){
33 | Object.defineProperty(func,key,{
34 | "enumerable":false, // 不可枚举
35 | "configurable":true, // 可配置
36 | "writable":true, // 可写
37 | "value":value
38 | })
39 | }
40 | delete Function.prototype['toString'];// 删除原型链上的toString
41 | set_native(Function.prototype,"toString",myToString); // 自定义一个getter方法,其实就是一个hook
42 | //套个娃,保护一下我们定义的toString,避免js对toString再次toString,如:location.reload.toString.toString() 否则就暴露了
43 | set_native(Function.prototype.toString,myFunction_toString_symbol,"function toString() { [native code] }");
44 | this.func_set_native = (func) => {
45 | set_native(func,myFunction_toString_symbol,`function ${myFunction_toString_symbol,func.name || ''}() { [native code] }`);
46 | }; //导出函数到globalThis,更改原型上的toSting为自己的toString。这个方法相当于过掉func的toString检测点
47 | }).call(this);
48 |
49 |
50 | Object.defineProperties(window,{
51 | [Symbol.toStringTag]:{
52 | value:"window",
53 | configurable:true
54 | }
55 | })
56 |
57 | window = vmProxy(window);
58 | /*
59 | 创建对象的几种方式: {} 、 Object.create({})、class xxx{} 、function xxx(){};+new xxx;
60 | 代理这些常见的浏览器对象,以便进行环境调试。
61 | */
62 | navigator = vmProxy(class navigator{});
63 | document = vmProxy(class document{});
64 |
65 | location = class location{};
66 | location.reload = function reload(){ //此处必须给个方法名,因为toString会默认调用该方法,可能会检测该方法名
67 |
68 | };func_set_native(location.reload);
69 |
70 | location = vmProxy(location);
71 | screen = vmProxy(class location{});
72 | debugger;
--------------------------------------------------------------------------------
/__bak/window_bak.js:
--------------------------------------------------------------------------------
1 | // 环境框架内容(环境头)
2 |
3 | window = this;
4 |
5 | navigator = {
6 | userAgent:"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.107 Safari/537.36"
7 | }
8 | function vmProxy(obj){
9 | // Proxy 可以多层代理,即 a = new proxy(a); a = new proxy(a);第二次代理
10 | // 后代理的检测不到先代理的
11 | return new Proxy(obj, {
12 | set(target, property, value){
13 | console.log(target, property, value);
14 | return Reflect.set(...arguments); //这是一种反射语句,这种不会产生死循环问题
15 | },
16 | get(target,property,receiver){
17 | console.log(target, property, receiver);
18 | return target[property]; // target中访问属性不会被proxy拦截,所以不会死循环
19 | }
20 | });
21 | }
22 | // 主要用来保护伪造的函数,让其更难识破
23 | (() => {
24 | 'use strict';
25 | const $toString = Function.toString;
26 | const myFunction_toString_symbol = Symbol('('.concat('',')_',(Math.random()+'').toString(36)));
27 | const myToString = function(){
28 | return typeof this == 'function' && this[myFunction_toString_symbol] || $toString.call(this);
29 | };
30 | function set_native(func,key,value){
31 | Object.defineProperty(func,key,{
32 | "enumerable":false,
33 | "configurable":true,
34 | "writable":true,
35 | "value":value
36 | })
37 | };
38 | delete Function.prototype['toString'];// 删除原型链上的toString
39 | set_native(Function.prototype,"toString",myToString); // 自定义个getter方法
40 | set_native(Function.prototype.toString,myFunction_toString_symbol,"function toString() { [native code] }"); //套个娃,保护一下我们定义的toString 否则就暴露了
41 | this.func_set_native = (func) => {
42 | set_native(func,myFunction_toString_symbol,`function ${myFunction_toString_symbol,func.name || ''}() { [native code] }`);
43 | }; //导出函数到globalThis,这个方法相当于过掉func的toString检测点
44 | }).call(this);
45 |
46 |
47 | Object.defineProperties(window,{
48 | [Symbol.toStringTag]:{
49 | value:"window",
50 | configurable:true
51 | }
52 | })
53 |
54 | window = vmProxy(window);
55 | /*
56 | 创建对象的几种方式: {} 、 Object.create({})、class xxx{} 、function xxx(){};+new xxx;
57 | 代理这些常见的浏览器对象,以便进行环境调试。
58 | */
59 | navigator = vmProxy(class navigator{});
60 | document = vmProxy(class document{});
61 |
62 | location = class location{};
63 | location.reload = function reload(){ //此处必须给个方法名,因为toString会默认调用该方法,可能会检测该方法名
64 |
65 | };func_set_native(location.reload);
66 |
67 | location = vmProxy(location);
68 | screen = vmProxy(class location{});
69 | debugger;
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | var fs = require('fs');
2 | var catvm2 = require('./CatVm2/catvm2.node.js');
3 | const {VM,VMScript} = require('vm2');
4 | var catvm2_code = catvm2.GetCode(); // 框架代码
5 | // debugger;
6 | // var web_js_code = fs.readFileSync(`${__dirname}/jy.js`) ; // 网站js代码
7 | var web_js_code = fs.readFileSync(`${__dirname}/rs.js`) ; // 网站js代码
8 | var log_code = "\r\ncatvm.print.getAll();\r\r"
9 | web_js_code = web_js_code+log_code
10 | var all_code = catvm2_code+web_js_code;
11 | fs.writeFileSync(`${__dirname}/debugger_bak.js`,all_code);
12 | const script = new VMScript(all_code,`${__dirname}/debugger.js`); //真实路径,浏览器打开的就是该缓存文件
13 |
14 | const vm = new VM(); // new 一个纯净v8环境
15 | debugger
16 | vm.run(script);
17 | debugger
18 |
--------------------------------------------------------------------------------
/补环境框架项目结构.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Big1moster/catvm/d843fcb236f78db4226327a7667217bcd11b8f02/补环境框架项目结构.png
--------------------------------------------------------------------------------