Why Anti-Debugging Matters
Obfuscation protects your code from static analysis — reading the source file. But a determined reverse engineer can bypass static analysis entirely by running your code and observing its behavior with browser DevTools. Anti-debugging techniques target this dynamic analysis approach, making it much harder to step through your code, set breakpoints, or observe runtime values.
Technique 1: Debugger Statement Loop
The simplest anti-debugging technique is inserting debugger statements in a continuous loop. When DevTools is open, the browser breaks on each debugger statement, pausing execution — making it nearly impossible to use the debugger normally.
// Basic debugger trap
setInterval(function() {
debugger;
}, 100);
The javascript-obfuscator's "Debug Protection" option implements a more sophisticated version of this that's harder to simply click through.
Technique 2: DevTools Detection
It's possible to detect when browser DevTools is open using several browser quirks:
// Size-based detection (works in some browsers)
function isDevToolsOpen() {
return window.outerWidth - window.innerWidth > 200 ||
window.outerHeight - window.innerHeight > 200;
}
// Performance-based detection
function isDevToolsOpen() {
const start = performance.now();
debugger;
return performance.now() - start > 100; // Debugger paused execution
}
Note: These methods are not 100% reliable across all browsers and browser versions, but they work against non-technical users.
Technique 3: Function.toString() Monitoring
Sophisticated analysis tools often override built-in functions. You can detect this:
// Detect if console.log has been tampered with
const nativeLog = console.log.toString();
if (nativeLog.indexOf('[native code]') === -1) {
// console.log has been overridden — kill execution
while(true) {}
}
Technique 4: Timing Attacks
Code executes much slower when being stepped through in a debugger. Timing-based checks exploit this:
function timingCheck() {
const start = Date.now();
// Fast computation
for (let i = 0; i < 1000; i++) {}
const elapsed = Date.now() - start;
if (elapsed > 100) {
// Execution is too slow — debugger is attached
document.location = 'about:blank';
}
}
timingCheck();
Technique 5: Anti-Eval Detection
Some reverse engineering workflows involve eval()-ing modified versions of your code. Detecting eval contexts:
// Detect if running in eval context
try {
eval('var _check = 1');
if (typeof _check !== 'undefined') {
// Running in eval — suspicious
}
} catch(e) { /* strict mode blocks eval */ }
The Debug Protection Interval
Our obfuscator's debug protection option includes an interval parameter — how often (in milliseconds) to re-trigger the debugger check. A shorter interval (e.g., 500ms) is more aggressive but may impact user experience if somehow triggered in production. 2000ms is a reasonable default.
Combining Techniques
Anti-debugging is most effective layered with obfuscation. Obfuscation forces use of dynamic analysis; anti-debugging makes dynamic analysis painful. Together, they significantly raise the bar for anyone trying to understand your code at runtime.