LemmeDebug

Disable anti-devtools techniques, block unwanted scripts, and bypass debugger spammers.

  1. // ==UserScript==
  2. // @name LemmeDebug
  3. // @namespace http://github.com/deeeeone/userscripts
  4. // @version 1.2
  5. // @description Disable anti-devtools techniques, block unwanted scripts, and bypass debugger spammers.
  6. // @author Custom
  7. // @match *://*/*
  8. // @run-at document-start
  9. // @grant none
  10. // ==/UserScript==
  11.  
  12. (function() {
  13. 'use strict';
  14.  
  15. ///////////////////////////
  16. // 1) BLOCK USUAL ANTI DEBUG SCRIPTS
  17. ///////////////////////////
  18.  
  19. const BLOCKED_DOMAINS = [
  20. 'theajack.github.io',
  21. ];
  22.  
  23. function isBlockedSrc(src) {
  24. try {
  25. const url = new URL(src, location.href);
  26. return BLOCKED_DOMAINS.includes(url.hostname);
  27. } catch (e) {
  28. return false;
  29. }
  30. }
  31.  
  32. const origCreate = Document.prototype.createElement;
  33. Document.prototype.createElement = function(tagName, options) {
  34. const el = origCreate.call(this, tagName, options);
  35. if (tagName.toLowerCase() === 'script') {
  36. Object.defineProperty(el, 'src', {
  37. set(value) {
  38. if (isBlockedSrc(value)) {
  39. console.warn(`[Blocklist] Blocked script: ${value}`);
  40. return;
  41. }
  42. HTMLScriptElement.prototype.__lookupSetter__('src').call(this, value);
  43. },
  44. get() {
  45. return HTMLScriptElement.prototype.__lookupGetter__('src').call(this);
  46. },
  47. configurable: true,
  48. enumerable: true
  49. });
  50. }
  51. return el;
  52. };
  53.  
  54. ['appendChild','insertBefore','replaceChild'].forEach(fnName => {
  55. const orig = Node.prototype[fnName];
  56. Node.prototype[fnName] = function(newNode, refNode) {
  57. if (newNode.tagName && newNode.tagName.toLowerCase() === 'script') {
  58. const src = newNode.src || newNode.getAttribute('src');
  59. if (src && isBlockedSrc(src)) {
  60. console.warn(`[Blocklist] Prevented ${fnName} of blocked: ${src}`);
  61. return newNode;
  62. }
  63. }
  64. return orig.call(this, newNode, refNode);
  65. };
  66. });
  67.  
  68. const origFetch = window.fetch;
  69. window.fetch = function(input, init) {
  70. let url = typeof input === 'string' ? input : input.url;
  71. if (isBlockedSrc(url)) {
  72. console.warn(`[Blocklist] fetch blocked: ${url}`);
  73. return new Promise(() => {});
  74. }
  75. return origFetch.call(this, input, init);
  76. };
  77.  
  78. const OrigOpen = XMLHttpRequest.prototype.open;
  79. XMLHttpRequest.prototype.open = function(method, url, async, user, pass) {
  80. if (isBlockedSrc(url)) {
  81. console.warn(`[Blocklist] XHR blocked: ${url}`);
  82. return;
  83. }
  84. return OrigOpen.call(this, method, url, async, user, pass);
  85. };
  86.  
  87. ///////////////////////////
  88. // 2) ANTI-ANTI-DEVTOOLS
  89. ///////////////////////////
  90.  
  91. window.Function = new Proxy(Function, {
  92. apply(target, thisArg, args) {
  93. if (typeof args[0] === 'string') args[0] = args[0].replace(/debugger\s*;?/g, '');
  94. return Reflect.apply(target, thisArg, args);
  95. },
  96. construct(target, args) {
  97. if (typeof args[0] === 'string') args[0] = args[0].replace(/debugger\s*;?/g, '');
  98. return Reflect.construct(target, args);
  99. }
  100. });
  101.  
  102. if (console && typeof console.clear === 'function') {
  103. console.clear = () => console.log('[Anti-Anti] console.clear() blocked');
  104. }
  105.  
  106. window.addEventListener('keydown', e => {
  107. if ((e.ctrlKey && e.shiftKey && ['I','J','C'].includes(e.key.toUpperCase())) || e.key === 'F12') {
  108. e.stopImmediatePropagation(); e.preventDefault();
  109. }
  110. }, true);
  111. window.addEventListener('contextmenu', e => {
  112. e.stopImmediatePropagation();
  113. }, true);
  114.  
  115. ['outerWidth','outerHeight'].forEach(prop => {
  116. Object.defineProperty(window, prop, { get: () => 1000, configurable: true });
  117. });
  118.  
  119. const origAdd = EventTarget.prototype.addEventListener;
  120. EventTarget.prototype.addEventListener = function(type, fn, opts) {
  121. if (type === 'keydown' || type === 'contextmenu') {
  122. return origAdd.call(this, type, e => e.stopImmediatePropagation(), opts);
  123. }
  124. return origAdd.call(this, type, fn, opts);
  125. };
  126.  
  127. ///////////////////////////
  128. // 3) DEBUGGER BYPASS
  129. ///////////////////////////
  130.  
  131. const Originals = {
  132. createElement: document.createElement,
  133. log: console.log,
  134. warn: console.warn,
  135. table: console.table,
  136. clear: console.clear,
  137. functionConstructor: window.Function.prototype.constructor,
  138. setInterval: window.setInterval,
  139. toString: Function.prototype.toString,
  140. addEventListener: window.addEventListener
  141. };
  142.  
  143. const cutoffs = {
  144. table: {amount:5, within:5000},
  145. clear: {amount:5, within:5000},
  146. redactedLog: {amount:5, within:5000},
  147. debugger: {amount:10, within:10000},
  148. debuggerThrow: {amount:10, within:10000}
  149. };
  150.  
  151. function shouldLog(type) {
  152. const cutoff = cutoffs[type]; if (cutoff.tripped) return false;
  153. cutoff.current = cutoff.current||0;
  154. const now = Date.now(); cutoff.last = cutoff.last||now;
  155. if (now - cutoff.last > cutoff.within) cutoff.current=0;
  156. cutoff.last = now; cutoff.current++;
  157. if (cutoff.current > cutoff.amount) {
  158. Originals.warn(`Limit reached! Ignoring ${type}`);
  159. cutoff.tripped = true; return false;
  160. }
  161. return true;
  162. }
  163.  
  164. function wrapFn(newFn, old) {
  165. return new Proxy(newFn, { get(target, prop) {
  166. return ['apply','bind','call'].includes(prop) ? target[prop] : old[prop];
  167. }});
  168. }
  169.  
  170. window.console.log = wrapFn((...args) => {
  171. let redactedCount=0;
  172. const newArgs = args.map(a => {
  173. if (typeof a==='function'){redactedCount++;return 'Redacted Function';}
  174. if (typeof a!=='object'||a===null) return a;
  175. const props = Object.getOwnPropertyDescriptors(a);
  176. for(const name in props){
  177. if(props[name].get){redactedCount++;return 'Redacted Getter';}
  178. if(name==='toString'){redactedCount++;return 'Redacted Str';}
  179. }
  180. if (Array.isArray(a)&&a.length===50&&typeof a[0]==='object'){redactedCount++;return 'Redacted LargeObjArray';}
  181. return a;
  182. });
  183. if (redactedCount>=Math.max(args.length-1,1)&&!shouldLog('redactedLog')) return;
  184. return Originals.log.apply(console,newArgs);
  185. }, Originals.log);
  186.  
  187. window.console.table = wrapFn(obj=>{
  188. if(shouldLog('table')) Originals.warn('Redacted table');
  189. }, Originals.table);
  190.  
  191. window.console.clear = wrapFn(()=>{
  192. if(shouldLog('clear')) Originals.warn('Prevented clear');
  193. }, Originals.clear);
  194.  
  195. let debugCount=0;
  196. window.Function.prototype.constructor = wrapFn((...args)=>{
  197. const originalFn = Originals.functionConstructor.apply(this,args);
  198. const content = args[0]||'';
  199. if(content.includes('debugger')){
  200. if(shouldLog('debugger')) Originals.warn('Prevented debugger');
  201. debugCount++;
  202. if(debugCount>100){
  203. if(shouldLog('debuggerThrow')) Originals.warn('Debugger loop! Throwing');
  204. throw new Error('Execution halted');
  205. } else {
  206. setTimeout(()=>debugCount--,1);
  207. }
  208. const newArgs=[content.replaceAll('debugger',''), ...args.slice(1)];
  209. return new Proxy(Originals.functionConstructor.apply(this,newArgs),{
  210. get(target,prop){ return prop==='toString'?originalFn.toString:target[prop]; }
  211. });
  212. }
  213. return originalFn;
  214. }, Originals.functionConstructor);
  215.  
  216. // keep console preserved inside iframes
  217. document.createElement = wrapFn((el,o)=>{
  218. const element = Originals.createElement.call(document,el,o);
  219. if(el.toLowerCase()==='iframe'){
  220. element.addEventListener('load',()=>{
  221. try{ element.contentWindow.console = window.console; }catch{};
  222. });
  223. }
  224. return element;
  225. }, Originals.createElement);
  226.  
  227. })();

QingJ © 2025

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