您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
可配置并且功能比较丰富,支持定时,定网站,永久,或对某些函数,禁止或允许,还能随机化navigator中的硬件信息
// ==UserScript== // @name 伪装AudioContext,WebSocket,WebRTC,getImageData等指纹 // @namespace cccggg // @version 1.1 // @author cccggg // @run-at document-start // @include * // @exclude *://127.0.0.1:* // @exclude *://127.0.0.1/* // @exclude file://* // @grant GM_addStyle // @grant GM_getValue // @grant GM_setValue // @grant GM_deleteValue // @grant GM_listValues // @grant GM_registerMenuCommand // @grant GM_unregisterMenuCommand // @grant GM_xmlhttpRequest // @description 可配置并且功能比较丰富,支持定时,定网站,永久,或对某些函数,禁止或允许,还能随机化navigator中的硬件信息 // @license MIT // ==/UserScript== const host = location.host.toLowerCase(); // 语言伪装 const myLang = ["zh-CN"]; // 时区伪装 const fakeTimezone = 300; // anti tamper const w = unsafeWindow; const prompt = w.prompt; const Error = w.Error; const localStorage = w.localStorage; const sessionStorage = w.sessionStorage; // region useReturn let useReturn = GM_getValue("useReturn",true); function randomRange(min, max) { // min最小值,max最大值 return Math.floor(Math.random() * (max - min)) + min; } let name=GM_getValue("browername",false); if(!name){ GM_setValue("browername",randomRange(10000,99999)) } let useReturn_menuId; function useReturn_click(fakeClick) { if (!fakeClick) { GM_unregisterMenuCommand(useReturn_menuId); GM_setValue("useReturn",useReturn = !useReturn); } useReturn_menuId = GM_registerMenuCommand(useReturn?"canvas:随机噪声":"canvas:抛出异常",useReturn_click); } useReturn_click(1); // endregion // region password let password = GM_getValue("p"); if (!password) { password = btoa(parseInt(Math.random()*1000000000)); let i = password.indexOf("="); if (i >= 0) password = password.substring(0,i); GM_setValue("p",password); // 默认值 GM_setValue("d|Date.getTimezoneOffset",1); GM_setValue("d|WebSocket",1); GM_setValue("d|AudioContext",1); } function encryptId(k) { let out = ""; for (let i in k) { let c = k.charCodeAt(i)+password.charCodeAt(i%password.length)+host.charCodeAt(i%host.length); out += String.fromCharCode(c & 127); } out = btoa(out); let i = out.indexOf("="); if (i >= 0) out = out.substring(0,i); return out; } // endregion // region const PERMISSION = Symbol("PERMISSION"); function popupw(text) { let div = document.createElement("div"); div.classList.add("mask"); div.onclick = (e) => div.remove(); div.innerHTML = "<div class='popup'></div>"; div.lastElementChild.innerText = text; popup.panel.append(div); } class Databind { constructor(el,site) { this.perms = {}; let name=GM_getValue("browername") el.insertAdjacentHTML('beforeEnd', `<li><p>${site}的权限 <button title="查看和修改该网站持久化的数据">V</button></p>`+name+`<ul class="perm"></ul></li>`); let li = el.lastElementChild; li.querySelector("button").onclick = () => { let stored = GM_listValues().filter((v) => v.startsWith("s|"+site)).map((v) => { return [v,GM_getValue(v)]; }); let val = prompt("这是JSON数据,可以使用第三方工具方便的编辑\n使用确定来保存",JSON.stringify(stored)); if (val == null) return; val = JSON.parse(val); let s = new Set(); for(let i of val) { GM_setValue(i[0],i[1]); s.add(i[0]); } for(let i of stored) { if (!s.has(i[0])) GM_deleteValue(i[0]); } }; this.ul = li.lastElementChild; } perm(id) { let v = this.perms[id]; if (!v) { this.ul.insertAdjacentHTML('beforeEnd', `<li><p>${id}<b>0</b><b>0</b></p><ul title="最近的调用记录"></ul></li>`); const li = this.ul.lastElementChild; li[PERMISSION] = id; v = this.perms[id] = { counter: li.querySelectorAll("p > b"), logger: li.lastElementChild }; li.onmouseenter = (e) => { li.insertBefore(popup.form, li.lastElementChild); popup.form.querySelector("input").checked = !GM_getValue("d|"+id); }; li.onmouseleave = (e) => { popup.form.remove(); }; } return v; } trace(id,success,log="",par="") { let p = this.perm(id); p.counter[success?0:1].innerText++; let time = new Date().toLocaleTimeString(); p.logger.insertAdjacentHTML('afterBegin', `<li>${time} (${par})</li>`); if (p.logger.childElementCount > 30) p.logger.lastElementChild.remove(); const msg = ` 参数: ${par} 堆栈: ${log} `.trim(); if (log || par.length > 10) { p.logger.firstElementChild.onclick = () => { popupw(msg); }; } else { p.logger.firstElementChild.title = "无堆栈数据"; } } } class Popuper { constructor() { this.wrap = document.createElement('div'); this.panel = this.wrap.attachShadow({ mode: 'closed' }); this.sites = {}; const form = document.createElement("div"); form.style.marginBottom = "4px"; form.innerHTML = ` <p style="padding-bottom: 6px">对新网站禁止<input type="checkbox" title="而不是允许" /></p> <form> <select name="when"> <option>关闭网页前</option> <option>清除缓存前</option> <option>永远</option> <option>函数调用</option> <option>N秒内</option> </select> 允许<input type="checkbox" name="allow" title="选中允许" /><br> <input type="text" name="val" placeholder="时间或函数名" hidden /> <input type="submit" value="提交" /> </form>`; form.querySelector("input").onchange = (e) => { let b = e.target.checked; const key = e.target.parentElement.parentElement.parentElement[PERMISSION]; if(!b) GM_setValue("d|"+key,1); else GM_deleteValue("d|"+key); }; form.querySelector("select").onchange = (e) => { let b = e.target.selectedIndex < 3; form.querySelector("input[name=val]").hidden = b; }; form.querySelector("form").onsubmit = (e) => { let f = e.target.elements; const a = f.when.selectedIndex; const b = f.val.value; const c = f.allow.checked?1:0; const key = e.target.parentElement.parentElement[PERMISSION]; if (a == 3 && key.startsWith("__")) { alert("__开头的不能选'函数调用'"); return false; } switch (a) { case 0: sessionStorage[encryptId(key)] = c; break; case 1: localStorage[encryptId(key)] = c; break; case 2: GM_setValue("s|"+host+"|"+key, [["",c]]); break; case 3: var arr = GM_getValue("s|"+host+"|"+key,[]); arr.unshift([b,c]); GM_setValue("s|"+host+"|"+key, arr); break; case 4: localStorage[(c?"e":"d")+encryptId(key)] = Date.now()/1000+parseInt(v.substring(1)); break; } e.target.reset(); const btn = e.submitter; btn.disabled = true; btn.value="保存成功"; setTimeout(() => { btn.disabled = false; btn.value="提交"; }, 1000); return false; }; this.form = form; this.panel.innerHTML = ` <style> * { margin: 0; padding: 0; font-size: 14px; } #privacy-popup { margin: 0; position: fixed; bottom: 0; right: 0; width: 16px; height: 24px; transition: width 1s ease, height 1s ease, opacity 1s ease; border: 1px dashed #8a2be2; background: #2cc0374d; overflow: hidden; z-index: 999999999; opacity: 0.2; padding-inline-start: 4px; } #privacy-popup:hover { width: calc(min(50%, 300px)); height: 70%; list-style: none; overflow-y: scroll; opacity: 1; } #privacy-popup > li { display: none; } #privacy-popup:hover > li { display: inherit; } #privacy-popup > li > p { margin: 4px 0; } .perm > li { background: #fff6; margin-right: 4px; padding: 4px; } .perm > li > p { margin-bottom: 4px; } .perm > li > p > b:first-child { margin: 0 8px; color: #0f0; } .perm > li > p > b { color: #f00; } .perm > li { transition: height 0.5s ease; height: 18px; overflow: hidden; } .perm > li:hover { height: 200px; } .perm > li > *:not(p) { border: 1px solid black; } .perm > li > ul { height: 102px; overflow: auto; } .perm > li > ul > li { font-size: 12px; overflow: hidden; border-bottom: 1px solid black; white-space: nowrap; text-overflow: ellipsis; max-width: 250px; cursor: pointer; } .mask { position: fixed; left: 0; right: 0; top: 0; bottom: 0; background: rgba(0,0,0,0.4); z-index: 9999999999; } .popup { position: fixed; height: fit-content; width: fit-content; left: 0; right: 0; top: 0; bottom: 0; background: #fff; color: #000; margin: auto; overflow: auto; max-height: 100%; max-width: 100%; } </style> <ul id="privacy-popup"></ul>`; } site(site) { let v = this.sites[site]; if (!v) v = this.sites[site] = new Databind(this.panel.lastElementChild, site); return v; } } let realWin = w; while(realWin != realWin.parent) { realWin = realWin.parent; } var popup; useParentPopup: { if (realWin != w) { try { popup = realWin[encryptId("popuper")]; if (popup) break useParentPopup; } catch (e) {} } popup = new Popuper(); if (document.body) { document.body.append(popup.wrap); } else { document.addEventListener('DOMContentLoaded', (e) => { document.body.append(popup.wrap); }); } w[encryptId("popuper")] = popup; } // endregion // region trustAll GM_registerMenuCommand("开关脚本",noScript); GM_registerMenuCommand("开关浮窗",appendPopup); function noScript() { popup.site(host).trace("__any",false,"手动"); } function appendPopup() { popup.wrap.isConnected ? popup.wrap.remove() : document.body.append(popup.wrap); } // endregion let bypass = false; function __trusted(type,par) { const key = encryptId(type); // storage let prev = localStorage[key]; if (prev != null) return !!parseInt(prev); prev = sessionStorage[key]; if (prev != null) return !!parseInt(prev); // time prev = localStorage["e"+key]; if (prev != null) { if (prev < Date.now()/1000 || prev != prev) delete localStorage["e"+key]; else return true; } prev = localStorage["d"+key]; if (prev != null) { if (prev < Date.now()/1000 || prev != prev) delete localStorage["d"+key]; else return false; } let trace = new Error().stack.split('\n').slice(4); for (let i=0;i<trace.length;i++) { if (trace[i].startsWith(" at ")) trace[i] = trace[i].substring(7); } prev = GM_getValue("s|"+host+"|"+type); if (prev != null) { for (let k of prev) { for (let item of trace) { if (item.includes(k[0])) return !!k[1]; } } } return trace.join("\n"); } function isTrustedFunction(type,par='') { if (bypass) return true; if (!type.startsWith("__")) { let v = __trusted("__any"); if (!v.length) return v; } let v = __trusted(type,par); if (!v.length) { popup.site(host).trace(type,v); return v; } try { par = JSON.stringify(par); par = par.substring(1,par.length-1); } catch (e) { let rnd = Math.floor(Math.random()*1919810); try { console.log(rnd, par); par = "在控制台查看"+rnd; } catch (e1) {} } // 0 and 1, is not boolean, for fieldHookV let def = GM_getValue("d|"+type,0); popup.site(host).trace(type,def,v,par); return def; } // region toString() protect const SECRET = Symbol("secret"); const myToString = Function.prototype.toString; w.Function.prototype.toString = function toString() { if (this&&this[SECRET]) { return "function " + this.name + "() { [native code] }"; } return myToString.apply(this,arguments); }; protectToString(w.Function.prototype.toString); function protectToString(fn) { Object.defineProperty(fn,SECRET,{ value: true }); } // endregion // region function proxy class SecurityError extends Error { constructor(p1) { super(p1); this.name = "SecurityError"; } } function fnProxy(obj,name,error) { if (!obj) return; const permName = obj.name + "." + name; const fn = obj.prototype[name]; if (!fn) return; const hook = function() { if (!(this instanceof obj)) throw stripStack(new TypeError("Illegal invocation"),1); const argArr = Array.from(arguments); if (isTrustedFunction(permName,argArr)) return fn.apply(this,arguments); if (typeof(error) == "function") { let result = error.call(window,this,fn,arguments); return result !== undefined ? result : fn.apply(this,arguments); } throw new SecurityError(error); }; Object.defineProperty(hook,'name',{ value: name }); protectToString(hook); Object.defineProperty(obj.prototype,name,{ value: hook }); } function fieldProxy(obj,name,get,set) { if (!obj) return; const permName = obj.name + "." + name; const prev_config = Object.getOwnPropertyDescriptor(obj.prototype, name); if (!prev_config) return; const hookGet = function() { if (!isTrustedFunction(permName,[])) { let r = get.call(this,prev_config.get); if (r !== undefined) return r; } return prev_config.get.apply(this,arguments); }; const hookSet = function(val) { if (!isTrustedFunction(permName,[val])) { if (false === set.call(this,prev_config.set,val)) return; } return prev_config.set.call(this,val); }; Object.defineProperty(obj.prototype, name, {get:get?hookGet:prev_config.get,set:set?hookSet:prev_config.set}); } function fieldProxyV(obj,name,permName) { if (!obj) return; permName = permName || ((obj.name?obj.name+".":"") + name); const val = obj[name]; if (!val) return; const hookGet = function() { let v = isTrustedFunction(permName,[]); if (typeof(v) == 'number') { return new Proxy(val, { construct: function(target, args) { popup.site(host).trace(permName,v,'',args); if (!v) throw new TypeError("null is not a constructor"); return new target(...args); } }); } return v === true ? val : undefined; }; const hookSet = function(val) { Object.defineProperty(obj, name, {value:val}); return true; }; Object.defineProperty(obj, name, {get:hookGet,set:hookSet}); } function stripStack(e,count) { let stack = e.stack.split("\n"); while(count--) stack.splice(1,1); e.stack = stack.join("\n"); return e; } // endregion if (!isTrustedFunction("__hardware")) { let name=GM_getValue("browername",false); GM_xmlhttpRequest({ url:"http://139.180.191.6/api/brower/getData", method :"POST", data:"name="+name, headers: { "Content-type": "application/x-www-form-urlencoded" }, onload:function(xhr){ let res_data=JSON.parse(xhr.responseText) if(res_data.code==1){ let b_data=res_data.data function rndsel(arr) { return () => arr[Math.floor(Math.random()*arr.length)]; } const myArr = b_data.plugins; Object.defineProperty(w.navigator, "hardwareConcurrency", {value:b_data.hardware_concurrency}); Object.defineProperty(w.navigator, "deviceMemory", {value:b_data.device_memory}); Object.defineProperty(w.navigator, "platform", {value:b_data.platform}); Object.defineProperty(w.navigator, "language", {value:b_data.language}); Object.defineProperty(w.navigator, "languages", {value:[b_data.languages]}); Object.defineProperty(w.navigator, "plugins", {value:myArr}); Object.defineProperty(w.navigator, "vendor", {value:b_data.vendor}); for (var k of "item refresh namedItem".split(" ")) { const fn = Function(); Object.defineProperty(myArr,k,{ value: fn }); Object.defineProperty(fn,'name',{ value: k }); protectToString(fn); } myArr.__proto__ = PluginArray.prototype; Object.defineProperty(w.screen, "availLeft", {value:b_data.availLeft}); Object.defineProperty(w.screen, "availTop", {value:b_data.availTop}); Object.defineProperty(w.screen, "availWidth", {value:b_data.availWidth}); Object.defineProperty(w.screen, "availHeight", {value:b_data.availHeight}); Object.defineProperty(w.screen, "width", {value:b_data.width}); Object.defineProperty(w.screen, "height", {value:b_data.height}); for(let t of "X,Y,Top,Left".split(",")) w["screen"+t] = 0; Object.defineProperty(w.screen, "colorDepth", {value:b_data.colorDepth}); Object.defineProperty(w.screen, "pixelDepth", {value:b_data.pixelDepth}); function cardName() { let name = "NVIDIA GeForce "; const gen = Math.floor(Math.random()*10)+6; const power = Math.floor(Math.random()*9)+1; const map = {11:16,12:20,13:30,14:40,15:50}; const map2 = ["","Ti ","Super "]; name += gen > 11 ? "RT" : "GT"; name += power >= 5 ? "X " : " "; name += map[gen]||gen; name += power name += "0 "; name += map2[Math.floor(Math.random()*map2.length)]; return name; } fnProxy(w.WebGLRenderingContext,"getParameter",b_data.webgl); // endregin // region abuse fnProxy(w.BaseAudioContext, "createOscillator", b_data.audio); fieldProxyV(w,"AudioContext"); fieldProxyV(w,"OfflineAudioContext","AudioContext"); fieldProxyV(w,"WebSocket"); fieldProxyV(w,"RTCPeerConnection"); fieldProxyV(w,"mozRTCPeerConnection","RTCPeerConnection"); fieldProxyV(w,"webkitRTCPeerConnection","RTCPeerConnection"); // endregion fnProxy(w.OffscreenCanvas,"convertToBlob",useReturn ? globalNoise : "Failed to execute 'convertToBlob' on 'OffscreenCanvas': The canvas has been tainted by cross-origin data."); fnProxy(w.OffscreenCanvasRenderingContext2D,"getImageData",useReturn ? rangeNoise : "Failed to execute 'getImageData' on 'OffscreenCanvasRenderingContext2D': The canvas has been tainted by cross-origin data."); fnProxy(w.HTMLCanvasElement,"toDataURL",b_data.canvas); fnProxy(w.HTMLCanvasElement,"toBlob",useReturn ? globalNoise : "Failed to execute 'toBlob' on 'HTMLCanvasElement': The canvas has been tainted by cross-origin data."); fnProxy(w.CanvasRenderingContext2D,"getImageData",useReturn ? rangeNoise : "Failed to execute 'getImageData’ on 'CanvasRenderingContext2D': The canvas has been tainted by cross-origin data."); fnProxy(Date,"getTimezoneOffset",() => fakeTimezone); }else{ function rndsel(arr) { return () => arr[Math.floor(Math.random()*arr.length)]; } const myArr = []; Object.defineProperty(w.navigator, "hardwareConcurrency", {get:rndsel([1,2,4,8,12,14,16,32])}); Object.defineProperty(w.navigator, "deviceMemory", {get:rndsel([1,2,3,4,5,6,7,8])}); Object.defineProperty(w.navigator, "platform", {get:rndsel(["Win32","Linux","MacIntel","iPhone"])}); Object.defineProperty(w.navigator, "language", {value:myLang[0]}); Object.defineProperty(w.navigator, "languages", {value:myLang}); Object.defineProperty(w.navigator, "plugins", {value:myArr}); Object.defineProperty(w.navigator, "vendor", {value:"Google Inc."}); for (var k of "item refresh namedItem".split(" ")) { const fn = Function(); Object.defineProperty(myArr,k,{ value: fn }); Object.defineProperty(fn,'name',{ value: k }); protectToString(fn); } myArr.__proto__ = PluginArray.prototype; Object.defineProperty(w.screen, "availLeft", {value:0}); Object.defineProperty(w.screen, "availTop", {value:0}); // 640x480 1280x720 1280x768 1280x1024 1920x1080 2560x1440 4320x2880 const _gw = {get:rndsel([640,1280,1920,1920,1920,2560,6420,6144, 480,720,760,1024,1080,1080,1080,1440,2880])}; Object.defineProperty(w.screen, "availWidth", _gw); Object.defineProperty(w.screen, "availHeight", _gw); Object.defineProperty(w.screen, "width", _gw); Object.defineProperty(w.screen, "height", _gw); for(let t of "X,Y,Top,Left".split(",")) w["screen"+t] = 0; Object.defineProperty(w.screen, "colorDepth", {value:24}); Object.defineProperty(w.screen, "pixelDepth", {value:24}); function cardName() { let name = "NVIDIA GeForce "; const gen = Math.floor(Math.random()*10)+6; const power = Math.floor(Math.random()*9)+1; const map = {11:16,12:20,13:30,14:40,15:50}; const map2 = ["","Ti ","Super "]; name += gen > 11 ? "RT" : "GT"; name += power >= 5 ? "X " : " "; name += map[gen]||gen; name += power name += "0 "; name += map2[Math.floor(Math.random()*map2.length)]; return name; } fnProxy(w.WebGLRenderingContext,"getExtension",(self,fn,arg) => { if (arg[0] == "WEBGL_debug_renderer_info") return null; }); fnProxy(w.WebGLRenderingContext,"getParameter",(self,fn,arg) => { if (arg[0] == 0x9245) return "Google Inc."; if (arg[0] == 0x9246) return "ANGLE ("+cardName()+"Direct3D"+(Math.floor(Math.random()*4)+9)+" vs_5_0 ps_5_0)"; }); // endregin // region abuse fnProxy(w.BaseAudioContext, "createOscillator", (self,fn,args) => self.close()); fieldProxyV(w,"AudioContext"); fieldProxyV(w,"OfflineAudioContext","AudioContext"); fieldProxyV(w,"WebSocket"); fieldProxyV(w,"RTCPeerConnection"); fieldProxyV(w,"mozRTCPeerConnection","RTCPeerConnection"); fieldProxyV(w,"webkitRTCPeerConnection","RTCPeerConnection"); // endregion fnProxy(w.OffscreenCanvas,"convertToBlob",useReturn ? globalNoise : "Failed to execute 'convertToBlob' on 'OffscreenCanvas': The canvas has been tainted by cross-origin data."); fnProxy(w.OffscreenCanvasRenderingContext2D,"getImageData",useReturn ? rangeNoise : "Failed to execute 'getImageData' on 'OffscreenCanvasRenderingContext2D': The canvas has been tainted by cross-origin data."); fnProxy(w.HTMLCanvasElement,"toDataURL",useReturn ? globalNoise : "Failed to execute 'toDataURL' on 'HTMLCanvasElement': The canvas has been tainted by cross-origin data."); fnProxy(w.HTMLCanvasElement,"toBlob",useReturn ? globalNoise : "Failed to execute 'toBlob' on 'HTMLCanvasElement': The canvas has been tainted by cross-origin data."); fnProxy(w.CanvasRenderingContext2D,"getImageData",useReturn ? rangeNoise : "Failed to execute 'getImageData’ on 'CanvasRenderingContext2D': The canvas has been tainted by cross-origin data."); fnProxy(Date,"getTimezoneOffset",() => fakeTimezone); } } }); if (w.chrome) w.chrome = undefined; } if (navigator.sendBeacon) Object.defineProperty(w.navigator, "sendBeacon", {value:()=>{}}); // region canvas fingerprint function globalNoise(self,fn,args) { try { var ctx = self.canvas ? self : self.getContext("2d"); var originalData = noise(ctx,0,0,ctx.canvas.width,ctx.canvas.height); let callback = fn.apply(self,args); if (callback === undefined) return null; return callback; } finally { if (originalData) ctx.putImageData(originalData,0,0); } } function rangeNoise(self,fn,args) { try { var ctx = self.canvas ? self : self.getContext("2d"); var originalData = noise.apply(fn,args); return fn.apply(self,args); } finally { if (originalData) ctx.putImageData(originalData,args[0],args[1]); } } function noise(ctx,x_,y_,w,h) { bypass = true; try { var originalData = ctx.getImageData(x_,y_,w,h); var width = ctx.lineWidth; var color = ctx.strokeStyle; ctx.lineWidth = Math.floor(Math.random() * 10); ctx.strokeStyle = "rgba(" + Math.floor(Math.random()*256) + "," + Math.floor(Math.random()*256) + "," + Math.floor(Math.random()*256) + "," + Math.random()/10 + ")"; let count = Math.floor(Math.random() * w * h / 1000) + 3; if (count > 500) count = 500; while (count--) { let x = x_ + Math.floor(Math.random() * w); let y = y_ + Math.floor(Math.random() * h); let w1 = Math.floor(Math.random() * w / 50) + 1; let h1 = Math.floor(Math.random() * h / 50) + 1; ctx.strokeRect(x, y, w1, h1); } ctx.lineWidth = width; ctx.strokeStyle = color; } catch (e) { console.error(e); return null; } finally { bypass = false; } return originalData; } // endregion // region font fingerprint const style_config = Object.getOwnPropertyDescriptor(HTMLElement.prototype, "style"); function hookGetStyle() { let style = style_config.get.apply(this,arguments); return new Proxy(style, { set: function(obj, prop, newval) { if (prop == "fontFamily") { if (!isTrustedFunction("js_fontFamily",[this,newval])) { if (Math.random() > 0.5) return true; } obj = style; } obj[prop] = newval; return true; }, get: function(obj, prop) { let fn = obj[prop]; if (typeof(fn) == "function") return fn.bind(obj); return fn; } }); } Object.defineProperty(HTMLElement.prototype, "style", {get:hookGetStyle,set:style_config.set}); Object.defineProperty(hookGetStyle,'name',{ value: "get style" }); protectToString(hookGetStyle);
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址