lolcaken/javascript-deobfuscator

Deobfuscator for javascript-obfuscator 5.x output (string arrays, control-flow flattening, self-defending, RC4/base64)

TypeScript

1

0 commits

updated Oct 6, 2026

See the code

See what people are saying

README

javascript-deobfuscator

Deobfuscator for javascript-obfuscator 5.x output. Feed it obfuscated JS, get back readable JS that runs the same.

Setup

Requires Node 18+.

git clone https://github.com/lolcaken/javascript-deobfuscator.git
cd javascript-deobfuscator
npm install
npm run build

Usage

Deobfuscate a file (writes <name>.deob.js next to the input unless -o is given):

node dist/src/cli.js input.ob.js -o output.js --stats

Flags:

FlagEffect
-o <file>output path (default: <input>.deob.js)
--no-renamekeep _0x… identifiers instead of renaming them
--statsprint what each pass changed
-husage

Or after npm link, anywhere:

deobfuscate input.ob.js -o output.js

Use it as a library:

import { deobfuscate } from 'javascript-deobfuscator';

const { code, stats } = deobfuscate(obfuscatedSource, { rename: true });
console.log(code);

Install from npm once published:

npm install javascript-deobfuscator

Example

Input — test/fixtures/source.js obfuscated with javascript-obfuscator (string arrays + rotation, split strings, control-flow flattening, dead-code injection, object-key transforms, number expressions), 3690 bytes of this:

function _0x54b6(_0xb7919b,_0x500140){_0xb7919b=_0xb7919b-(0x1f8d+-0x1*-0xb9d+0x2a06*-0x1);const _0x229d59=_0x1598();let _0x3ccc27=_0x229d59[_0xb7919b];return _0x3ccc27;}const _0x822f89=_0x54b6;function _0x1598(){const _0x23b861=['com/','http','ies','log','join','uiXo','alic','fqAn','oint','bob','2zqCUix','PJTj','3161739tTCvqO','?r=','5dPKAUt','727970ZDbPoX','ple.','caro','neg','s://',…];_0x1598=function(){return _0x23b861;};return _0x1598();}(function(_0x5e6e6e,_0x257dcb){const _0x5ed3d4=_0x54b6,_0x860095=_0x5e6e6e();while(!![]){try{const _0x44a344=-parseInt(_0x5ed3d4(0x138))/(0xb*-0x281+0x1c08+0x2*-0x3e)+…;if(_0x44a344===_0x257dcb)break;else _0x860095['push'](_0x860095['shift']());}catch(_0x1f2aee){_0x860095['push'](_0x860095['shift']());}}}(_0x1598,…));const greeting=_0x822f89(0x12e)+'o';function greet(_0x35652d){…}const users=[_0x822f89(0x12c)+'e',_0x822f89(0x12d),_0x822f89(0x138)+'l'];

(The full obfuscated file is at test/fixtures/demo.ob.js.)

Output — 2359 bytes, runs identically:

const greeting = "Hello";
function greet(p) {
  const q = f,
    r = {};
  r[q(0x12b) + 'i'] = function (u, v) {
    return u + v;
  }, r[q(0x140) + 'X'] = function (w, x) {
    return w + x;
  };
  const s = r,
    t = s[q(0x12b) + 'i'](s[q(0x12b) + 'i'](s[q(0x140) + 'X'](greeting, ',\x20'), p), '!');
  return t;
}
const users = ["alice", "bob", "carol"];
let total = 0;
for (let i = 0; i < users.length; i++) {
  total += users[i].length, console.log(greet(users[i]));
}

(Full output: test/fixtures/demo.deob.js.)

Both print:

Hello, alice!
Hello, bob!
Hello, carol!
https://api.example.com/v1?r=3 13 zero|pos|pos

What it handles

  • string arrays (plain, base64, RC4) with rotation loops, decoder wrappers, calls-transform, split strings
  • control-flow flattening (while(true){switch…}), dead-code injection
  • proxy functions/objects, object-key transforms, number expressions
  • self-defending / debug protection / console-output disabling (removed)
  • scope-aware _0x… renaming

Tests

npm test obfuscates sample programs with javascript-obfuscator 5.9.0 under three presets (default, medium, heavy) and asserts the deobfuscated code prints identical output and reparses cleanly. Currently 9/9.

License

ISC — see LICENSE.

ast
babel
deobfuscation
deobfuscator
javascript
malware-analysis
obfuscator
reverse-engineering
security
typescript

lolcaken/javascript-deobfuscator

Deobfuscator for javascript-obfuscator 5.x output (string arrays, control-flow flattening, self-defending, RC4/base64)

TypeScript

1

0 commits

updated Oct 6, 2026

See the code

See what people are saying

README

javascript-deobfuscator

Deobfuscator for javascript-obfuscator 5.x output. Feed it obfuscated JS, get back readable JS that runs the same.

Setup

Requires Node 18+.

git clone https://github.com/lolcaken/javascript-deobfuscator.git
cd javascript-deobfuscator
npm install
npm run build

Usage

Deobfuscate a file (writes <name>.deob.js next to the input unless -o is given):

node dist/src/cli.js input.ob.js -o output.js --stats

Flags:

FlagEffect
-o <file>output path (default: <input>.deob.js)
--no-renamekeep _0x… identifiers instead of renaming them
--statsprint what each pass changed
-husage

Or after npm link, anywhere:

deobfuscate input.ob.js -o output.js

Use it as a library:

import { deobfuscate } from 'javascript-deobfuscator';

const { code, stats } = deobfuscate(obfuscatedSource, { rename: true });
console.log(code);

Install from npm once published:

npm install javascript-deobfuscator

Example

Input — test/fixtures/source.js obfuscated with javascript-obfuscator (string arrays + rotation, split strings, control-flow flattening, dead-code injection, object-key transforms, number expressions), 3690 bytes of this:

function _0x54b6(_0xb7919b,_0x500140){_0xb7919b=_0xb7919b-(0x1f8d+-0x1*-0xb9d+0x2a06*-0x1);const _0x229d59=_0x1598();let _0x3ccc27=_0x229d59[_0xb7919b];return _0x3ccc27;}const _0x822f89=_0x54b6;function _0x1598(){const _0x23b861=['com/','http','ies','log','join','uiXo','alic','fqAn','oint','bob','2zqCUix','PJTj','3161739tTCvqO','?r=','5dPKAUt','727970ZDbPoX','ple.','caro','neg','s://',…];_0x1598=function(){return _0x23b861;};return _0x1598();}(function(_0x5e6e6e,_0x257dcb){const _0x5ed3d4=_0x54b6,_0x860095=_0x5e6e6e();while(!![]){try{const _0x44a344=-parseInt(_0x5ed3d4(0x138))/(0xb*-0x281+0x1c08+0x2*-0x3e)+…;if(_0x44a344===_0x257dcb)break;else _0x860095['push'](_0x860095['shift']());}catch(_0x1f2aee){_0x860095['push'](_0x860095['shift']());}}}(_0x1598,…));const greeting=_0x822f89(0x12e)+'o';function greet(_0x35652d){…}const users=[_0x822f89(0x12c)+'e',_0x822f89(0x12d),_0x822f89(0x138)+'l'];

(The full obfuscated file is at test/fixtures/demo.ob.js.)

Output — 2359 bytes, runs identically:

const greeting = "Hello";
function greet(p) {
  const q = f,
    r = {};
  r[q(0x12b) + 'i'] = function (u, v) {
    return u + v;
  }, r[q(0x140) + 'X'] = function (w, x) {
    return w + x;
  };
  const s = r,
    t = s[q(0x12b) + 'i'](s[q(0x12b) + 'i'](s[q(0x140) + 'X'](greeting, ',\x20'), p), '!');
  return t;
}
const users = ["alice", "bob", "carol"];
let total = 0;
for (let i = 0; i < users.length; i++) {
  total += users[i].length, console.log(greet(users[i]));
}

(Full output: test/fixtures/demo.deob.js.)

Both print:

Hello, alice!
Hello, bob!
Hello, carol!
https://api.example.com/v1?r=3 13 zero|pos|pos

What it handles

  • string arrays (plain, base64, RC4) with rotation loops, decoder wrappers, calls-transform, split strings
  • control-flow flattening (while(true){switch…}), dead-code injection
  • proxy functions/objects, object-key transforms, number expressions
  • self-defending / debug protection / console-output disabling (removed)
  • scope-aware _0x… renaming

Tests

npm test obfuscates sample programs with javascript-obfuscator 5.9.0 under three presets (default, medium, heavy) and asserts the deobfuscated code prints identical output and reparses cleanly. Currently 9/9.

License

ISC — see LICENSE.

ast
babel
deobfuscation
deobfuscator
javascript
malware-analysis
obfuscator
reverse-engineering
security
typescript