开发工具限制绕过

绕过网站对开发工具的限制,具有增强的保护功能

  1. // ==UserScript==
  2. // @name DevTools Bypass
  3. // @name:vi Bỏ Qua Chặn DevTools
  4. // @name:zh-CN 开发工具限制绕过
  5. // @name:ru Разблокировка DevTools
  6. // @namespace https://gf.qytechs.cn/vi/users/1195312-renji-yuusei
  7. // @version 2024.12.23.2
  8. // @description Bypass for website restrictions on DevTools with enhanced protection
  9. // @description:vi Bỏ qua các hạn chế của trang web về DevTools với bảo vệ nâng cao
  10. // @description:zh-CN 绕过网站对开发工具的限制,具有增强的保护功能
  11. // @description:ru Разблокировка DevTools с усиленной защитой
  12. // @author Yuusei
  13. // @match *://*/*
  14. // @grant unsafeWindow
  15. // @run-at document-start
  16. // @license GPL-3.0-only
  17. // ==/UserScript==
  18.  
  19. (() => {
  20. 'use strict';
  21.  
  22. // Constants
  23. const CONSTANTS = {
  24. PREFIX: '[DevTools Bypass]',
  25. LOG_LEVELS: {
  26. INFO: 'info',
  27. WARN: 'warn',
  28. ERROR: 'error',
  29. DEBUG: 'debug'
  30. },
  31. TIME_THRESHOLDS: {
  32. DEBUGGER: 80,
  33. CACHE: 30000
  34. }
  35. };
  36.  
  37. // Configuration
  38. const config = {
  39. debugPatterns: {
  40. basic: /[;\s]*(?:debugger|debug(?:ger)?|breakpoint|console\.[a-z]+)[\s;]*/gi,
  41. advanced: /(?:debugger|debug(?:ger)?|breakpoint|devtools?)(?:\s*\{[\s\S]*?\}|\s*\([^)]*\)|\s*;|\s*$)/gi,
  42. timing: /(?:performance(?:\.timing)?|Date)\.(?:now|getTime)\(\)|new\s+Date(?:\s*\(\s*\))?\s*\.getTime\(\)/gi,
  43. eval: /(?:eval|Function|setTimeout|setInterval)\s*\(\s*(?:[`'"].*?(?:debugger|debug|breakpoint).*?[`'"]|\{[\s\S]*?(?:debugger|debug|breakpoint)[\s\S]*?\})\s*\)/gi,
  44. devtools: /(?:isDevTools?|devtools?|debugMode|debug_mode|debugEnabled)\s*[=:]\s*(?:true|1|!0|yes)/gi,
  45. consoleCheck: /console\.(?:log|warn|error|info|debug|trace|dir|table)\s*\([^)]*\)/gi,
  46. functionDebug: /function\s*[^(]*\([^)]*\)\s*\{(?:\s|.)*?(?:debugger|debug|breakpoint)(?:\s|.)*?\}/gi,
  47. sourceMap: /\/\/[#@]\s*source(?:Mapping)?URL\s*=\s*(?:data:|https?:)?\/\/.*?$/gm,
  48. debugStrings: /(['"`])(?:(?!\1).)*?(?:debug|debugger|breakpoint|devtools?)(?:(?!\1).)*?\1/gi,
  49. debugComments: /\/\*[\s\S]*?(?:debug|debugger|breakpoint|devtools?)[\s\S]*?\*\/|\/\/.*(?:debug|debugger|breakpoint|devtools?).*$/gim
  50. },
  51. consoleProps: ['log', 'warn', 'error', 'info', 'debug', 'trace', 'dir', 'dirxml', 'table', 'profile', 'group', 'groupEnd', 'time', 'timeEnd'],
  52. cutoffs: {
  53. debugger: { amount: 30, within: CONSTANTS.TIME_THRESHOLDS.CACHE },
  54. debuggerThrow: { amount: 30, within: CONSTANTS.TIME_THRESHOLDS.CACHE }
  55. },
  56. bypassTriggers: {
  57. timeThreshold: CONSTANTS.TIME_THRESHOLDS.DEBUGGER,
  58. stackDepth: 30,
  59. recursionLimit: 50
  60. },
  61. logging: {
  62. enabled: true,
  63. prefix: CONSTANTS.PREFIX,
  64. levels: Object.values(CONSTANTS.LOG_LEVELS),
  65. detailedErrors: true
  66. },
  67. protection: {
  68. preventDevToolsKeys: true,
  69. hideStackTraces: true,
  70. sanitizeErrors: true,
  71. obfuscateTimers: true,
  72. preventRightClick: true,
  73. preventViewSource: true,
  74. preventCopy: true,
  75. preventPaste: true,
  76. preventPrint: true,
  77. preventSave: true
  78. }
  79. };
  80.  
  81. // Logger class
  82. class Logger {
  83. static #instance;
  84. #lastLog = 0;
  85. #logCount = 0;
  86. #logBuffer = [];
  87.  
  88. constructor() {
  89. if (Logger.#instance) {
  90. return Logger.#instance;
  91. }
  92. Logger.#instance = this;
  93. this.#setupBufferFlush();
  94. }
  95.  
  96. #setupBufferFlush() {
  97. setInterval(() => {
  98. if (this.#logBuffer.length) {
  99. this.#flushBuffer();
  100. }
  101. }, 1000);
  102. }
  103.  
  104. #flushBuffer() {
  105. this.#logBuffer.forEach(({level, args}) => {
  106. console[level](config.logging.prefix, ...args);
  107. });
  108. this.#logBuffer = [];
  109. }
  110.  
  111. #shouldLog() {
  112. const now = Date.now();
  113. if (now - this.#lastLog > 1000) {
  114. this.#logCount = 0;
  115. }
  116. this.#lastLog = now;
  117. return ++this.#logCount <= 10;
  118. }
  119.  
  120. #log(level, ...args) {
  121. if (!config.logging.enabled || !this.#shouldLog()) return;
  122. this.#logBuffer.push({ level, args });
  123. }
  124.  
  125. info(...args) { this.#log(CONSTANTS.LOG_LEVELS.INFO, ...args); }
  126. warn(...args) { this.#log(CONSTANTS.LOG_LEVELS.WARN, ...args); }
  127. error(...args) { this.#log(CONSTANTS.LOG_LEVELS.ERROR, ...args); }
  128. debug(...args) { this.#log(CONSTANTS.LOG_LEVELS.DEBUG, ...args); }
  129. }
  130.  
  131. // Original functions store
  132. const OriginalFunctions = {
  133. defineProperty: Object.defineProperty,
  134. getOwnPropertyDescriptor: Object.getOwnPropertyDescriptor,
  135. setTimeout: window.setTimeout,
  136. setInterval: window.setInterval,
  137. Date: window.Date,
  138. now: Date.now,
  139. performance: window.performance,
  140. Function: window.Function,
  141. eval: window.eval,
  142. console: {},
  143. toString: Function.prototype.toString,
  144. preventDefault: Event.prototype.preventDefault,
  145. getComputedStyle: window.getComputedStyle,
  146. addEventListener: window.addEventListener,
  147. removeEventListener: window.removeEventListener,
  148. fetch: window.fetch,
  149. XMLHttpRequest: window.XMLHttpRequest,
  150.  
  151. initConsole() {
  152. config.consoleProps.forEach(prop => {
  153. if (console[prop]) {
  154. this.console[prop] = console[prop].bind(console);
  155. }
  156. });
  157. }
  158. };
  159.  
  160. OriginalFunctions.initConsole();
  161.  
  162. // Debugger detector
  163. class DebuggerDetector {
  164. static #detectionCache = new Map();
  165. static #detectionHistory = [];
  166.  
  167. static isPresent() {
  168. try {
  169. const cacheKey = 'debugger_check';
  170. const cached = this.#detectionCache.get(cacheKey);
  171. if (cached && Date.now() - cached.timestamp < 500) {
  172. return cached.result;
  173. }
  174.  
  175. const startTime = OriginalFunctions.now.call(Date);
  176. new Function('debugger;')();
  177. const timeDiff = OriginalFunctions.now.call(Date) - startTime;
  178.  
  179. const result = timeDiff > config.bypassTriggers.timeThreshold;
  180. this.#detectionCache.set(cacheKey, {
  181. result,
  182. timestamp: Date.now()
  183. });
  184.  
  185. this.#detectionHistory.push({
  186. timestamp: Date.now(),
  187. result,
  188. timeDiff
  189. });
  190.  
  191. // Keep history for 5 minutes
  192. const fiveMinutesAgo = Date.now() - 300000;
  193. this.#detectionHistory = this.#detectionHistory.filter(entry => entry.timestamp > fiveMinutesAgo);
  194.  
  195. return result;
  196. } catch {
  197. return false;
  198. }
  199. }
  200.  
  201. static analyzeStack() {
  202. try {
  203. const stack = new Error().stack;
  204. const frames = stack.split('\n');
  205. const uniqueFrames = new Set(frames);
  206.  
  207. return {
  208. depth: frames.length,
  209. hasDebugKeywords: frames.some(frame =>
  210. Object.values(config.debugPatterns).some(pattern => pattern.test(frame))
  211. ),
  212. isRecursive: uniqueFrames.size < frames.length,
  213. suspiciousPatterns: this.#detectSuspiciousPatterns(stack),
  214. stackHash: this.#generateStackHash(stack)
  215. };
  216. } catch {
  217. return {
  218. depth: 0,
  219. hasDebugKeywords: false,
  220. isRecursive: false,
  221. suspiciousPatterns: [],
  222. stackHash: ''
  223. };
  224. }
  225. }
  226.  
  227. static #detectSuspiciousPatterns(stack) {
  228. const patterns = [
  229. /eval.*?\(/g,
  230. /Function.*?\(/g,
  231. /debugger/g,
  232. /debug/g,
  233. /DevTools/g,
  234. /console\./g,
  235. /chrome-extension/g
  236. ];
  237. return patterns.filter(pattern => pattern.test(stack));
  238. }
  239.  
  240. static #generateStackHash(stack) {
  241. return Array.from(stack).reduce((hash, char) => {
  242. hash = ((hash << 5) - hash) + char.charCodeAt(0);
  243. return hash & hash;
  244. }, 0).toString(36);
  245. }
  246.  
  247. static getDetectionStats() {
  248. const now = Date.now();
  249. const recentDetections = this.#detectionHistory.filter(entry =>
  250. entry.timestamp > now - 60000
  251. );
  252.  
  253. return {
  254. total: recentDetections.length,
  255. positive: recentDetections.filter(entry => entry.result).length,
  256. averageTime: recentDetections.reduce((acc, curr) =>
  257. acc + curr.timeDiff, 0) / recentDetections.length || 0
  258. };
  259. }
  260. }
  261.  
  262. // Helper functions
  263. const BypassHelpers = {
  264. disableAntiDebugging: {
  265. patchTimingChecks() {
  266. const originalNow = Date.now;
  267. Date.now = function() {
  268. return originalNow.call(this) - Math.random() * 100;
  269. };
  270. },
  271.  
  272. patchStackTraces() {
  273. Error.prepareStackTrace = (_, stack) =>
  274. stack.filter(frame => !frame.toString().includes('debugger'));
  275. },
  276.  
  277. patchDebugChecks() {
  278. const noop = () => {};
  279. window.debug = noop;
  280. window.debugger = noop;
  281. window.isDebuggerEnabled = false;
  282. }
  283. },
  284.  
  285. debugTools: {
  286. monitorAPICalls() {
  287. const originalFetch = window.fetch;
  288. window.fetch = async (...args) => {
  289. console.log('[API Call]', ...args);
  290. return originalFetch.apply(this, args);
  291. };
  292. },
  293.  
  294. monitorDOMEvents() {
  295. new MutationObserver(mutations => {
  296. mutations.forEach(mutation => {
  297. console.log('[DOM Change]', mutation);
  298. });
  299. }).observe(document.body, {
  300. childList: true,
  301. subtree: true
  302. });
  303. }
  304. }
  305. };
  306.  
  307. // Protection class
  308. class Protection {
  309. static applyAll() {
  310. this.#protectTimers();
  311. this.#protectTiming();
  312. this.#protectFunction();
  313. this.#protectStack();
  314. this.#protectEval();
  315. this.#protectConsole();
  316. this.#setupMutationObserver();
  317. this.#protectDevToolsKeys();
  318. this.#protectRightClick();
  319. this.#protectViewSource();
  320. this.#protectNetwork();
  321. this.#protectStorage();
  322. this.#protectClipboard();
  323. this.#protectPrinting();
  324. this.#protectWebWorkers();
  325. this.#enableDebuggingHelpers();
  326. }
  327.  
  328. static #protectTimers() {
  329. const wrapTimer = original => {
  330. return function(handler, timeout, ...args) {
  331. if (typeof handler !== 'function') {
  332. return original.apply(this, arguments);
  333. }
  334.  
  335. const wrappedHandler = function() {
  336. try {
  337. if (DebuggerDetector.isPresent()) return;
  338. return handler.apply(this, arguments);
  339. } catch (e) {
  340. if (e.message?.includes('debugger')) return;
  341. throw e;
  342. }
  343. };
  344.  
  345. if (config.protection.obfuscateTimers) {
  346. timeout = Math.max(1, timeout + (Math.random() * 20 - 10));
  347. }
  348.  
  349. return original.call(this, wrappedHandler, timeout, ...args);
  350. };
  351. };
  352.  
  353. window.setTimeout = wrapTimer(OriginalFunctions.setTimeout);
  354. window.setInterval = wrapTimer(OriginalFunctions.setInterval);
  355. }
  356.  
  357. static #protectTiming() {
  358. const timeOffset = Math.random() * 25;
  359. const safeNow = () => OriginalFunctions.now.call(Date) + timeOffset;
  360.  
  361. Object.defineProperty(Date, 'now', {
  362. value: safeNow,
  363. configurable: false,
  364. writable: false
  365. });
  366.  
  367. if (window.performance?.now) {
  368. Object.defineProperty(window.performance, 'now', {
  369. value: safeNow,
  370. configurable: false,
  371. writable: false
  372. });
  373. }
  374. }
  375.  
  376. static #protectFunction() {
  377. const handler = {
  378. apply(target, thisArg, args) {
  379. if (typeof args[0] === 'string') {
  380. args[0] = Protection.#cleanCode(args[0]);
  381. }
  382. return Reflect.apply(target, thisArg, args);
  383. },
  384. construct(target, args) {
  385. if (typeof args[0] === 'string') {
  386. args[0] = Protection.#cleanCode(args[0]);
  387. }
  388. return Reflect.construct(target, args);
  389. }
  390. };
  391.  
  392. window.Function = new Proxy(OriginalFunctions.Function, handler);
  393. if (typeof unsafeWindow !== 'undefined') {
  394. unsafeWindow.Function = window.Function;
  395. }
  396. }
  397.  
  398. static #protectStack() {
  399. if (!config.protection.hideStackTraces) return;
  400.  
  401. const errorHandler = {
  402. get(target, prop) {
  403. if (prop === 'stack') {
  404. return Protection.#cleanCode(target.stack);
  405. }
  406. return target[prop];
  407. }
  408. };
  409.  
  410. const originalErrorPrototype = Error.prototype;
  411. const proxyErrorPrototype = Object.create(originalErrorPrototype);
  412.  
  413. Object.defineProperty(proxyErrorPrototype, 'stack', {
  414. get() {
  415. return Protection.#cleanCode(new Error().stack);
  416. },
  417. configurable: true
  418. });
  419.  
  420. try {
  421. Error.prototype = proxyErrorPrototype;
  422. } catch (e) {
  423. logger.error('Failed to protect stack traces:', e);
  424. }
  425. }
  426.  
  427. static #protectEval() {
  428. const safeEval = function(code) {
  429. if (typeof code === 'string') {
  430. if (DebuggerDetector.isPresent()) return;
  431. return OriginalFunctions.eval.call(this, Protection.#cleanCode(code));
  432. }
  433. return OriginalFunctions.eval.apply(this, arguments);
  434. };
  435.  
  436. Object.defineProperty(window, 'eval', {
  437. value: safeEval,
  438. configurable: false,
  439. writable: false
  440. });
  441.  
  442. if (typeof unsafeWindow !== 'undefined') {
  443. unsafeWindow.eval = safeEval;
  444. }
  445. }
  446.  
  447. static #protectConsole() {
  448. const consoleHandler = {
  449. get(target, prop) {
  450. if (!config.consoleProps.includes(prop)) return target[prop];
  451.  
  452. return function(...args) {
  453. if (DebuggerDetector.isPresent()) return;
  454. return OriginalFunctions.console[prop]?.apply(console, args);
  455. };
  456. },
  457. set(target, prop, value) {
  458. if (config.consoleProps.includes(prop)) return true;
  459. target[prop] = value;
  460. return true;
  461. }
  462. };
  463.  
  464. window.console = new Proxy(console, consoleHandler);
  465. }
  466.  
  467. static #setupMutationObserver() {
  468. new MutationObserver(mutations => {
  469. mutations.forEach(mutation => {
  470. if (mutation.type === 'childList') {
  471. mutation.addedNodes.forEach(node => {
  472. if (node.tagName === 'SCRIPT') {
  473. const originalContent = node.textContent;
  474. const cleanedContent = Protection.#cleanCode(originalContent);
  475. if (originalContent !== cleanedContent) {
  476. node.textContent = cleanedContent;
  477. }
  478. }
  479. });
  480. }
  481. });
  482. }).observe(document, {
  483. childList: true,
  484. subtree: true
  485. });
  486. }
  487.  
  488. static #protectDevToolsKeys() {
  489. if (!config.protection.preventDevToolsKeys) return;
  490.  
  491. const handler = e => {
  492. const { keyCode, ctrlKey, shiftKey, altKey } = e;
  493. if (
  494. keyCode === 123 || // F12
  495. (ctrlKey && shiftKey && keyCode === 73) || // Ctrl+Shift+I
  496. (ctrlKey && shiftKey && keyCode === 74) || // Ctrl+Shift+J
  497. (ctrlKey && keyCode === 85) || // Ctrl+U
  498. (altKey && keyCode === 68) // Alt+D
  499. ) {
  500. e.preventDefault();
  501. e.stopPropagation();
  502. return false;
  503. }
  504. };
  505.  
  506. window.addEventListener('keydown', handler, true);
  507. window.addEventListener('keyup', handler, true);
  508. window.addEventListener('keypress', handler, true);
  509. }
  510.  
  511. static #protectRightClick() {
  512. if (!config.protection.preventRightClick) return;
  513.  
  514. window.addEventListener('contextmenu', e => {
  515. e.preventDefault();
  516. e.stopPropagation();
  517. return false;
  518. }, true);
  519. }
  520.  
  521. static #protectViewSource() {
  522. if (!config.protection.preventViewSource) return;
  523.  
  524. const handler = e => {
  525. if (
  526. (e.ctrlKey && (e.key === 'u' || e.key === 's')) || // Ctrl+U, Ctrl+S
  527. (e.ctrlKey && e.shiftKey && e.key === 'i') || // Ctrl+Shift+I
  528. (e.ctrlKey && e.shiftKey && e.key === 'j') || // Ctrl+Shift+J
  529. (e.ctrlKey && e.shiftKey && e.key === 'c') || // Ctrl+Shift+C
  530. e.key === 'F12'
  531. ) {
  532. e.preventDefault();
  533. e.stopPropagation();
  534. return false;
  535. }
  536. };
  537.  
  538. window.addEventListener('keydown', handler, true);
  539. document.addEventListener('keydown', handler, true);
  540.  
  541. window.addEventListener('beforeunload', e => {
  542. if (window.location.protocol === 'view-source:') {
  543. e.preventDefault();
  544. return false;
  545. }
  546. });
  547. }
  548.  
  549. static #protectNetwork() {
  550. window.fetch = async function(...args) {
  551. if (DebuggerDetector.isPresent()) {
  552. throw new Error('Network request blocked');
  553. }
  554. return OriginalFunctions.fetch.apply(this, args);
  555. };
  556.  
  557. window.XMLHttpRequest = function() {
  558. const xhr = new OriginalFunctions.XMLHttpRequest();
  559. const originalOpen = xhr.open;
  560. xhr.open = function(...args) {
  561. if (DebuggerDetector.isPresent()) {
  562. throw new Error('Network request blocked');
  563. }
  564. return originalOpen.apply(xhr, args);
  565. };
  566. return xhr;
  567. };
  568. }
  569.  
  570. static #protectStorage() {
  571. const storageHandler = {
  572. get(target, prop) {
  573. if (DebuggerDetector.isPresent()) return null;
  574. return target[prop];
  575. },
  576. set(target, prop, value) {
  577. if (DebuggerDetector.isPresent()) return true;
  578. target[prop] = value;
  579. return true;
  580. }
  581. };
  582.  
  583. window.localStorage = new Proxy(window.localStorage, storageHandler);
  584. window.sessionStorage = new Proxy(window.sessionStorage, storageHandler);
  585. }
  586.  
  587. static #protectClipboard() {
  588. if (!config.protection.preventCopy) return;
  589.  
  590. document.addEventListener('copy', e => {
  591. e.preventDefault();
  592. }, true);
  593.  
  594. document.addEventListener('cut', e => {
  595. e.preventDefault();
  596. }, true);
  597.  
  598. if (config.protection.preventPaste) {
  599. document.addEventListener('paste', e => {
  600. e.preventDefault();
  601. }, true);
  602. }
  603. }
  604.  
  605. static #protectPrinting() {
  606. if (!config.protection.preventPrint) return;
  607.  
  608. window.addEventListener('beforeprint', e => {
  609. e.preventDefault();
  610. }, true);
  611.  
  612. window.addEventListener('afterprint', e => {
  613. e.preventDefault();
  614. }, true);
  615. }
  616.  
  617. static #protectWebWorkers() {
  618. window.Worker = function(scriptURL, options) {
  619. console.log('[Worker Created]', scriptURL);
  620. return new OriginalFunctions.Worker(scriptURL, options);
  621. };
  622. }
  623.  
  624. static #enableDebuggingHelpers() {
  625. BypassHelpers.disableAntiDebugging.patchTimingChecks();
  626. BypassHelpers.disableAntiDebugging.patchStackTraces();
  627. BypassHelpers.debugTools.monitorAPICalls();
  628. BypassHelpers.debugTools.monitorDOMEvents();
  629. }
  630.  
  631. static #cleanCode(code) {
  632. if (typeof code !== 'string') return code;
  633.  
  634. let cleanCode = code
  635. .replace(/\/\/[#@]\s*source(?:Mapping)?URL\s*=.*$/gm, '')
  636. .replace(/(['"`])(?:(?!\1).)*?(?:debug|debugger|devtools?)(?:(?!\1).)*?\1/gi, match => `'${btoa(match)}'`)
  637. .replace(/\/\*[\s\S]*?\*\/|\/\/.*$/gm, '')
  638. .replace(/debugger|debug\s*\(|console\.[a-z]+/gi, '');
  639.  
  640. Object.values(config.debugPatterns).forEach(pattern => {
  641. cleanCode = cleanCode.replace(pattern, '');
  642. });
  643.  
  644. return cleanCode
  645. .replace(/function\s*\(/g, 'function /*debug*/(')
  646. .replace(/return\s+/g, 'return /*debug*/ ');
  647. }
  648. }
  649.  
  650. // Main class
  651. class DevToolsBypass {
  652. static init() {
  653. try {
  654. Protection.applyAll();
  655. logger.info('DevTools Bypass initialized successfully');
  656. } catch (e) {
  657. logger.error('Failed to initialize DevTools Bypass:', e);
  658. }
  659. }
  660. }
  661.  
  662. // Initialize
  663. DevToolsBypass.init();
  664. })();

QingJ © 2025

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