├── 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 | [![OSCS Status](https://www.oscs1024.com/platform/badge/fanchangrui/catvm.svg?size=small)](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 --------------------------------------------------------------------------------