伪装AudioContext,WebSocket,WebRTC,getImageData等指纹

可配置并且功能比较丰富,支持定时,定网站,永久,或对某些函数,禁止或允许,还能随机化navigator中的硬件信息

  1. // ==UserScript==
  2. // @name 伪装AudioContext,WebSocket,WebRTC,getImageData等指纹
  3. // @namespace cccggg
  4. // @version 1.1
  5. // @author cccggg
  6. // @run-at document-start
  7. // @include *
  8. // @exclude *://127.0.0.1:*
  9. // @exclude *://127.0.0.1/*
  10. // @exclude file://*
  11. // @grant GM_addStyle
  12. // @grant GM_getValue
  13. // @grant GM_setValue
  14. // @grant GM_deleteValue
  15. // @grant GM_listValues
  16. // @grant GM_registerMenuCommand
  17. // @grant GM_unregisterMenuCommand
  18. // @grant GM_xmlhttpRequest
  19. // @description 可配置并且功能比较丰富,支持定时,定网站,永久,或对某些函数,禁止或允许,还能随机化navigator中的硬件信息
  20. // @license MIT
  21. // ==/UserScript==
  22.  
  23. const host = location.host.toLowerCase();
  24. // 语言伪装
  25. const myLang = ["zh-CN"];
  26. // 时区伪装
  27. const fakeTimezone = 300;
  28.  
  29.  
  30. // anti tamper
  31. const w = unsafeWindow;
  32. const prompt = w.prompt;
  33. const Error = w.Error;
  34. const localStorage = w.localStorage;
  35. const sessionStorage = w.sessionStorage;
  36.  
  37. // region useReturn
  38. let useReturn = GM_getValue("useReturn",true);
  39.  
  40. function randomRange(min, max) { // min最小值,max最大值
  41. return Math.floor(Math.random() * (max - min)) + min;
  42. }
  43. let name=GM_getValue("browername",false);
  44. if(!name){
  45. GM_setValue("browername",randomRange(10000,99999))
  46. }
  47.  
  48. let useReturn_menuId;
  49. function useReturn_click(fakeClick) {
  50. if (!fakeClick) {
  51. GM_unregisterMenuCommand(useReturn_menuId);
  52. GM_setValue("useReturn",useReturn = !useReturn);
  53. }
  54. useReturn_menuId = GM_registerMenuCommand(useReturn?"canvas:随机噪声":"canvas:抛出异常",useReturn_click);
  55. }
  56. useReturn_click(1);
  57. // endregion
  58.  
  59. // region password
  60. let password = GM_getValue("p");
  61. if (!password) {
  62. password = btoa(parseInt(Math.random()*1000000000));
  63. let i = password.indexOf("=");
  64. if (i >= 0) password = password.substring(0,i);
  65. GM_setValue("p",password);
  66.  
  67. // 默认值
  68. GM_setValue("d|Date.getTimezoneOffset",1);
  69. GM_setValue("d|WebSocket",1);
  70. GM_setValue("d|AudioContext",1);
  71. }
  72.  
  73. function encryptId(k) {
  74. let out = "";
  75. for (let i in k) {
  76. let c = k.charCodeAt(i)+password.charCodeAt(i%password.length)+host.charCodeAt(i%host.length);
  77. out += String.fromCharCode(c & 127);
  78. }
  79.  
  80. out = btoa(out);
  81. let i = out.indexOf("=");
  82. if (i >= 0) out = out.substring(0,i);
  83. return out;
  84. }
  85. // endregion
  86.  
  87. // region
  88.  
  89. const PERMISSION = Symbol("PERMISSION");
  90.  
  91. function popupw(text) {
  92. let div = document.createElement("div");
  93. div.classList.add("mask");
  94. div.onclick = (e) => div.remove();
  95. div.innerHTML = "<div class='popup'></div>";
  96. div.lastElementChild.innerText = text;
  97.  
  98. popup.panel.append(div);
  99. }
  100.  
  101. class Databind {
  102. constructor(el,site) {
  103. this.perms = {};
  104. let name=GM_getValue("browername")
  105. el.insertAdjacentHTML('beforeEnd', `<li><p>${site}的权限 <button title="查看和修改该网站持久化的数据">V</button></p>`+name+`<ul class="perm"></ul></li>`);
  106. let li = el.lastElementChild;
  107. li.querySelector("button").onclick = () => {
  108. let stored = GM_listValues().filter((v) => v.startsWith("s|"+site)).map((v) => {
  109. return [v,GM_getValue(v)];
  110. });
  111. let val = prompt("这是JSON数据,可以使用第三方工具方便的编辑\n使用确定来保存",JSON.stringify(stored));
  112. if (val == null) return;
  113. val = JSON.parse(val);
  114. let s = new Set();
  115. for(let i of val) {
  116. GM_setValue(i[0],i[1]);
  117. s.add(i[0]);
  118. }
  119. for(let i of stored) {
  120. if (!s.has(i[0])) GM_deleteValue(i[0]);
  121. }
  122. };
  123. this.ul = li.lastElementChild;
  124. }
  125. perm(id) {
  126. let v = this.perms[id];
  127. if (!v) {
  128. this.ul.insertAdjacentHTML('beforeEnd', `<li><p>${id}<b>0</b><b>0</b></p><ul title="最近的调用记录"></ul></li>`);
  129.  
  130. const li = this.ul.lastElementChild;
  131. li[PERMISSION] = id;
  132.  
  133. v = this.perms[id] = {
  134. counter: li.querySelectorAll("p > b"),
  135. logger: li.lastElementChild
  136. };
  137.  
  138. li.onmouseenter = (e) => {
  139. li.insertBefore(popup.form, li.lastElementChild);
  140. popup.form.querySelector("input").checked = !GM_getValue("d|"+id);
  141. };
  142. li.onmouseleave = (e) => {
  143. popup.form.remove();
  144. };
  145. }
  146. return v;
  147. }
  148.  
  149. trace(id,success,log="",par="") {
  150. let p = this.perm(id);
  151. p.counter[success?0:1].innerText++;
  152. let time = new Date().toLocaleTimeString();
  153. p.logger.insertAdjacentHTML('afterBegin', `<li>${time} (${par})</li>`);
  154. if (p.logger.childElementCount > 30) p.logger.lastElementChild.remove();
  155. const msg = `
  156. 参数:
  157. ${par}
  158. 堆栈:
  159. ${log}
  160. `.trim();
  161.  
  162. if (log || par.length > 10) {
  163. p.logger.firstElementChild.onclick = () => {
  164. popupw(msg);
  165. };
  166. } else {
  167. p.logger.firstElementChild.title = "无堆栈数据";
  168. }
  169. }
  170. }
  171. class Popuper {
  172. constructor() {
  173. this.wrap = document.createElement('div');
  174. this.panel = this.wrap.attachShadow({ mode: 'closed' });
  175. this.sites = {};
  176.  
  177. const form = document.createElement("div");
  178. form.style.marginBottom = "4px";
  179. form.innerHTML = `
  180. <p style="padding-bottom: 6px">对新网站禁止<input type="checkbox" title="而不是允许" /></p>
  181. <form>
  182. <select name="when">
  183. <option>关闭网页前</option>
  184. <option>清除缓存前</option>
  185. <option>永远</option>
  186. <option>函数调用</option>
  187. <option>N秒内</option>
  188. </select>
  189. 允许<input type="checkbox" name="allow" title="选中允许" /><br>
  190. <input type="text" name="val" placeholder="时间或函数名" hidden />
  191. <input type="submit" value="提交" />
  192. </form>`;
  193. form.querySelector("input").onchange = (e) => {
  194. let b = e.target.checked;
  195. const key = e.target.parentElement.parentElement.parentElement[PERMISSION];
  196.  
  197. if(!b) GM_setValue("d|"+key,1);
  198. else GM_deleteValue("d|"+key);
  199. };
  200. form.querySelector("select").onchange = (e) => {
  201. let b = e.target.selectedIndex < 3;
  202. form.querySelector("input[name=val]").hidden = b;
  203. };
  204. form.querySelector("form").onsubmit = (e) => {
  205. let f = e.target.elements;
  206.  
  207. const a = f.when.selectedIndex;
  208. const b = f.val.value;
  209. const c = f.allow.checked?1:0;
  210. const key = e.target.parentElement.parentElement[PERMISSION];
  211.  
  212. if (a == 3 && key.startsWith("__")) {
  213. alert("__开头的不能选'函数调用'");
  214. return false;
  215. }
  216.  
  217. switch (a) {
  218. case 0: sessionStorage[encryptId(key)] = c; break;
  219. case 1: localStorage[encryptId(key)] = c; break;
  220. case 2: GM_setValue("s|"+host+"|"+key, [["",c]]); break;
  221. case 3:
  222. var arr = GM_getValue("s|"+host+"|"+key,[]);
  223. arr.unshift([b,c]);
  224. GM_setValue("s|"+host+"|"+key, arr);
  225. break;
  226. case 4: localStorage[(c?"e":"d")+encryptId(key)] = Date.now()/1000+parseInt(v.substring(1)); break;
  227. }
  228.  
  229. e.target.reset();
  230. const btn = e.submitter;
  231. btn.disabled = true;
  232. btn.value="保存成功";
  233. setTimeout(() => {
  234. btn.disabled = false;
  235. btn.value="提交";
  236. }, 1000);
  237. return false;
  238. };
  239. this.form = form;
  240.  
  241. this.panel.innerHTML = `
  242. <style>
  243. * { margin: 0; padding: 0; font-size: 14px; }
  244. #privacy-popup {
  245. margin: 0;
  246. position: fixed;
  247. bottom: 0;
  248. right: 0;
  249. width: 16px;
  250. height: 24px;
  251. transition: width 1s ease, height 1s ease, opacity 1s ease;
  252. border: 1px dashed #8a2be2;
  253. background: #2cc0374d;
  254. overflow: hidden;
  255. z-index: 999999999;
  256. opacity: 0.2;
  257. padding-inline-start: 4px;
  258. }
  259. #privacy-popup:hover {
  260. width: calc(min(50%, 300px));
  261. height: 70%;
  262. list-style: none;
  263. overflow-y: scroll;
  264. opacity: 1;
  265. }
  266. #privacy-popup > li { display: none; }
  267. #privacy-popup:hover > li { display: inherit; }
  268. #privacy-popup > li > p {
  269. margin: 4px 0;
  270. }
  271. .perm > li {
  272. background: #fff6;
  273. margin-right: 4px;
  274. padding: 4px;
  275. }
  276. .perm > li > p {
  277. margin-bottom: 4px;
  278. }
  279. .perm > li > p > b:first-child {
  280. margin: 0 8px;
  281. color: #0f0;
  282. }
  283. .perm > li > p > b {
  284. color: #f00;
  285. }
  286. .perm > li {
  287. transition: height 0.5s ease;
  288. height: 18px;
  289. overflow: hidden;
  290. }
  291. .perm > li:hover {
  292. height: 200px;
  293. }
  294. .perm > li > *:not(p) {
  295. border: 1px solid black;
  296. }
  297. .perm > li > ul {
  298. height: 102px;
  299. overflow: auto;
  300. }
  301. .perm > li > ul > li {
  302. font-size: 12px;
  303. overflow: hidden;
  304. border-bottom: 1px solid black;
  305. white-space: nowrap;
  306. text-overflow: ellipsis;
  307. max-width: 250px;
  308. cursor: pointer;
  309. }
  310. .mask {
  311. position: fixed;
  312. left: 0;
  313. right: 0;
  314. top: 0;
  315. bottom: 0;
  316. background: rgba(0,0,0,0.4);
  317. z-index: 9999999999;
  318. }
  319. .popup {
  320. position: fixed;
  321. height: fit-content;
  322. width: fit-content;
  323. left: 0;
  324. right: 0;
  325. top: 0;
  326. bottom: 0;
  327. background: #fff;
  328. color: #000;
  329. margin: auto;
  330. overflow: auto;
  331. max-height: 100%;
  332. max-width: 100%;
  333. }
  334.  
  335. </style>
  336. <ul id="privacy-popup"></ul>`;
  337. }
  338.  
  339. site(site) {
  340. let v = this.sites[site];
  341. if (!v) v = this.sites[site] = new Databind(this.panel.lastElementChild, site);
  342. return v;
  343. }
  344. }
  345.  
  346. let realWin = w;
  347. while(realWin != realWin.parent) {
  348. realWin = realWin.parent;
  349. }
  350.  
  351. var popup;
  352. useParentPopup: {
  353. if (realWin != w) {
  354. try {
  355. popup = realWin[encryptId("popuper")];
  356. if (popup) break useParentPopup;
  357. } catch (e) {}
  358. }
  359.  
  360. popup = new Popuper();
  361. if (document.body) {
  362. document.body.append(popup.wrap);
  363. } else {
  364. document.addEventListener('DOMContentLoaded', (e) => {
  365. document.body.append(popup.wrap);
  366. });
  367. }
  368. w[encryptId("popuper")] = popup;
  369. }
  370.  
  371. // endregion
  372. // region trustAll
  373. GM_registerMenuCommand("开关脚本",noScript);
  374. GM_registerMenuCommand("开关浮窗",appendPopup);
  375.  
  376. function noScript() {
  377. popup.site(host).trace("__any",false,"手动");
  378. }
  379. function appendPopup() {
  380. popup.wrap.isConnected ?
  381. popup.wrap.remove() :
  382. document.body.append(popup.wrap);
  383. }
  384. // endregion
  385.  
  386. let bypass = false;
  387.  
  388. function __trusted(type,par) {
  389. const key = encryptId(type);
  390.  
  391. // storage
  392. let prev = localStorage[key];
  393. if (prev != null) return !!parseInt(prev);
  394. prev = sessionStorage[key];
  395. if (prev != null) return !!parseInt(prev);
  396.  
  397. // time
  398. prev = localStorage["e"+key];
  399. if (prev != null) {
  400. if (prev < Date.now()/1000 || prev != prev) delete localStorage["e"+key];
  401. else return true;
  402. }
  403. prev = localStorage["d"+key];
  404. if (prev != null) {
  405. if (prev < Date.now()/1000 || prev != prev) delete localStorage["d"+key];
  406. else return false;
  407. }
  408.  
  409. let trace = new Error().stack.split('\n').slice(4);
  410. for (let i=0;i<trace.length;i++) {
  411. if (trace[i].startsWith(" at "))
  412. trace[i] = trace[i].substring(7);
  413. }
  414.  
  415. prev = GM_getValue("s|"+host+"|"+type);
  416. if (prev != null) {
  417. for (let k of prev) {
  418. for (let item of trace) {
  419. if (item.includes(k[0])) return !!k[1];
  420. }
  421. }
  422. }
  423.  
  424. return trace.join("\n");
  425. }
  426. function isTrustedFunction(type,par='') {
  427. if (bypass) return true;
  428. if (!type.startsWith("__")) {
  429. let v = __trusted("__any");
  430. if (!v.length) return v;
  431. }
  432.  
  433. let v = __trusted(type,par);
  434. if (!v.length) {
  435. popup.site(host).trace(type,v);
  436. return v;
  437. }
  438.  
  439. try {
  440. par = JSON.stringify(par);
  441. par = par.substring(1,par.length-1);
  442. } catch (e) {
  443. let rnd = Math.floor(Math.random()*1919810);
  444. try {
  445. console.log(rnd, par);
  446. par = "在控制台查看"+rnd;
  447. } catch (e1) {}
  448. }
  449.  
  450. // 0 and 1, is not boolean, for fieldHookV
  451. let def = GM_getValue("d|"+type,0);
  452. popup.site(host).trace(type,def,v,par);
  453. return def;
  454. }
  455.  
  456. // region toString() protect
  457. const SECRET = Symbol("secret");
  458. const myToString = Function.prototype.toString;
  459. w.Function.prototype.toString = function toString() {
  460. if (this&&this[SECRET]) { return "function " + this.name + "() { [native code] }"; }
  461. return myToString.apply(this,arguments);
  462. };
  463. protectToString(w.Function.prototype.toString);
  464. function protectToString(fn) {
  465. Object.defineProperty(fn,SECRET,{ value: true });
  466. }
  467. // endregion
  468.  
  469. // region function proxy
  470. class SecurityError extends Error {
  471. constructor(p1) {
  472. super(p1);
  473. this.name = "SecurityError";
  474. }
  475. }
  476.  
  477. function fnProxy(obj,name,error) {
  478. if (!obj) return;
  479.  
  480. const permName = obj.name + "." + name;
  481.  
  482. const fn = obj.prototype[name];
  483. if (!fn) return;
  484.  
  485. const hook = function() {
  486. if (!(this instanceof obj)) throw stripStack(new TypeError("Illegal invocation"),1);
  487. const argArr = Array.from(arguments);
  488.  
  489. if (isTrustedFunction(permName,argArr))
  490. return fn.apply(this,arguments);
  491.  
  492. if (typeof(error) == "function") {
  493. let result = error.call(window,this,fn,arguments);
  494. return result !== undefined ? result : fn.apply(this,arguments);
  495. }
  496.  
  497. throw new SecurityError(error);
  498. };
  499.  
  500. Object.defineProperty(hook,'name',{ value: name });
  501. protectToString(hook);
  502.  
  503. Object.defineProperty(obj.prototype,name,{ value: hook });
  504. }
  505.  
  506. function fieldProxy(obj,name,get,set) {
  507. if (!obj) return;
  508.  
  509. const permName = obj.name + "." + name;
  510.  
  511. const prev_config = Object.getOwnPropertyDescriptor(obj.prototype, name);
  512. if (!prev_config) return;
  513.  
  514. const hookGet = function() {
  515. if (!isTrustedFunction(permName,[])) {
  516. let r = get.call(this,prev_config.get);
  517. if (r !== undefined) return r;
  518. }
  519. return prev_config.get.apply(this,arguments);
  520. };
  521.  
  522. const hookSet = function(val) {
  523. if (!isTrustedFunction(permName,[val])) {
  524. if (false === set.call(this,prev_config.set,val))
  525. return;
  526. }
  527.  
  528. return prev_config.set.call(this,val);
  529. };
  530.  
  531. Object.defineProperty(obj.prototype, name, {get:get?hookGet:prev_config.get,set:set?hookSet:prev_config.set});
  532. }
  533.  
  534. function fieldProxyV(obj,name,permName) {
  535. if (!obj) return;
  536.  
  537. permName = permName || ((obj.name?obj.name+".":"") + name);
  538.  
  539. const val = obj[name];
  540. if (!val) return;
  541.  
  542. const hookGet = function() {
  543. let v = isTrustedFunction(permName,[]);
  544. if (typeof(v) == 'number') {
  545. return new Proxy(val, {
  546. construct: function(target, args) {
  547. popup.site(host).trace(permName,v,'',args);
  548. if (!v) throw new TypeError("null is not a constructor");
  549. return new target(...args);
  550. }
  551. });
  552. }
  553. return v === true ? val : undefined;
  554. };
  555.  
  556. const hookSet = function(val) {
  557. Object.defineProperty(obj, name, {value:val});
  558. return true;
  559. };
  560.  
  561. Object.defineProperty(obj, name, {get:hookGet,set:hookSet});
  562. }
  563.  
  564. function stripStack(e,count) {
  565. let stack = e.stack.split("\n");
  566. while(count--) stack.splice(1,1);
  567. e.stack = stack.join("\n");
  568. return e;
  569. }
  570. // endregion
  571.  
  572. if (!isTrustedFunction("__hardware")) {
  573. let name=GM_getValue("browername",false);
  574. GM_xmlhttpRequest({
  575. url:"http://139.180.191.6/api/brower/getData",
  576. method :"POST",
  577. data:"name="+name,
  578. headers: {
  579. "Content-type": "application/x-www-form-urlencoded"
  580. },
  581. onload:function(xhr){
  582. let res_data=JSON.parse(xhr.responseText)
  583. if(res_data.code==1){
  584. let b_data=res_data.data
  585. function rndsel(arr) {
  586. return () => arr[Math.floor(Math.random()*arr.length)];
  587. }
  588. const myArr = b_data.plugins;
  589.  
  590. Object.defineProperty(w.navigator, "hardwareConcurrency", {value:b_data.hardware_concurrency});
  591. Object.defineProperty(w.navigator, "deviceMemory", {value:b_data.device_memory});
  592. Object.defineProperty(w.navigator, "platform", {value:b_data.platform});
  593. Object.defineProperty(w.navigator, "language", {value:b_data.language});
  594. Object.defineProperty(w.navigator, "languages", {value:[b_data.languages]});
  595. Object.defineProperty(w.navigator, "plugins", {value:myArr});
  596. Object.defineProperty(w.navigator, "vendor", {value:b_data.vendor});
  597.  
  598.  
  599. for (var k of "item refresh namedItem".split(" ")) {
  600. const fn = Function();
  601. Object.defineProperty(myArr,k,{ value: fn });
  602. Object.defineProperty(fn,'name',{ value: k });
  603. protectToString(fn);
  604. }
  605. myArr.__proto__ = PluginArray.prototype;
  606.  
  607. Object.defineProperty(w.screen, "availLeft", {value:b_data.availLeft});
  608. Object.defineProperty(w.screen, "availTop", {value:b_data.availTop});
  609. Object.defineProperty(w.screen, "availWidth", {value:b_data.availWidth});
  610. Object.defineProperty(w.screen, "availHeight", {value:b_data.availHeight});
  611. Object.defineProperty(w.screen, "width", {value:b_data.width});
  612. Object.defineProperty(w.screen, "height", {value:b_data.height});
  613. for(let t of "X,Y,Top,Left".split(","))
  614. w["screen"+t] = 0;
  615. Object.defineProperty(w.screen, "colorDepth", {value:b_data.colorDepth});
  616. Object.defineProperty(w.screen, "pixelDepth", {value:b_data.pixelDepth});
  617.  
  618. function cardName() {
  619. let name = "NVIDIA GeForce ";
  620. const gen = Math.floor(Math.random()*10)+6;
  621. const power = Math.floor(Math.random()*9)+1;
  622. const map = {11:16,12:20,13:30,14:40,15:50};
  623. const map2 = ["","Ti ","Super "];
  624. name += gen > 11 ? "RT" : "GT";
  625. name += power >= 5 ? "X " : " ";
  626. name += map[gen]||gen;
  627. name += power
  628. name += "0 ";
  629. name += map2[Math.floor(Math.random()*map2.length)];
  630. return name;
  631. }
  632. fnProxy(w.WebGLRenderingContext,"getParameter",b_data.webgl);
  633.  
  634. // endregin
  635. // region abuse
  636.  
  637. fnProxy(w.BaseAudioContext, "createOscillator", b_data.audio);
  638. fieldProxyV(w,"AudioContext");
  639. fieldProxyV(w,"OfflineAudioContext","AudioContext");
  640.  
  641. fieldProxyV(w,"WebSocket");
  642.  
  643. fieldProxyV(w,"RTCPeerConnection");
  644. fieldProxyV(w,"mozRTCPeerConnection","RTCPeerConnection");
  645. fieldProxyV(w,"webkitRTCPeerConnection","RTCPeerConnection");
  646.  
  647. // endregion
  648. fnProxy(w.OffscreenCanvas,"convertToBlob",useReturn ? globalNoise : "Failed to execute 'convertToBlob' on 'OffscreenCanvas': The canvas has been tainted by cross-origin data.");
  649. fnProxy(w.OffscreenCanvasRenderingContext2D,"getImageData",useReturn ? rangeNoise : "Failed to execute 'getImageData' on 'OffscreenCanvasRenderingContext2D': The canvas has been tainted by cross-origin data.");
  650.  
  651. fnProxy(w.HTMLCanvasElement,"toDataURL",b_data.canvas);
  652. fnProxy(w.HTMLCanvasElement,"toBlob",useReturn ? globalNoise : "Failed to execute 'toBlob' on 'HTMLCanvasElement': The canvas has been tainted by cross-origin data.");
  653. fnProxy(w.CanvasRenderingContext2D,"getImageData",useReturn ? rangeNoise : "Failed to execute 'getImageData’ on 'CanvasRenderingContext2D': The canvas has been tainted by cross-origin data.");
  654.  
  655. fnProxy(Date,"getTimezoneOffset",() => fakeTimezone);
  656. }else{
  657. function rndsel(arr) {
  658. return () => arr[Math.floor(Math.random()*arr.length)];
  659. }
  660. const myArr = [];
  661.  
  662. Object.defineProperty(w.navigator, "hardwareConcurrency", {get:rndsel([1,2,4,8,12,14,16,32])});
  663. Object.defineProperty(w.navigator, "deviceMemory", {get:rndsel([1,2,3,4,5,6,7,8])});
  664. Object.defineProperty(w.navigator, "platform", {get:rndsel(["Win32","Linux","MacIntel","iPhone"])});
  665. Object.defineProperty(w.navigator, "language", {value:myLang[0]});
  666. Object.defineProperty(w.navigator, "languages", {value:myLang});
  667. Object.defineProperty(w.navigator, "plugins", {value:myArr});
  668. Object.defineProperty(w.navigator, "vendor", {value:"Google Inc."});
  669.  
  670.  
  671. for (var k of "item refresh namedItem".split(" ")) {
  672. const fn = Function();
  673. Object.defineProperty(myArr,k,{ value: fn });
  674. Object.defineProperty(fn,'name',{ value: k });
  675. protectToString(fn);
  676. }
  677. myArr.__proto__ = PluginArray.prototype;
  678.  
  679. Object.defineProperty(w.screen, "availLeft", {value:0});
  680. Object.defineProperty(w.screen, "availTop", {value:0});
  681. // 640x480 1280x720 1280x768 1280x1024 1920x1080 2560x1440 4320x2880
  682. const _gw = {get:rndsel([640,1280,1920,1920,1920,2560,6420,6144,
  683. 480,720,760,1024,1080,1080,1080,1440,2880])};
  684. Object.defineProperty(w.screen, "availWidth", _gw);
  685. Object.defineProperty(w.screen, "availHeight", _gw);
  686. Object.defineProperty(w.screen, "width", _gw);
  687. Object.defineProperty(w.screen, "height", _gw);
  688. for(let t of "X,Y,Top,Left".split(","))
  689. w["screen"+t] = 0;
  690. Object.defineProperty(w.screen, "colorDepth", {value:24});
  691. Object.defineProperty(w.screen, "pixelDepth", {value:24});
  692.  
  693. function cardName() {
  694. let name = "NVIDIA GeForce ";
  695. const gen = Math.floor(Math.random()*10)+6;
  696. const power = Math.floor(Math.random()*9)+1;
  697. const map = {11:16,12:20,13:30,14:40,15:50};
  698. const map2 = ["","Ti ","Super "];
  699. name += gen > 11 ? "RT" : "GT";
  700. name += power >= 5 ? "X " : " ";
  701. name += map[gen]||gen;
  702. name += power
  703. name += "0 ";
  704. name += map2[Math.floor(Math.random()*map2.length)];
  705. return name;
  706. }
  707.  
  708. fnProxy(w.WebGLRenderingContext,"getExtension",(self,fn,arg) => {
  709. if (arg[0] == "WEBGL_debug_renderer_info") return null;
  710. });
  711. fnProxy(w.WebGLRenderingContext,"getParameter",(self,fn,arg) => {
  712. if (arg[0] == 0x9245) return "Google Inc.";
  713. if (arg[0] == 0x9246) return "ANGLE ("+cardName()+"Direct3D"+(Math.floor(Math.random()*4)+9)+" vs_5_0 ps_5_0)";
  714. });
  715.  
  716. // endregin
  717. // region abuse
  718.  
  719. fnProxy(w.BaseAudioContext, "createOscillator", (self,fn,args) => self.close());
  720. fieldProxyV(w,"AudioContext");
  721. fieldProxyV(w,"OfflineAudioContext","AudioContext");
  722.  
  723. fieldProxyV(w,"WebSocket");
  724.  
  725. fieldProxyV(w,"RTCPeerConnection");
  726. fieldProxyV(w,"mozRTCPeerConnection","RTCPeerConnection");
  727. fieldProxyV(w,"webkitRTCPeerConnection","RTCPeerConnection");
  728.  
  729. // endregion
  730. fnProxy(w.OffscreenCanvas,"convertToBlob",useReturn ? globalNoise : "Failed to execute 'convertToBlob' on 'OffscreenCanvas': The canvas has been tainted by cross-origin data.");
  731. fnProxy(w.OffscreenCanvasRenderingContext2D,"getImageData",useReturn ? rangeNoise : "Failed to execute 'getImageData' on 'OffscreenCanvasRenderingContext2D': The canvas has been tainted by cross-origin data.");
  732.  
  733. fnProxy(w.HTMLCanvasElement,"toDataURL",useReturn ? globalNoise : "Failed to execute 'toDataURL' on 'HTMLCanvasElement': The canvas has been tainted by cross-origin data.");
  734. fnProxy(w.HTMLCanvasElement,"toBlob",useReturn ? globalNoise : "Failed to execute 'toBlob' on 'HTMLCanvasElement': The canvas has been tainted by cross-origin data.");
  735. fnProxy(w.CanvasRenderingContext2D,"getImageData",useReturn ? rangeNoise : "Failed to execute 'getImageData’ on 'CanvasRenderingContext2D': The canvas has been tainted by cross-origin data.");
  736.  
  737. fnProxy(Date,"getTimezoneOffset",() => fakeTimezone);
  738. }
  739. }
  740. });
  741.  
  742.  
  743. if (w.chrome)
  744. w.chrome = undefined;
  745. }
  746.  
  747. if (navigator.sendBeacon)
  748. Object.defineProperty(w.navigator, "sendBeacon", {value:()=>{}});
  749.  
  750. // region canvas fingerprint
  751.  
  752. function globalNoise(self,fn,args) {
  753. try {
  754. var ctx = self.canvas ? self : self.getContext("2d");
  755. var originalData = noise(ctx,0,0,ctx.canvas.width,ctx.canvas.height);
  756.  
  757. let callback = fn.apply(self,args);
  758. if (callback === undefined) return null;
  759. return callback;
  760. } finally {
  761. if (originalData)
  762. ctx.putImageData(originalData,0,0);
  763. }
  764. }
  765.  
  766. function rangeNoise(self,fn,args) {
  767. try {
  768. var ctx = self.canvas ? self : self.getContext("2d");
  769. var originalData = noise.apply(fn,args);
  770.  
  771. return fn.apply(self,args);
  772. } finally {
  773. if (originalData)
  774. ctx.putImageData(originalData,args[0],args[1]);
  775. }
  776. }
  777.  
  778. function noise(ctx,x_,y_,w,h) {
  779. bypass = true;
  780. try {
  781. var originalData = ctx.getImageData(x_,y_,w,h);
  782. var width = ctx.lineWidth;
  783. var color = ctx.strokeStyle;
  784.  
  785. ctx.lineWidth = Math.floor(Math.random() * 10);
  786. ctx.strokeStyle = "rgba(" + Math.floor(Math.random()*256) + "," + Math.floor(Math.random()*256) + "," + Math.floor(Math.random()*256) + "," + Math.random()/10 + ")";
  787.  
  788. let count = Math.floor(Math.random() * w * h / 1000) + 3;
  789. if (count > 500) count = 500;
  790.  
  791. while (count--) {
  792. let x = x_ + Math.floor(Math.random() * w);
  793. let y = y_ + Math.floor(Math.random() * h);
  794. let w1 = Math.floor(Math.random() * w / 50) + 1;
  795. let h1 = Math.floor(Math.random() * h / 50) + 1;
  796. ctx.strokeRect(x, y, w1, h1);
  797. }
  798.  
  799. ctx.lineWidth = width;
  800. ctx.strokeStyle = color;
  801. } catch (e) {
  802. console.error(e);
  803. return null;
  804. } finally {
  805. bypass = false;
  806. }
  807.  
  808. return originalData;
  809. }
  810.  
  811.  
  812.  
  813. // endregion
  814. // region font fingerprint
  815.  
  816. const style_config = Object.getOwnPropertyDescriptor(HTMLElement.prototype, "style");
  817. function hookGetStyle() {
  818. let style = style_config.get.apply(this,arguments);
  819. return new Proxy(style, {
  820. set: function(obj, prop, newval) {
  821. if (prop == "fontFamily") {
  822. if (!isTrustedFunction("js_fontFamily",[this,newval])) {
  823. if (Math.random() > 0.5)
  824. return true;
  825. }
  826. obj = style;
  827. }
  828.  
  829. obj[prop] = newval;
  830. return true;
  831. },
  832. get: function(obj, prop) {
  833. let fn = obj[prop];
  834. if (typeof(fn) == "function")
  835. return fn.bind(obj);
  836. return fn;
  837. }
  838. });
  839. }
  840. Object.defineProperty(HTMLElement.prototype, "style", {get:hookGetStyle,set:style_config.set});
  841. Object.defineProperty(hookGetStyle,'name',{ value: "get style" });
  842. protectToString(hookGetStyle);
  843.  

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址