反反调试

阻止大多数 JavaScript 混淆器实现的反调试,并阻止控制台日志被自动清除。修复了控制台标签丢失的问题。

目前为 2024-10-07 提交的版本。查看 最新版本

  1. // ==UserScript==
  2. // @name Anti Anti-debugger
  3. // @name:vi Chống Anti-debugger
  4. // @name:zh-CN 反反调试
  5. // @namespace https://greasyfork.org/vi/users/1195312-renji-yuusei
  6. // @version 1.1
  7. // @description Stops most anti-debugging implementations by JavaScript obfuscators and stops the console logs from being automatically cleared. Fixed issue with missing console tab.
  8. // @description:vi Ngăn chặn hầu hết các triển khai anti-debugging bằng JavaScript obfuscators và ngăn chặn việc xóa nhật ký console tự động. Đã sửa lỗi mất tab console.
  9. // @description:zh-CN 阻止大多数 JavaScript 混淆器实现的反调试,并阻止控制台日志被自动清除。修复了控制台标签丢失的问题。
  10. // @author Yuusei
  11. // @match *://*/*
  12. // @grant unsafeWindow
  13. // @grant GM_setValue
  14. // @grant GM_getValue
  15. // @run-at document-start
  16. // @license GPL-3.0-only
  17. // ==/UserScript==
  18.  
  19. (function() {
  20. 'use strict';
  21.  
  22. const config = {
  23. excludedDomains: ['vidstream.pro', 'mcloud.to'],
  24. debugKeywords: ['debugger', 'debug', 'debugging', 'breakpoint'],
  25. consoleProps: ['log', 'warn', 'error', 'info', 'debug', 'assert', 'dir', 'dirxml', 'trace', 'group', 'groupCollapsed', 'groupEnd', 'time', 'timeEnd', 'profile', 'profileEnd', 'count'],
  26. enabled: true, // Can be toggled at runtime
  27. };
  28.  
  29. // Load user settings
  30. const loadSettings = () => {
  31. config.enabled = GM_getValue('antiAntiDebuggerEnabled', true);
  32. config.excludedDomains = GM_getValue('excludedDomains', config.excludedDomains);
  33. };
  34.  
  35. loadSettings();
  36.  
  37. const isExcludedDomain = () => config.excludedDomains.some(domain =>
  38. new RegExp(`(^|\.)${domain.replace(/\./g, '\\.')}$`, 'i').test(location.hostname)
  39. );
  40.  
  41. if (isExcludedDomain()) return;
  42.  
  43. const safeEval = (code, context = {}) => {
  44. const safeContext = { ...context, console: { log: () => {} } };
  45. const safeCode = `
  46. 'use strict';
  47. const alert = () => {};
  48. const confirm = () => {};
  49. const prompt = () => {};
  50. ${Object.keys(safeContext).map(key => `const ${key} = this.${key};`).join('\n')}
  51. return (${code});
  52. `;
  53. try {
  54. return new Function(safeCode).call(safeContext);
  55. } catch (error) {
  56. console.warn('Failed to evaluate code:', error);
  57. return null;
  58. }
  59. };
  60.  
  61. const modifyFunction = (func) => {
  62. if (typeof func !== 'function') return func;
  63.  
  64. let funcStr = func.toString();
  65. if (config.debugKeywords.some(keyword => funcStr.includes(keyword))) {
  66. funcStr = funcStr.replace(new RegExp(`\\b(${config.debugKeywords.join('|')})\\b`, 'g'), '/* removed */');
  67. return safeEval(funcStr) || func;
  68. }
  69. return func;
  70. };
  71.  
  72. const wrapConsole = () => {
  73. const originalConsole = { ...console };
  74. const consoleProxy = new Proxy(originalConsole, {
  75. get: (target, prop) => {
  76. if (config.consoleProps.includes(prop) && typeof target[prop] === 'function') {
  77. return new Proxy(target[prop], {
  78. apply: (targetFunc, thisArg, args) => {
  79. if (!config.enabled) return Reflect.apply(targetFunc, thisArg, args);
  80. args = args.map(modifyFunction);
  81. return Reflect.apply(targetFunc, thisArg, args);
  82. }
  83. });
  84. }
  85. return Reflect.get(target, prop);
  86. }
  87. });
  88.  
  89. Object.defineProperty(unsafeWindow, 'console', {
  90. value: consoleProxy,
  91. writable: false,
  92. configurable: false
  93. });
  94. };
  95.  
  96. const antiAntiDebugger = () => {
  97. const proxyHandler = {
  98. apply: (target, thisArg, args) => {
  99. if (!config.enabled) return Reflect.apply(target, thisArg, args);
  100. args = args.map(modifyFunction);
  101. return Reflect.apply(target, thisArg, args);
  102. },
  103. construct: (target, args) => {
  104. if (!config.enabled) return Reflect.construct(target, args);
  105. args = args.map(modifyFunction);
  106. return Reflect.construct(target, args);
  107. }
  108. };
  109.  
  110. Function.prototype.constructor = new Proxy(Function.prototype.constructor, proxyHandler);
  111. // Protect eval and Function constructor
  112. unsafeWindow.eval = new Proxy(unsafeWindow.eval, proxyHandler);
  113. unsafeWindow.Function = new Proxy(unsafeWindow.Function, proxyHandler);
  114. };
  115.  
  116. const preventDebugging = () => {
  117. const noop = () => {};
  118. const protectedProps = [...config.debugKeywords, 'pause', 'alert', 'confirm', 'prompt'];
  119. protectedProps.forEach(prop => {
  120. if (prop !== 'debugger') { // Exclude 'debugger' to prevent issues
  121. Object.defineProperty(unsafeWindow, prop, {
  122. get: () => config.enabled ? noop : unsafeWindow[prop],
  123. set: () => {},
  124. configurable: false
  125. });
  126. }
  127. });
  128.  
  129. // Override common debugging-related Date methods
  130. const originalDate = unsafeWindow.Date;
  131. unsafeWindow.Date = new Proxy(originalDate, {
  132. construct: (target, args) => {
  133. const date = new target(...args);
  134. date.getTime = new Proxy(date.getTime, {
  135. apply: (target, thisArg, args) => {
  136. if (config.enabled && new Error().stack.includes('debugger')) {
  137. return 0; // Return a fake timestamp
  138. }
  139. return Reflect.apply(target, thisArg, args);
  140. }
  141. });
  142. return date;
  143. }
  144. });
  145. };
  146.  
  147. const setupToggleShortcut = () => {
  148. document.addEventListener('keydown', (e) => {
  149. if (e.ctrlKey && e.shiftKey && e.key === 'D') {
  150. config.enabled = !config.enabled;
  151. GM_setValue('antiAntiDebuggerEnabled', config.enabled);
  152. console.log(`Anti Anti-debugger ${config.enabled ? 'enabled' : 'disabled'}`);
  153. }
  154. });
  155. };
  156.  
  157. wrapConsole();
  158. antiAntiDebugger();
  159. preventDebugging();
  160. setupToggleShortcut();
  161.  
  162. console.log('Anti Anti-debugger is active');
  163. })();