// ==UserScript==
// @name 网站限制解除脚本
// @namespace https://web.zyxn.dpdns.org
// @version 4.0
// @description 解锁复制/粘贴/右键,彻底屏蔽 debugger 循环和 eval/Function 注入。
// @author flkGit
// @match *://*/*
// @run-at document-start
// @grant none
// @license MIT
// ==/UserScript==
(function(){
'use strict';
// --- 基础解锁:右键/复制/粘贴 + F12保护 ---
const SENSITIVE_EVENTS = [
'copy', 'paste', 'cut', 'contextmenu', 'selectstart', 'dragstart',
'keydown', 'keyup', 'keypress' // 包含键盘事件保护F12等
];
// 高优先级事件拦截
for (const ev of SENSITIVE_EVENTS) {
window.addEventListener(ev, e => {
// 特殊保护开发者工具快捷键
if (e.type.startsWith('key')) {
const isF12 = e.keyCode === 123;
const isDevTools = e.ctrlKey && e.shiftKey && e.keyCode === 73; // Ctrl+Shift+I
const isConsole = e.ctrlKey && e.shiftKey && e.keyCode === 74; // Ctrl+Shift+J
const isViewSource = e.ctrlKey && e.keyCode === 85; // Ctrl+U
const isInspect = e.ctrlKey && e.shiftKey && e.keyCode === 67; // Ctrl+Shift+C
if (isF12 || isDevTools || isConsole || isViewSource || isInspect) {
e.stopImmediatePropagation();
return; // 让浏览器处理这些快捷键
}
}
// 其他敏感事件全部放行
e.stopImmediatePropagation();
}, true);
}
// 清理内联事件处理器
function cleanInline() {
const inlineEvents = ['oncopy', 'onpaste', 'oncut', 'oncontextmenu', 'onselectstart', 'onkeydown', 'onkeyup'];
const targets = [document, document.documentElement, document.body].filter(Boolean);
for (const target of targets) {
for (const attr of inlineEvents) {
if (target[attr]) target[attr] = null;
}
}
}
// 定期清理 + 页面变化时清理
const cleanTimer = setInterval(cleanInline, 2000);
if (typeof MutationObserver !== 'undefined') {
new MutationObserver(cleanInline).observe(document, {childList: true, subtree: true});
}
// 页面卸载前清理定时器
window.addEventListener('beforeunload', () => clearInterval(cleanTimer));
// 强制CSS样式解锁
function injectUnlockCSS() {
if (document.head) {
const style = document.createElement('style');
style.textContent = `
* {
-webkit-user-select: text !important;
-moz-user-select: text !important;
user-select: text !important;
-webkit-touch-callout: default !important;
-webkit-user-drag: element !important;
pointer-events: auto !important;
}
`;
document.head.appendChild(style);
}
}
// 立即注入CSS,DOM加载后再次注入
injectUnlockCSS();
document.addEventListener('DOMContentLoaded', injectUnlockCSS);
// 强制允许 execCommand
const origExecCommand = document.execCommand;
document.execCommand = function(cmd, showUI, value) {
return origExecCommand.call(this, cmd, showUI, value) || true; // 强制返回true
};
// === 增强版 Debugger 拦截系统 ===
function createDebuggerBlocker() {
const logBlocked = (type, info) => console.warn(`[Debugger Blocked] ${type}:`, info);
// 1. 重写核心函数
const originals = {
eval: window.eval,
Function: window.Function,
setTimeout: window.setTimeout,
setInterval: window.setInterval
};
// 检测debugger的正则(更严格)
const debuggerRegex = /\bdebugger\b/;
// 重写 eval
window.eval = function(code) {
if (typeof code === 'string' && debuggerRegex.test(code)) {
logBlocked('eval', code.slice(0, 100));
return undefined;
}
return originals.eval.call(this, code);
};
// 重写 Function 构造器
window.Function = function(...args) {
const code = args[args.length - 1];
if (typeof code === 'string' && debuggerRegex.test(code)) {
logBlocked('Function', code.slice(0, 100));
return () => {}; // 返回无害的空函数
}
return originals.Function.apply(this, args);
};
// 重写定时器函数
const wrapTimer = (original, name) => function(callback, delay, ...args) {
if (typeof callback === 'string' && debuggerRegex.test(callback)) {
logBlocked(name + ' string', callback.slice(0, 100));
return original.call(this, () => {}, delay, ...args);
}
if (typeof callback === 'function') {
try {
const funcStr = callback.toString();
if (debuggerRegex.test(funcStr)) {
logBlocked(name + ' function', funcStr.slice(0, 100));
return original.call(this, () => {}, delay, ...args);
}
} catch (e) {
// 如果toString()失败,可能是native函数,放行
}
}
return original.call(this, callback, delay, ...args);
};
window.setTimeout = wrapTimer(originals.setTimeout, 'setTimeout');
window.setInterval = wrapTimer(originals.setInterval, 'setInterval');
// 2. 主动清理现有定时器
let cleanupActive = true;
const cleanupDebuggers = () => {
if (!cleanupActive) return;
try {
// 获取当前最高的timer ID
const testId = setTimeout(() => {}, 0);
clearTimeout(testId);
// 清理可疑的定时器(延迟很短的)
for (let i = Math.max(1, testId - 1000); i <= testId; i++) {
try {
clearTimeout(i);
clearInterval(i);
} catch (e) {}
}
} catch (e) {}
};
// 启动清理任务
const cleanupTimer = setInterval(cleanupDebuggers, 3000);
// 15秒后停止清理
setTimeout(() => {
cleanupActive = false;
clearInterval(cleanupTimer);
logBlocked('cleanup', '定时器清理任务已完成');
}, 15000);
// 3. 保护 console 对象
try {
const originalClear = console.clear;
Object.defineProperty(console, 'clear', {
value: function() {
logBlocked('console.clear', '阻止清除控制台');
},
writable: false,
configurable: false
});
} catch (e) {}
}
// 立即启动debugger拦截
createDebuggerBlocker();
// === 页面加载完成后的额外保护 ===
const finalSetup = () => {
cleanInline();
injectUnlockCSS();
// 移除可能的CSS限制
const restrictiveStyles = document.querySelectorAll('style, link[rel="stylesheet"]');
restrictiveStyles.forEach(style => {
try {
if (style.textContent && /user-select\s*:\s*none|pointer-events\s*:\s*none/.test(style.textContent)) {
style.textContent = style.textContent
.replace(/user-select\s*:\s*none/gi, 'user-select: text')
.replace(/pointer-events\s*:\s*none/gi, 'pointer-events: auto');
}
} catch (e) {}
});
};
// 多个时机执行最终设置
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', finalSetup);
} else {
finalSetup();
}
window.addEventListener('load', () => setTimeout(finalSetup, 500));
console.info('[Unlocker v4.0] 已启用:F12保护 + 复制解锁 + Debugger全面拦截');
})();