How to Deobfuscate obfuscator.io Code — Step-by-Step Guide
If you've been reverse engineering JavaScript lately, there's a very good chance you've run into code produced by JavaScript Obfuscator — better known as obfuscator.io. It's the most widely used open-source JavaScript obfuscation tool in the world, with millions of downloads. It shows up in browser extensions, web scrapers fighting back against bots, malware samples, and plenty of legitimate applications protecting their front-end logic.
The good news: obfuscator.io follows predictable patterns. Once you know what to look for, you can reverse its output systematically. This guide will show you exactly how.
What Is obfuscator.io?
javascript-obfuscator (hosted at obfuscator.io) is a free, open-source tool that takes clean JavaScript and applies multiple layers of transformation to make it hard to read. Unlike simple minifiers that just remove whitespace, obfuscator.io fundamentally restructures the code.
Here's what clean code looks like before obfuscation:
function greet(name) {
const message = "Hello, " + name + "!";
console.log(message);
}
greet("World");And here's what the same code looks like after running through obfuscator.io with default settings:
var _0x3f2a=['World','log','Hello, ','greet'];
(function(_0x4b1c,_0x2e3d){
var _0x1a2b=function(_0x5c4e){
while(--_0x5c4e){
_0x4b1c['push'](_0x4b1c['shift']());
}
};
_0x1a2b(++_0x2e3d);
}(_0x3f2a,0x1b8));
var _0x2f1c=function(_0x3a4b,_0x5c2d){
_0x3a4b=_0x3a4b-0x0;
var _0x4f3e=_0x3f2a[_0x3a4b];
return _0x4f3e;
};
function _0x1b3c(_0x4d2e){
var _0x3c1f=_0x2f1c('0x0')+_0x4d2e+'!';
console[_0x2f1c('0x1')](_0x3c1f);
}
_0x1b3c(_0x2f1c('0x3'));A beautifier alone won't crack this. The formatting isn't the problem — the logichas been systematically replaced with encoded lookups. Let's understand each technique being used before we reverse it.
The 5 Techniques obfuscator.io Uses
1. String Array Obfuscation
All string literals are extracted from the code and placed into a single array (like _0x3f2aabove). Every reference to a string in the original code becomes a function call that looks up that index. The logic is still there — it's just buried under an indirection layer.
2. String Array Rotation
To make it even harder, obfuscator.io rotates the string array by a certain number of positions at runtime. You'll see a self-executing function that calls push and shiftin a loop — that's the rotation happening. This is why you can't just read the array directly; you have to evaluate it after rotation.
3. Variable Name Mangling
Every variable, function, and parameter name gets replaced with hex-prefixed identifiers like _0x1a2b, _0x3f2a, etc. These names carry zero semantic meaning. The number after _0xis just an index — it doesn't correspond to any value.
4. Hexadecimal Number Encoding
Plain numbers are replaced with their hexadecimal equivalents. 0x0 means 0, 0x1b8 means 440. This applies to array indices, loop counters, and any numeric literal in the original code.
5. Control Flow Flattening (Optional)
With control flow flattening enabled, obfuscator.io replaces if/else blocks and loops with aswitch statement inside a loop, controlled by a state variable. This is the most aggressive transformation and the hardest to reverse manually.
Step-by-Step: How to Deobfuscate obfuscator.io Code
Step 1 — Identify the String Array
Look for a variable declared at the top of the file containing an array of strings. It will look something like this:
var _0x3f2a = ['World', 'log', 'Hello, ', 'greet'];This is your Rosetta Stone. Every string the original code used is in here, just shuffled around.
Step 2 — Find the Rotation Function
Immediately after the array, you'll see a self-executing function that rotates it. It looks like this:
(function(_0x4b1c, _0x2e3d) {
var _0x1a2b = function(_0x5c4e) {
while (--_0x5c4e) {
_0x4b1c['push'](_0x4b1c['shift']());
}
};
_0x1a2b(++_0x2e3d);
}(_0x3f2a, 0x1b8));This rotates the array by 0x1b8(440) positions. The final order of the array after rotation is the real order. You don't need to do this manually — our deobfuscator evaluates it for you.
Step 3 — Resolve the Lookup Function
The lookup function (typically named something like _0x2f1c) takes a hex index and returns the corresponding string:
var _0x2f1c = function(_0x3a4b, _0x5c2d) {
_0x3a4b = _0x3a4b - 0x0; // convert hex string to number
var _0x4f3e = _0x3f2a[_0x3a4b];
return _0x4f3e;
};Once you know what each index maps to, you can mentally substitute every _0x2f1c('0x1') with its actual string value. For example, _0x2f1c('0x1') → 'log', so console[_0x2f1c('0x1')] is actually console.log.
Step 4 — Use an AST-Based Deobfuscator
Doing this manually is tedious. For anything beyond a toy example, you want a tool that:
- Evaluates the string array and its rotation
- Inlines all string lookups with their real values
- Renames variables where possible
- Beautifies the final output
Our JavaScript Deobfuscatorhandles all of this in one step. Paste your obfuscated code, hit Deobfuscate, and get readable output immediately. Here's what the obfuscated example from above becomes:
function greet(name) {
var message = "Hello, " + name + "!";
console.log(message);
}
greet("World");Exact same logic as the original. The transformation is complete.
What About Control Flow Flattening?
Control flow flattening is the one obfuscator.io technique that's harder to reverse automatically. If the code has it enabled, you'll see large switch statements inside while(true) loops, controlled by a string like '0|3|1|2|4'.split('|') that determines the execution order.
var _sequence = '0|3|1|2|4'['split']('|');
var _step = 0x0;
while (true) {
switch (_sequence[_step++]) {
case '0':
var name = _0x2f1c('0x3');
continue;
case '1':
console[_0x2f1c('0x1')](_message);
continue;
case '2':
greet(name);
continue;
case '3':
var _message = _0x2f1c('0x2') + name + '!';
continue;
case '4':
break;
}
break;
}This is still reversible. The sequence string ('0|3|1|2|4') tells you the actual execution order — read the cases in that order and you get the original logic back. For automated reversal, a proper AST tool will trace the state machine and reconstruct the original control flow.
Tips for Stubborn obfuscator.io Code
If auto-deobfuscation doesn't fully clean up the code, try these manual steps:
- Run it in a sandbox: Open Chrome DevTools, paste the code in the console (in an isolated tab), and use breakpoints to inspect variable values at runtime. The browser will do the decoding for you.
- Find the self-defending code:Some obfuscator.io configs add self-defending code that detects when it's being analyzed. Look for
setIntervalcalls at the global level — these are usually the anti-tampering mechanism. Removing them lets you analyze the rest freely. - Focus on the entry point:Don't try to understand everything at once. Find the function that gets called first and trace it forward. Most obfuscated code has a clear entry point.
- Use string substitution: Once you know what each
_0x2f1c('0xN')resolves to, do a find-and-replace across the file. This alone — even without reversing the control flow — makes the code dramatically more readable.
Is It Legal to Deobfuscate obfuscator.io Code?
Generally yes — for your own code, for code you have permission to analyze, or for security research purposes. JavaScript running in a browser is publicly accessible by design; the obfuscation is a speed bump, not legal protection.
That said, if you're analyzing someone else's proprietary application specifically to copy their implementation, that may violate their terms of service or copyright depending on your jurisdiction. Use your judgment and check the applicable terms. For security research, CTF challenges, malware analysis, and understanding your own dependencies — you're on solid ground.
Try It Now
Got some obfuscator.io code you need to analyze? Paste it into our free JavaScript Deobfuscator and get a clean, readable version instantly. No installation, no account, no upload limits.
Have obfuscator.io code to analyze?
Paste it below — our AST-based engine handles string arrays, rotation, and hex encoding automatically.
Open JS Deobfuscator →