초기 PM 소스 전체 업로드
This commit is contained in:
821
views/anti_debugging.js
Normal file
821
views/anti_debugging.js
Normal file
@@ -0,0 +1,821 @@
|
||||
export class AntiDebug {
|
||||
constructor() {
|
||||
this.checks = [];
|
||||
this.isDestroyed = false;
|
||||
this.originalScripts = new Map();
|
||||
this.detectionCount = 0;
|
||||
this.monitoringIntervals = [];
|
||||
|
||||
// 감지 시작(개발자 모드에서는 주석처리)
|
||||
// this.emergencyProtection();
|
||||
// this.init();
|
||||
}
|
||||
|
||||
emergencyProtection() {
|
||||
// 페이지 로드 즉시 실행
|
||||
const script = document.createElement('script');
|
||||
script.textContent = `
|
||||
(function() {
|
||||
const start = Date.now();
|
||||
debugger;
|
||||
if (Date.now() - start > 100) {
|
||||
document.documentElement.innerHTML = '<h1 style="color:red;text-align:center;margin-top:50vh;">Access Denied</h1>';
|
||||
while(true) { debugger; }
|
||||
}
|
||||
})();
|
||||
`;
|
||||
if (document.head) {
|
||||
document.head.insertBefore(script, document.head.firstChild);
|
||||
}
|
||||
}
|
||||
|
||||
async init() {
|
||||
// 모든 스크립트의 실제 내용을 메모리에 저장
|
||||
await this.captureAllScriptContents();
|
||||
|
||||
// 체크 메서드 등록
|
||||
this.checks.push(this.checkConsole.bind(this));
|
||||
this.checks.push(this.checkDebugger.bind(this));
|
||||
this.checks.push(this.checkToString.bind(this));
|
||||
// this.checks.push(this.checkDevToolsSize.bind(this)); //사이즈는 사이니지때문에 우선 주석
|
||||
|
||||
// 다층 보호 시작
|
||||
this.protectFunctions();
|
||||
this.blockDevToolsShortcuts();
|
||||
this.overrideNetworkAPIs();
|
||||
this.polluteDOMWithFakes();
|
||||
|
||||
// 체크 시작
|
||||
this.startAggressiveMonitoring();
|
||||
}
|
||||
|
||||
async captureAllScriptContents() {
|
||||
try {
|
||||
const scripts = document.querySelectorAll('script');
|
||||
|
||||
for (const script of scripts) {
|
||||
if (script.src) {
|
||||
try {
|
||||
// 외부 스크립트 fetch
|
||||
const response = await fetch(script.src);
|
||||
const content = await response.text();
|
||||
|
||||
this.originalScripts.set(script.src, {
|
||||
type: 'external',
|
||||
content: content,
|
||||
element: script,
|
||||
url: script.src
|
||||
});
|
||||
} catch(e) {
|
||||
console.error('Failed to capture:', script.src);
|
||||
}
|
||||
} else if (script.textContent) {
|
||||
this.originalScripts.set(`inline_${Date.now()}_${Math.random()}`, {
|
||||
type: 'inline',
|
||||
content: script.textContent,
|
||||
element: script
|
||||
});
|
||||
}
|
||||
}
|
||||
} catch(e) {
|
||||
console.error('Script capture failed:', e);
|
||||
}
|
||||
}
|
||||
|
||||
startAggressiveMonitoring() {
|
||||
// 다양한 간격으로 체크 (회피 어렵게)
|
||||
const intervals = [500, 1000, 1500, 2000, 3000];
|
||||
|
||||
intervals.forEach(interval => {
|
||||
const id = setInterval(() => this.runChecks(), interval);
|
||||
this.monitoringIntervals.push(id);
|
||||
});
|
||||
|
||||
// requestAnimationFrame으로도 체크
|
||||
const rafCheck = () => {
|
||||
if (!this.isDestroyed) {
|
||||
this.runChecks();
|
||||
requestAnimationFrame(rafCheck);
|
||||
}
|
||||
};
|
||||
requestAnimationFrame(rafCheck);
|
||||
}
|
||||
|
||||
checkConsole() {
|
||||
try {
|
||||
const start = performance.now();
|
||||
const devtools = {};
|
||||
Object.defineProperty(devtools, 'toString', {
|
||||
get: function() {
|
||||
return true;
|
||||
}
|
||||
});
|
||||
console.log('%c', devtools);
|
||||
const end = performance.now();
|
||||
return (end - start) > 100;
|
||||
} catch(e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
checkDebugger() {
|
||||
try {
|
||||
const start = performance.now();
|
||||
debugger;
|
||||
const end = performance.now();
|
||||
return (end - start) > 100;
|
||||
} catch(e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
checkToString() {
|
||||
try {
|
||||
let detected = false;
|
||||
const detector = /./;
|
||||
detector.toString = function() {
|
||||
detected = true;
|
||||
};
|
||||
console.log('%c', detector);
|
||||
return detected;
|
||||
} catch(e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
checkDevToolsSize() {
|
||||
const widthThreshold = window.outerWidth - window.innerWidth > 160;
|
||||
const heightThreshold = window.outerHeight - window.innerHeight > 160;
|
||||
return widthThreshold || heightThreshold;
|
||||
}
|
||||
|
||||
protectFunctions() {
|
||||
try {
|
||||
const originalToString = Function.prototype.toString;
|
||||
const self = this;
|
||||
|
||||
Function.prototype.toString = function() {
|
||||
const fnString = originalToString.call(this);
|
||||
const fnName = this.name || '';
|
||||
|
||||
// AntiDebug 관련 함수는 숨김
|
||||
if (fnName.includes('check') ||
|
||||
fnName.includes('Anti') ||
|
||||
fnName.includes('destroy') ||
|
||||
fnName.includes('protect') ||
|
||||
fnString.includes('debugger')) {
|
||||
return `function ${fnName}() { [native code] }`;
|
||||
}
|
||||
|
||||
return fnString;
|
||||
};
|
||||
|
||||
// Object.defineProperty도 보호
|
||||
const originalDefineProperty = Object.defineProperty;
|
||||
Object.defineProperty = function(obj, prop, descriptor) {
|
||||
// console 조작 방지
|
||||
if (obj === console || obj === window.console) {
|
||||
return obj;
|
||||
}
|
||||
return originalDefineProperty(obj, prop, descriptor);
|
||||
};
|
||||
|
||||
} catch(e) {}
|
||||
}
|
||||
|
||||
blockDevToolsShortcuts() {
|
||||
// 모든 개발자 도구 단축키 차단
|
||||
document.addEventListener('keydown', (e) => {
|
||||
const forbidden = [
|
||||
e.keyCode === 123, // F12
|
||||
e.ctrlKey && e.shiftKey && e.keyCode === 73, // Ctrl+Shift+I
|
||||
e.ctrlKey && e.shiftKey && e.keyCode === 74, // Ctrl+Shift+J
|
||||
e.ctrlKey && e.shiftKey && e.keyCode === 67, // Ctrl+Shift+C
|
||||
e.ctrlKey && e.keyCode === 85, // Ctrl+U
|
||||
e.metaKey && e.altKey && e.keyCode === 73, // Cmd+Option+I (Mac)
|
||||
e.metaKey && e.altKey && e.keyCode === 74, // Cmd+Option+J (Mac)
|
||||
e.metaKey && e.altKey && e.keyCode === 67, // Cmd+Option+C (Mac)
|
||||
];
|
||||
|
||||
if (forbidden.some(x => x)) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
e.stopImmediatePropagation();
|
||||
// this.increaseDetectionCount();
|
||||
return false;
|
||||
}
|
||||
}, true);
|
||||
|
||||
// 우클릭 완전 차단
|
||||
// document.addEventListener('contextmenu', (e) => {
|
||||
// e.preventDefault();
|
||||
// e.stopPropagation();
|
||||
// return false;
|
||||
// }, true);
|
||||
|
||||
// 선택 차단
|
||||
// document.addEventListener('selectstart', (e) => {
|
||||
// e.preventDefault();
|
||||
// return false;
|
||||
// });
|
||||
|
||||
// 드래그 차단
|
||||
// document.addEventListener('dragstart', (e) => {
|
||||
// e.preventDefault();
|
||||
// return false;
|
||||
// });
|
||||
}
|
||||
|
||||
overrideNetworkAPIs() {
|
||||
// fetch API 오버라이드
|
||||
const originalFetch = window.fetch;
|
||||
const self = this;
|
||||
|
||||
window.fetch = async function(...args) {
|
||||
const url = args[0];
|
||||
|
||||
// DevTools가 감지된 경우
|
||||
if (self.isDestroyed && typeof url === 'string' && url.endsWith('.js')) {
|
||||
console.log('Blocked fetch request:', url);
|
||||
|
||||
// 가짜 응답 반환
|
||||
return new Response(
|
||||
self.generateMassiveGarbageCode(),
|
||||
{
|
||||
status: 200,
|
||||
headers: { 'Content-Type': 'application/javascript' }
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
return originalFetch.apply(this, args);
|
||||
};
|
||||
|
||||
// XMLHttpRequest 오버라이드
|
||||
const originalXHROpen = XMLHttpRequest.prototype.open;
|
||||
const originalXHRSend = XMLHttpRequest.prototype.send;
|
||||
|
||||
XMLHttpRequest.prototype.open = function(method, url, ...rest) {
|
||||
this._url = url;
|
||||
return originalXHROpen.call(this, method, url, ...rest);
|
||||
};
|
||||
|
||||
XMLHttpRequest.prototype.send = function(...args) {
|
||||
if (self.isDestroyed && this._url && this._url.endsWith('.js')) {
|
||||
console.log('Blocked XHR request:', this._url);
|
||||
|
||||
// 가짜 응답 설정
|
||||
Object.defineProperty(this, 'responseText', {
|
||||
writable: true,
|
||||
value: self.generateMassiveGarbageCode()
|
||||
});
|
||||
Object.defineProperty(this, 'response', {
|
||||
writable: true,
|
||||
value: self.generateMassiveGarbageCode()
|
||||
});
|
||||
|
||||
// 성공 이벤트 발생
|
||||
setTimeout(() => {
|
||||
this.readyState = 4;
|
||||
this.status = 200;
|
||||
if (this.onload) this.onload();
|
||||
if (this.onreadystatechange) this.onreadystatechange();
|
||||
}, 0);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
return originalXHRSend.apply(this, args);
|
||||
};
|
||||
}
|
||||
|
||||
polluteDOMWithFakes() {
|
||||
const fakeCount = 200; // 200개의 가짜 스크립트
|
||||
|
||||
const scriptPaths = [
|
||||
'main/main.js',
|
||||
'main/app.js',
|
||||
'main/utils.js',
|
||||
'main/api.js',
|
||||
'main/config.js',
|
||||
'login/login.js',
|
||||
'login/auth.js',
|
||||
'login/validator.js',
|
||||
'index/index.js',
|
||||
'index/controller.js',
|
||||
'index/router.js'
|
||||
];
|
||||
|
||||
// 각 파일명마다 여러 버전의 가짜 생성
|
||||
scriptPaths.forEach(path => {
|
||||
for (let i = 0; i < 20; i++) {
|
||||
const fakeScript = document.createElement('script');
|
||||
fakeScript.setAttribute('data-fake-source', path);
|
||||
fakeScript.setAttribute('data-version', `v${i}`);
|
||||
fakeScript.type = 'text/javascript';
|
||||
fakeScript.textContent = this.generateRealisticFakeCode(path, i);
|
||||
|
||||
if (document.head) {
|
||||
document.head.appendChild(fakeScript);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
generateRealisticFakeCode(filename, version) {
|
||||
const modules = ['auth', 'api', 'utils', 'config', 'router', 'store'];
|
||||
const functions = ['init', 'setup', 'validate', 'process', 'handle', 'execute'];
|
||||
|
||||
return `
|
||||
// ===================================================================
|
||||
// Module: ${filename} (Protected Version ${version})
|
||||
// Build: ${Math.random().toString(36).substr(2, 10).toUpperCase()}
|
||||
// Status: ENCRYPTED - Original source removed
|
||||
// ===================================================================
|
||||
|
||||
(function(global, factory) {
|
||||
'use strict';
|
||||
|
||||
if (typeof define === 'function' && define.amd) {
|
||||
define([], factory);
|
||||
} else if (typeof module === 'object' && module.exports) {
|
||||
module.exports = factory();
|
||||
} else {
|
||||
global._Module_${Math.random().toString(36).substr(2, 8)} = factory();
|
||||
}
|
||||
|
||||
}(typeof window !== 'undefined' ? window : this, function() {
|
||||
'use strict';
|
||||
|
||||
// ============ Obfuscated Configuration ============
|
||||
const _config_${Math.random().toString(36).substr(2, 6)} = {
|
||||
${this.generateFakeConfig()}
|
||||
};
|
||||
|
||||
// ============ Protected Functions ============
|
||||
${functions.map(fn => this.generateFakeFunction(fn)).join('\n\n')}
|
||||
|
||||
// ============ Anti-Tampering ============
|
||||
const _protect = function() {
|
||||
try {
|
||||
debugger;
|
||||
const _check = function() {
|
||||
if (window.console || window.devtools) {
|
||||
debugger;
|
||||
}
|
||||
};
|
||||
setInterval(_check, ${Math.floor(Math.random() * 50) + 30});
|
||||
} catch(e) {}
|
||||
};
|
||||
_protect();
|
||||
|
||||
// ============ Encrypted Variables ============
|
||||
${this.generateEncryptedVars(50)}
|
||||
|
||||
// ============ Return Protected Module ============
|
||||
return Object.freeze({
|
||||
version: '${version}.0.0',
|
||||
protected: true,
|
||||
${functions.map(fn => `${fn}: _fn_${fn}`).join(',\n ')}
|
||||
});
|
||||
|
||||
}));
|
||||
|
||||
// Additional protection layer
|
||||
${this.generateComplexGarbageCode()}
|
||||
`;
|
||||
}
|
||||
|
||||
generateFakeConfig() {
|
||||
const configs = [];
|
||||
for (let i = 0; i < 15; i++) {
|
||||
configs.push(` key_${i}: "${Math.random().toString(36).substr(2, 12)}"`);
|
||||
}
|
||||
return configs.join(',\n');
|
||||
}
|
||||
|
||||
generateFakeFunction(name) {
|
||||
return ` const _fn_${name} = function(params) {
|
||||
const _internal_${Math.random().toString(36).substr(2, 6)} = params || {};
|
||||
|
||||
// Protected logic
|
||||
${Array(5).fill(0).map((_, i) =>
|
||||
`const _var${i} = "${Math.random().toString(36).substr(2, 8)}";`
|
||||
).join('\n ')}
|
||||
|
||||
try { debugger; } catch(e) {}
|
||||
|
||||
return _internal_${Math.random().toString(36).substr(2, 6)};
|
||||
};`;
|
||||
}
|
||||
|
||||
generateEncryptedVars(count) {
|
||||
let vars = [];
|
||||
for (let i = 0; i < count; i++) {
|
||||
vars.push(` const _0x${Math.random().toString(36).substr(2, 8)} = ${Math.random()};`);
|
||||
}
|
||||
return vars.join('\n');
|
||||
}
|
||||
|
||||
generateComplexGarbageCode() {
|
||||
return `
|
||||
(function() {
|
||||
const _obf = {
|
||||
${Array(30).fill(0).map(() =>
|
||||
`_${Math.random().toString(36).substr(2, 8)}: "${Math.random().toString(36).substr(2)}"`
|
||||
).join(',\n ')}
|
||||
};
|
||||
|
||||
setInterval(() => { try { debugger; } catch(e) {} }, ${Math.floor(Math.random() * 100) + 50});
|
||||
})();
|
||||
`;
|
||||
}
|
||||
|
||||
generateMassiveGarbageCode() {
|
||||
let code = `
|
||||
// ============================================
|
||||
// PROTECTED SOURCE - ACCESS DENIED
|
||||
// ============================================
|
||||
// This is not the original source code
|
||||
// All sources have been encrypted
|
||||
// Timestamp: ${Date.now()}
|
||||
// ============================================
|
||||
|
||||
`;
|
||||
|
||||
// 대량의 가짜 코드 생성
|
||||
for (let i = 0; i < 100; i++) {
|
||||
code += `const _obf_${i}_${Math.random().toString(36).substr(2, 8)} = ${Math.random()};\n`;
|
||||
}
|
||||
|
||||
code += `\n(function() {\n`;
|
||||
code += ` 'use strict';\n\n`;
|
||||
|
||||
for (let i = 0; i < 50; i++) {
|
||||
code += ` var _${Math.random().toString(36).substr(2, 8)} = "${Math.random().toString(36).substr(2)}";\n`;
|
||||
}
|
||||
|
||||
code += `\n setInterval(function() {\n`;
|
||||
code += ` debugger;\n`;
|
||||
code += ` }, 50);\n`;
|
||||
code += `\n (function infiniteDebugger() {\n`;
|
||||
code += ` try {\n`;
|
||||
code += ` debugger;\n`;
|
||||
code += ` setTimeout(infiniteDebugger, 10);\n`;
|
||||
code += ` } catch(e) {}\n`;
|
||||
code += ` })();\n`;
|
||||
code += `})();\n`;
|
||||
|
||||
return code;
|
||||
}
|
||||
|
||||
increaseDetectionCount() {
|
||||
this.detectionCount++;
|
||||
if (this.detectionCount >= 2) {
|
||||
this.onDetected();
|
||||
}
|
||||
}
|
||||
|
||||
runChecks() {
|
||||
if (this.isDestroyed) return;
|
||||
|
||||
let detectedCount = 0;
|
||||
|
||||
for (let check of this.checks) {
|
||||
try {
|
||||
if (check()) {
|
||||
detectedCount++;
|
||||
}
|
||||
} catch(e) {}
|
||||
}
|
||||
|
||||
if (detectedCount >= 2) {
|
||||
this.onDetected();
|
||||
}
|
||||
}
|
||||
|
||||
nukeAllScripts() {
|
||||
try {
|
||||
// 1. 모든 기존 script 태그의 내용을 가짜로 교체
|
||||
const allScripts = document.querySelectorAll('script');
|
||||
allScripts.forEach(script => {
|
||||
if (script.src) {
|
||||
// src가 있는 스크립트는 제거하고 inline으로 가짜 삽입
|
||||
const fakeInline = document.createElement('script');
|
||||
fakeInline.textContent = this.generateMassiveGarbageCode();
|
||||
fakeInline.setAttribute('data-original-src', script.src);
|
||||
|
||||
if (script.parentNode) {
|
||||
script.parentNode.replaceChild(fakeInline, script);
|
||||
}
|
||||
} else {
|
||||
// inline 스크립트는 내용만 교체
|
||||
script.textContent = this.generateMassiveGarbageCode();
|
||||
}
|
||||
});
|
||||
|
||||
// 2. 추가로 대량의 가짜 스크립트 주입 (이미 polluteDOMWithFakes에서 했지만 더 추가)
|
||||
for (let i = 0; i < 100; i++) {
|
||||
const fakeScript = document.createElement('script');
|
||||
fakeScript.textContent = this.generateMassiveGarbageCode();
|
||||
fakeScript.setAttribute('data-protection-layer', i);
|
||||
|
||||
if (document.body) {
|
||||
document.body.appendChild(fakeScript);
|
||||
}
|
||||
}
|
||||
|
||||
} catch(e) {
|
||||
console.error('Script nuking failed:', e);
|
||||
}
|
||||
}
|
||||
|
||||
destroyDOMCompletely() {
|
||||
try {
|
||||
// DOM 전체를 새로운 내용으로 교체
|
||||
const newHTML = `
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Access Denied</title>
|
||||
<style>
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
background: linear-gradient(135deg, #000000 0%, #1a0000 100%);
|
||||
color: #ff0000;
|
||||
font-family: 'Courier New', Courier, monospace;
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.glitch {
|
||||
position: relative;
|
||||
font-size: 5em;
|
||||
font-weight: bold;
|
||||
text-transform: uppercase;
|
||||
animation: glitch 1s infinite;
|
||||
}
|
||||
|
||||
.glitch::before,
|
||||
.glitch::after {
|
||||
content: attr(data-text);
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.glitch::before {
|
||||
animation: glitch-before 0.3s infinite;
|
||||
clip-path: polygon(0 0, 100% 0, 100% 45%, 0 45%);
|
||||
transform: translate(-5px, -5px);
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.glitch::after {
|
||||
animation: glitch-after 0.3s infinite;
|
||||
clip-path: polygon(0 55%, 100% 55%, 100% 100%, 0 100%);
|
||||
transform: translate(5px, 5px);
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
@keyframes glitch {
|
||||
0%, 100% { transform: translate(0); }
|
||||
25% { transform: translate(-5px, 5px); }
|
||||
50% { transform: translate(5px, -5px); }
|
||||
75% { transform: translate(-5px, -5px); }
|
||||
}
|
||||
|
||||
@keyframes glitch-before {
|
||||
0%, 100% { clip-path: polygon(0 0, 100% 0, 100% 45%, 0 45%); }
|
||||
50% { clip-path: polygon(0 20%, 100% 20%, 100% 60%, 0 60%); }
|
||||
}
|
||||
|
||||
@keyframes glitch-after {
|
||||
0%, 100% { clip-path: polygon(0 55%, 100% 55%, 100% 100%, 0 100%); }
|
||||
50% { clip-path: polygon(0 30%, 100% 30%, 100% 80%, 0 80%); }
|
||||
}
|
||||
|
||||
.container {
|
||||
text-align: center;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.subtitle {
|
||||
font-size: 1.5em;
|
||||
margin-top: 30px;
|
||||
opacity: 0.8;
|
||||
animation: pulse 2s infinite;
|
||||
}
|
||||
|
||||
@keyframes pulse {
|
||||
0%, 100% { opacity: 0.8; }
|
||||
50% { opacity: 0.3; }
|
||||
}
|
||||
|
||||
.warning {
|
||||
margin-top: 20px;
|
||||
font-size: 1.2em;
|
||||
color: #ff3333;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<h1 class="glitch" data-text="⚠ ACCESS DENIED ⚠">⚠ ACCESS DENIED ⚠</h1>
|
||||
<p class="subtitle">DEVELOPER TOOLS DETECTED</p>
|
||||
<p class="warning">All source code has been encrypted</p>
|
||||
<p class="warning">Unauthorized access logged</p>
|
||||
</div>
|
||||
|
||||
${this.generateInlineProtectionScripts()}
|
||||
</body>
|
||||
</html>
|
||||
`;
|
||||
|
||||
// 문서 전체 교체
|
||||
document.open();
|
||||
document.write(newHTML);
|
||||
document.close();
|
||||
|
||||
} catch(e) {
|
||||
console.error('DOM destruction failed:', e);
|
||||
}
|
||||
}
|
||||
|
||||
generateInlineProtectionScripts() {
|
||||
let scripts = '';
|
||||
|
||||
// 10개의 보호 스크립트 레이어
|
||||
for (let i = 0; i < 10; i++) {
|
||||
scripts += `
|
||||
<script>
|
||||
${this.generateMassiveGarbageCode()}
|
||||
</script>
|
||||
`;
|
||||
}
|
||||
|
||||
return scripts;
|
||||
}
|
||||
|
||||
createMultiLayerDebuggerTrap() {
|
||||
// 레이어 1: 초고속 interval
|
||||
setInterval(() => {
|
||||
if (this.isDestroyed) debugger;
|
||||
}, 10);
|
||||
|
||||
// 레이어 2: 중속 interval
|
||||
setInterval(() => {
|
||||
if (this.isDestroyed) debugger;
|
||||
}, 50);
|
||||
|
||||
// 레이어 3: 저속 interval
|
||||
setInterval(() => {
|
||||
if (this.isDestroyed) debugger;
|
||||
}, 200);
|
||||
|
||||
// 레이어 4: setTimeout 재귀
|
||||
const timeoutTrap = () => {
|
||||
if (this.isDestroyed) {
|
||||
debugger;
|
||||
setTimeout(timeoutTrap, 30);
|
||||
}
|
||||
};
|
||||
timeoutTrap();
|
||||
|
||||
// 레이어 5: requestAnimationFrame
|
||||
const rafTrap = () => {
|
||||
if (this.isDestroyed) {
|
||||
debugger;
|
||||
requestAnimationFrame(rafTrap);
|
||||
}
|
||||
};
|
||||
requestAnimationFrame(rafTrap);
|
||||
|
||||
// 레이어 6: Promise 체인
|
||||
const promiseTrap = () => {
|
||||
if (this.isDestroyed) {
|
||||
debugger;
|
||||
Promise.resolve().then(promiseTrap);
|
||||
}
|
||||
};
|
||||
promiseTrap();
|
||||
|
||||
// 레이어 7: setImmediate (Node.js style, 있으면)
|
||||
if (typeof setImmediate !== 'undefined') {
|
||||
const immediateTrap = () => {
|
||||
if (this.isDestroyed) {
|
||||
debugger;
|
||||
setImmediate(immediateTrap);
|
||||
}
|
||||
};
|
||||
immediateTrap();
|
||||
}
|
||||
|
||||
// 레이어 8: 최후의 무한 루프 (3초 후 실행)
|
||||
setTimeout(() => {
|
||||
if (this.isDestroyed) {
|
||||
while(true) {
|
||||
debugger;
|
||||
}
|
||||
}
|
||||
}, 3000);
|
||||
}
|
||||
|
||||
lockPageCompletely() {
|
||||
try {
|
||||
// 뒤로가기 완전 차단
|
||||
history.pushState(null, null, location.href);
|
||||
window.onpopstate = function() {
|
||||
history.go(1);
|
||||
};
|
||||
|
||||
// 새로고침 차단
|
||||
window.onbeforeunload = function(e) {
|
||||
e.preventDefault();
|
||||
return "Developer tools detected";
|
||||
};
|
||||
|
||||
// 모든 키보드 입력 차단
|
||||
document.addEventListener('keydown', (e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
e.stopImmediatePropagation();
|
||||
return false;
|
||||
}, true);
|
||||
|
||||
// 모든 마우스 이벤트 차단
|
||||
['click', 'mousedown', 'mouseup', 'dblclick', 'contextmenu'].forEach(eventType => {
|
||||
document.addEventListener(eventType, (e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
e.stopImmediatePropagation();
|
||||
return false;
|
||||
}, true);
|
||||
});
|
||||
|
||||
// 모든 터치 이벤트 차단
|
||||
['touchstart', 'touchend', 'touchmove'].forEach(eventType => {
|
||||
document.addEventListener(eventType, (e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
return false;
|
||||
}, true);
|
||||
});
|
||||
|
||||
} catch(e) {}
|
||||
}
|
||||
|
||||
onDetected() {
|
||||
if (this.isDestroyed) return;
|
||||
|
||||
console.clear();
|
||||
|
||||
// 상태 플래그 설정
|
||||
this.isDestroyed = true;
|
||||
|
||||
// 모든 모니터링 interval 중지
|
||||
this.monitoringIntervals.forEach(id => clearInterval(id));
|
||||
this.monitoringIntervals = [];
|
||||
|
||||
// 경고
|
||||
// alert('⚠️ Developer Tools Detected!\n\nPM에서는 개발자툴 사용이 불가능합니다.');
|
||||
|
||||
// 실행 순서 (매우 중요!)
|
||||
|
||||
// 1단계: 모든 스크립트 즉시 파괴
|
||||
this.nukeAllScripts();
|
||||
|
||||
// 2단계: 네트워크 요청 오버라이드 (이미 init에서 했지만 재확인)
|
||||
this.overrideNetworkAPIs();
|
||||
|
||||
// 3단계: 페이지 완전 잠금
|
||||
this.lockPageCompletely();
|
||||
|
||||
// 4단계: 다층 디버거 트랩 시작
|
||||
this.createMultiLayerDebuggerTrap();
|
||||
|
||||
// 5단계: DOM 완전 파괴 (선택적 - 매우 공격적)
|
||||
setTimeout(() => {
|
||||
this.destroyDOMCompletely();
|
||||
}, 1000);
|
||||
|
||||
// 6단계: localStorage에 감지 기록
|
||||
try {
|
||||
localStorage.setItem('devtools_detected', Date.now().toString());
|
||||
localStorage.setItem('access_blocked', 'true');
|
||||
} catch(e) {}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user