DevTools Bypass

Bypass for website restrictions on DevTools with improved protection

目前為 2024-11-10 提交的版本,檢視 最新版本

  1. // ==UserScript==
  2. // @name DevTools Bypass
  3. // @name:vi Bỏ Qua Chặn DevTools
  4. // @name:zh-CN 开发工具限制绕过
  5. // @namespace https://greasyfork.org/vi/users/1195312-renji-yuusei
  6. // @version 3.0
  7. // @description Bypass for website restrictions on DevTools with improved protection
  8. // @description:vi Bỏ qua các hạn chế của trang web về DevTools với bảo vệ được cải tiến
  9. // @description:zh-CN 绕过网站对开发工具的限制,具有增强的保护功能
  10. // @author Yuusei
  11. // @match *://*/*
  12. // @grant unsafeWindow
  13. // @run-at document-start
  14. // @license GPL-3.0-only
  15. // ==/UserScript==
  16.  
  17. (function() {
  18. 'use strict';
  19.  
  20. // Add initialization logging
  21. console.log('[DevTools Bypass] Script initialized at:', new Date().toISOString());
  22.  
  23. const config = {
  24. debugPatterns: {
  25. basic: /;\s*(?:debugger|debug(?:ger)?|breakpoint)\s*;?/g,
  26. advanced: /(?:debugger|debug(?:ger)?|breakpoint)[\s;]*(?:\{[\s\S]*?\})?/g,
  27. timing: /performance\.now\(\)|Date\.now\(\)/g,
  28. eval: /eval\(.*?debugger.*?\)/g
  29. },
  30. consoleProps: ['log', 'warn', 'error', 'info', 'debug', 'trace'],
  31. cutoffs: {
  32. debugger: { amount: 50, within: 60000 },
  33. debuggerThrow: { amount: 50, within: 60000 }
  34. },
  35. bypassTriggers: {
  36. timeThreshold: 100,
  37. stackDepth: 50,
  38. recursionLimit: 100
  39. },
  40. logging: {
  41. enabled: false,
  42. prefix: '[DevTools Bypass]',
  43. levels: ['info', 'warn', 'error']
  44. }
  45. };
  46.  
  47. // Enhanced logging utility
  48. const logger = {
  49. info: (...args) => {
  50. if (config.logging.enabled) {
  51. console.log(config.logging.prefix, '(INFO)', ...args);
  52. }
  53. },
  54. warn: (...args) => {
  55. if (config.logging.enabled) {
  56. console.warn(config.logging.prefix, '(WARN)', ...args);
  57. }
  58. },
  59. error: (...args) => {
  60. if (config.logging.enabled) {
  61. console.error(config.logging.prefix, '(ERROR)', ...args);
  62. }
  63. }
  64. };
  65.  
  66. const originals = {
  67. defineProperty: Object.defineProperty,
  68. getOwnPropertyDescriptor: Object.getOwnPropertyDescriptor,
  69. setTimeout: window.setTimeout,
  70. setInterval: window.setInterval,
  71. Date: window.Date,
  72. now: Date.now,
  73. performance: window.performance,
  74. Function: window.Function,
  75. eval: window.eval,
  76. console: {},
  77. toString: Function.prototype.toString,
  78. preventDefault: Event.prototype.preventDefault,
  79. getComputedStyle: window.getComputedStyle
  80. };
  81.  
  82. config.consoleProps.forEach(prop => {
  83. if (console[prop]) {
  84. originals.console[prop] = console[prop].bind(console);
  85. }
  86. });
  87.  
  88. const isDebuggerPresent = () => {
  89. try {
  90. const startTime = originals.now.call(Date);
  91. const testFunc = new Function('debugger;')();
  92. const timeDiff = originals.now.call(Date) - startTime;
  93. if (timeDiff > config.bypassTriggers.timeThreshold) {
  94. logger.warn('Debugger detected! Time difference:', timeDiff, 'ms');
  95. return true;
  96. }
  97. return false;
  98. } catch (e) {
  99. logger.error('Error in debugger detection:', e);
  100. return false;
  101. }
  102. };
  103.  
  104. const analyzeStack = () => {
  105. try {
  106. const stack = new Error().stack;
  107. const frames = stack.split('\n');
  108. const analysis = {
  109. depth: frames.length,
  110. hasDebugKeywords: frames.some(frame =>
  111. Object.values(config.debugPatterns).some(pattern =>
  112. pattern.test(frame)
  113. )
  114. ),
  115. isRecursive: new Set(frames).size < frames.length
  116. };
  117.  
  118. if (analysis.hasDebugKeywords || analysis.isRecursive) {
  119. logger.warn('Suspicious stack detected:', analysis);
  120. }
  121.  
  122. return analysis;
  123. } catch (e) {
  124. logger.error('Error analyzing stack:', e);
  125. return { depth: 0, hasDebugKeywords: false, isRecursive: false };
  126. }
  127. };
  128.  
  129. const enhancedAntiDebugger = () => {
  130. try {
  131. let protectionCount = 0;
  132.  
  133. const createSafeTimer = (original) => {
  134. return function(handler, timeout, ...args) {
  135. if (typeof handler === 'function') {
  136. const wrappedHandler = function() {
  137. try {
  138. return handler.apply(this, arguments);
  139. } catch (e) {
  140. if (e.message?.includes('debugger')) {
  141. logger.info('Caught and bypassed debugger in timer');
  142. return undefined;
  143. }
  144. throw e;
  145. }
  146. };
  147. return original.call(this, wrappedHandler, timeout, ...args);
  148. }
  149. return original.apply(this, arguments);
  150. };
  151. };
  152.  
  153. const protectTiming = () => {
  154. const timeOffset = Math.random() * 10;
  155. const safeNow = function() {
  156. return originals.now.call(Date) + timeOffset;
  157. };
  158.  
  159. try {
  160. Object.defineProperty(Date, 'now', {
  161. value: safeNow,
  162. configurable: true,
  163. writable: true
  164. });
  165.  
  166. if (window.performance && window.performance.now) {
  167. Object.defineProperty(window.performance, 'now', {
  168. value: safeNow,
  169. configurable: true,
  170. writable: true
  171. });
  172. }
  173. protectionCount++;
  174. logger.info('Timing protection applied with offset:', timeOffset);
  175. } catch (e) {
  176. logger.error('Failed to protect timing:', e);
  177. }
  178. };
  179.  
  180. const protectFunction = () => {
  181. const handler = {
  182. apply(target, thisArg, args) {
  183. const code = args[0];
  184. if (typeof code === 'string') {
  185. let cleanCode = code;
  186. let detectedPatterns = [];
  187. Object.entries(config.debugPatterns).forEach(([key, pattern]) => {
  188. if (pattern.test(code)) {
  189. detectedPatterns.push(key);
  190. }
  191. cleanCode = cleanCode.replace(pattern, '');
  192. });
  193. if (detectedPatterns.length > 0) {
  194. logger.warn('Cleaned debug patterns from Function:', detectedPatterns);
  195. }
  196. args[0] = cleanCode;
  197. }
  198. return Reflect.apply(target, thisArg, args);
  199. },
  200. construct(target, args) {
  201. const code = args[0];
  202. if (typeof code === 'string') {
  203. let cleanCode = code;
  204. Object.values(config.debugPatterns).forEach(pattern => {
  205. cleanCode = cleanCode.replace(pattern, '');
  206. });
  207. args[0] = cleanCode;
  208. }
  209. return Reflect.construct(target, args);
  210. }
  211. };
  212.  
  213. window.Function = new Proxy(originals.Function, handler);
  214. if (typeof unsafeWindow !== 'undefined') {
  215. unsafeWindow.Function = window.Function;
  216. }
  217. protectionCount++;
  218. logger.info('Function protection applied');
  219. };
  220.  
  221. const protectStack = () => {
  222. try {
  223. const errorHandler = {
  224. get(target, prop) {
  225. if (prop === 'stack') {
  226. const stack = target.stack;
  227. const cleanedStack = stack.split('\n')
  228. .filter(line => !Object.values(config.debugPatterns)
  229. .some(pattern => pattern.test(line)))
  230. .join('\n');
  231. if (cleanedStack.length !== stack.length) {
  232. logger.info('Cleaned suspicious stack trace');
  233. }
  234. return cleanedStack;
  235. }
  236. return target[prop];
  237. }
  238. };
  239.  
  240. const errorProtoHandler = {
  241. get(target, prop) {
  242. if (prop === 'stack') {
  243. const error = new Error();
  244. return new Proxy(error, errorHandler).stack;
  245. }
  246. return Reflect.get(target, prop);
  247. }
  248. };
  249.  
  250. Error.prototype = new Proxy(Error.prototype, errorProtoHandler);
  251. protectionCount++;
  252. logger.info('Stack protection applied');
  253. } catch (e) {
  254. logger.error('Failed to protect stack:', e);
  255. }
  256. };
  257.  
  258. const protectEval = () => {
  259. const safeEval = function(code) {
  260. if (typeof code === 'string') {
  261. let cleanCode = code;
  262. let detectedPatterns = [];
  263. Object.entries(config.debugPatterns).forEach(([key, pattern]) => {
  264. if (pattern.test(code)) {
  265. detectedPatterns.push(key);
  266. }
  267. cleanCode = cleanCode.replace(pattern, '');
  268. });
  269. if (detectedPatterns.length > 0) {
  270. logger.warn('Cleaned debug patterns from eval:', detectedPatterns);
  271. }
  272. return originals.eval.call(this, cleanCode);
  273. }
  274. return originals.eval.apply(this, arguments);
  275. };
  276.  
  277. try {
  278. Object.defineProperty(window, 'eval', {
  279. value: safeEval,
  280. configurable: true,
  281. writable: true
  282. });
  283. if (typeof unsafeWindow !== 'undefined') {
  284. unsafeWindow.eval = safeEval;
  285. }
  286. protectionCount++;
  287. logger.info('Eval protection applied');
  288. } catch (e) {
  289. logger.error('Failed to protect eval:', e);
  290. }
  291. };
  292.  
  293. const protectConsole = () => {
  294. const handler = {
  295. get(target, prop) {
  296. if (config.consoleProps.includes(prop)) {
  297. return function(...args) {
  298. if (!isDebuggerPresent()) {
  299. return originals.console[prop]?.apply(console, args);
  300. }
  301. logger.warn('Console method blocked due to debugger presence:', prop);
  302. return undefined;
  303. };
  304. }
  305. return target[prop];
  306. },
  307. set(target, prop, value) {
  308. if (config.consoleProps.includes(prop)) {
  309. logger.warn('Attempted to modify console method:', prop);
  310. return true;
  311. }
  312. target[prop] = value;
  313. return true;
  314. }
  315. };
  316.  
  317. window.console = new Proxy(console, handler);
  318. protectionCount++;
  319. logger.info('Console protection applied');
  320. };
  321.  
  322. // Apply all protections
  323. window.setTimeout = createSafeTimer(originals.setTimeout);
  324. window.setInterval = createSafeTimer(originals.setInterval);
  325. protectTiming();
  326. protectFunction();
  327. protectStack();
  328. protectEval();
  329. protectConsole();
  330.  
  331. // Enhanced MutationObserver with logging
  332. const observer = new MutationObserver((mutations) => {
  333. for (const mutation of mutations) {
  334. if (mutation.type === 'childList') {
  335. mutation.addedNodes.forEach((node) => {
  336. if (node.tagName === 'SCRIPT') {
  337. const content = node.textContent;
  338. let detectedPatterns = [];
  339. Object.entries(config.debugPatterns).forEach(([key, pattern]) => {
  340. if (pattern.test(content)) {
  341. detectedPatterns.push(key);
  342. }
  343. });
  344.  
  345. if (detectedPatterns.length > 0) {
  346. logger.warn('Cleaned debug patterns from dynamic script:', detectedPatterns);
  347. node.textContent = content.replace(
  348. new RegExp(Object.values(config.debugPatterns)
  349. .map(p => p.source).join('|'), 'g'),
  350. ''
  351. );
  352. }
  353. }
  354. });
  355. }
  356. }
  357. });
  358.  
  359. observer.observe(document, {
  360. childList: true,
  361. subtree: true
  362. });
  363.  
  364. logger.info('All protections applied successfully. Total protections:', protectionCount);
  365.  
  366. } catch (e) {
  367. logger.error('Critical error in enhancedAntiDebugger:', e);
  368. }
  369. };
  370.  
  371. const init = () => {
  372. try {
  373. logger.info('Initializing DevTools bypass...');
  374. enhancedAntiDebugger();
  375. logger.info('DevTools bypass initialized successfully');
  376. } catch (e) {
  377. logger.error('Failed to initialize DevTools bypass:', e);
  378. }
  379. };
  380.  
  381. // Add status check function
  382. window._checkDevToolsBypassStatus = () => {
  383. try {
  384. const status = {
  385. initialized: true,
  386. debuggerPresent: isDebuggerPresent(),
  387. stackAnalysis: analyzeStack(),
  388. timestamp: new Date().toISOString()
  389. };
  390. logger.info('Status check:', status);
  391. return status;
  392. } catch (e) {
  393. logger.error('Error checking status:', e);
  394. return { error: e.message };
  395. }
  396. };
  397.  
  398. init();
  399. })();