Giter Club home page Giter Club logo

javascript-deobfuscator's Introduction

General purpose JavaScript deobfuscator

A simple but powerful deobfuscator to remove common JavaScript obfuscation techniques. Open an issue if there is a feature you think should be implemented.

Online version at deobfuscate.io

Install via npm install js-deobfuscator

Looking for a deobfuscator specific to Obfuscator.io/javascript-obfuscator? Try this repo

If you would like to discuss/learn about JavaScript obfuscation and deobfuscation you can join the Discord server

Features

  • Unpacks arrays containing literals (strings, numbers etc) and replaces all references to them
  • Removes simple proxy functions (calls to another function), array proxy functions and arithmetic proxy functions (binary expressions)
  • Simplifies arithmetic expressions
  • Simplifies string concatenation
  • Renames unreadable hexadecimal identifiers (e.g. _0xca830a)
  • Converts computed to static member expressions and beautifies the code

Examples

See bottom for more complicated example with features chained together.

Array Unpacking

Before

const a = ['\x20', '\x57\x6f\x72\x6c\x64', '\x48\x65\x6c\x6c\x6f'];

console.log(a[2] + a[0] + a[1]);

After

console.log('Hello' + ' ' + 'World');

Proxy Functions

An example with simple proxy functions for other functions

Before

function a(b, c) {
    return someFunction(b, c);
}

const result = a(5, 6);

After

const result = someFunction(5, 6);

An example with proxy functions for arithmetic

Before

function a(b, c) {
    return c + 2 * b;
}

const result = a(5, 6);

After

const result = 6 + 2 * 5;

An example with chained proxy functions

Before

function a(b, c) {
    return c + 2 * b;
}
function b(c, d) {
    return a(c, d);
}
function c(d, e) {
    return b(d, e);
}

const result = c(5, 6);

After

const result = 6 + 2 * 5;

Expression Simplification

An example with numbers

Before

let total = 0x2 * 0x109e + -0xc * -0x16a + -0x3234;
for (let i = 0x1196 + 0x97b * 0x3 + -0x2e07; i < -0x95 * -0x38 + -0x1a75 + -0x619; i++) {
    total += i;
}

After

let total = 0;
for (let i = 0; i < 10; i++) {
    total += i;
}

An example with strings.

Before

console.log('He' + 'll' + 'o' + ' Wo' + 'r' + 'ld');

After

console.log('Hello World');

Overall Example

All these features can be chained together to simplify code.

Before

const ar = [
    '\x48\x65\x6c\x6c\x6f',
    0x95,
    '\x20',
    0x1a75,
    '\x57\x6f\x72\x6c\x64',
    -0x53,
    '\x6c\x6f\x67'
];
const a = function (b, c) {
        return c + 2 * b;
    },
    b = function (c, d) {
        return a(c, d);
    },
    c = function (d, e) {
        return b(d, e);
    };
const message = ar[0] + ar[2] + ar[4];
const result = c(ar[1] * 0x38 + ar[3] + 0x619, 0x12 * ar[5] + 0x1a13 + 0x621);
console[ar[6]](message + ' ' + result);

After

const message = 'Hello World';
const result = 40106;
console.log(message + ' ' + result);

Config

interface Config {
    arrays: {
        unpackArrays: boolean;
        removeArrays: boolean;
    };
    proxyFunctions: {
        replaceProxyFunctions: boolean;
        removeProxyFunctions: boolean;
    };
    expressions: {
        simplifyExpressions: boolean;
        removeDeadBranches: boolean;
    };
    miscellaneous: {
        beautify: boolean;
        simplifyProperties: boolean;
        renameHexIdentifiers: boolean;
    };
}

To Run

Either install the module locally via npm install js-deobfuscator and import as usual or install globally npm install -g js-deobfuscator and use the js-deobfuscator CLI:

> js-deobfuscator -h
Usage: run [options]

Deobfuscate a javascript file

Options:
  -i, --input [input_file]    The input file to deobfuscate (default: "input/source.js")
  -o, --output [output_file]  The deobfuscated output file (default: "output/output.js")
  -f, --force                 Whether to overwrite the output file or not
  -h, --help                  display help for command

>

Alternatively use the online version at deobfuscate.io

javascript-deobfuscator's People

Contributors

aarock1234 avatar ben-sb avatar bvanheu avatar humphryyy avatar liudonghua123 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

javascript-deobfuscator's Issues

Replace !![] and ![]

obfuscator.io tends to use !![] for true and ![] for false. Replacing these might clean up the code a bit.

throw new Error(`Ran out of variable names`)

/tmp/javascript-deobfuscator/dist/modifications/renaming/variableRenamer.js:195
throw new Error(Ran out of variable names);
^

Error: Ran out of variable names
at VariableRenamer.getVariableName (/tmp/javascript-deobfuscator/dist/modifications/renaming/variableRenamer.js:195:19)
at VariableRenamer.renameVariables (/tmp/javascript-deobfuscator/dist/modifications/renaming/variableRenamer.js:169:38)
at VariableRenamer.renameVariables (/tmp/javascript-deobfuscator/dist/modifications/renaming/variableRenamer.js:174:18)
at VariableRenamer.renameVariables (/tmp/javascript-deobfuscator/dist/modifications/renaming/variableRenamer.js:174:18)
at VariableRenamer.renameVariables (/tmp/javascript-deobfuscator/dist/modifications/renaming/variableRenamer.js:174:18)
at VariableRenamer.execute (/tmp/javascript-deobfuscator/dist/modifications/renaming/variableRenamer.js:32:14)
at /tmp/javascript-deobfuscator/dist/index.js:59:34
at Array.forEach ()
at Object.deobfuscate (/tmp/javascript-deobfuscator/dist/index.js:59:19)
at Object. (/tmp/javascript-deobfuscator/dist/run.js:27:24)

unnecessary freezing after pasting large code into textarea

on www.deobfuscator.io there's an unnecessary delay between pasting the code and launching the dialog box.

You could use:
launchModal(message);
setTimeout(function() { processData(thisData) }, 10);

This would launch the modal immediately and then wait 10ms before processing the data so there's no delay between Ctrl+V and launching the modal.

Error

/root/javascript-deobfuscator/node_modules/shift-parser/dist/parser.js:206
throw this.createUnexpected(this.lookahead);
^

Error: [1:3561]: Unexpected identifier
at new JsError (/root/javascript-deobfuscator/node_modules/shift-parser/dist/tokenizer.js:166:104)
at GenericParser.createError (/root/javascript-deobfuscator/node_modules/shift-parser/dist/tokenizer.js:297:14)
at GenericParser.createUnexpected (/root/javascript-deobfuscator/node_modules/shift-parser/dist/tokenizer.js:265:23)
at GenericParser.expect (/root/javascript-deobfuscator/node_modules/shift-parser/dist/parser.js:206:18)
at GenericParser.parseGroupExpression (/root/javascript-deobfuscator/node_modules/shift-parser/dist/parser.js:2215:12)
at GenericParser.parsePrimaryExpression (/root/javascript-deobfuscator/node_modules/shift-parser/dist/parser.js:1943:21)
at GenericParser.parseLeftHandSideExpression (/root/javascript-deobfuscator/node_modules/shift-parser/dist/parser.js:1779:21)
at GenericParser.parseUpdateExpression (/root/javascript-deobfuscator/node_modules/shift-parser/dist/parser.js:1656:26)
at GenericParser.parseUnaryExpression (/root/javascript-deobfuscator/node_modules/shift-parser/dist/parser.js:1628:21)
at GenericParser.parseExponentiationExpression (/root/javascript-deobfuscator/node_modules/shift-parser/dist/parser.js:1598:23) {
index: 3560,
line: 1,
column: 3561,
parseErrorLine: 1,
parseErrorColumn: 3561,
description: 'Unexpected identifier'
}

Variable names, lambda functions, and executing safe javascript

Thank you for this useful tool.

I have been receiving phishing/spam messages with IP addresses in the Russian Federation (e.g., 3260518168///sh.php) that redirect to a page with the following Javascript:

var _0x45a3=['href','310326TemamY','$1//$2','3789jqLAjI','201260CufYBR','includes','location','624856ogdMrz','28pRWhXX','10734yvtFqz','352RuMMpQ','1339PvpRAh','392868PctkdY','indexOf','596BmZxvY'];var _0x5ce7=function(_0x34bb17,_0x37718d){_0x34bb17=_0x34bb17-0x1b8;var _0x45a37a=_0x45a3[_0x34bb17];return _0x45a37a;};var _0x3c82e1=_0x5ce7;(function(_0x4279be,_0x4a014c){var _0x2ec4e6=_0x5ce7;while(!![]){try{var _0xe2f92d=-parseInt(_0x2ec4e6(0x1c4))+parseInt(_0x2ec4e6(0x1c2))*-parseInt(_0x2ec4e6(0x1bf))+-parseInt(_0x2ec4e6(0x1c0))+parseInt(_0x2ec4e6(0x1bc))*parseInt(_0x2ec4e6(0x1bd))+parseInt(_0x2ec4e6(0x1bb))+-parseInt(_0x2ec4e6(0x1b8))+parseInt(_0x2ec4e6(0x1c6))*parseInt(_0x2ec4e6(0x1be));if(_0xe2f92d===_0x4a014c)break;else _0x4279be['push'](_0x4279be['shift']());}catch(_0x1227cb){_0x4279be['push'](_0x4279be['shift']());}}}(_0x45a3,0x87e5e));var params='lptoken=16bb40f2638560276692';params!=''&&(window[_0x3c82e1(0x1ba)][_0x3c82e1(0x1c3)][_0x3c82e1(0x1c1)]('?')<0x0?params='?'+params:params='&'+params);if(window['location']['href'][_0x3c82e1(0x1b9)]('#'))window[_0x3c82e1(0x1ba)][_0x3c82e1(0x1c3)]=window['location'][_0x3c82e1(0x1c3)]['replace'](/(.*?)\/\/(.*?)\/(.*)#/,_0x3c82e1(0x1c5))+params;
[Click to see the output from deobfuscate.io]
var _0x45a3 = ["href", "310326TemamY", "$1//$2", "3789jqLAjI", "201260CufYBR", "includes", "location", "624856ogdMrz", "28pRWhXX", "10734yvtFqz", "352RuMMpQ", "1339PvpRAh", "392868PctkdY", "indexOf", "596BmZxvY"];
var _0x5ce7 = function (_0x34bb17, _0x37718d) {
  _0x34bb17 = _0x34bb17 - 440;
  var _0x45a37a = _0x45a3[_0x34bb17];
  return _0x45a37a;
};
var _0x3c82e1 = _0x5ce7;
(function (_0x4279be, _0x4a014c) {
  var _0x2ec4e6 = _0x5ce7;
  while (!![]) {
    try {
      var _0xe2f92d = -parseInt(_0x2ec4e6(452)) + parseInt(_0x2ec4e6(450)) * -parseInt(_0x2ec4e6(447)) + -parseInt(_0x2ec4e6(448)) + parseInt(_0x2ec4e6(444)) * parseInt(_0x2ec4e6(445)) + parseInt(_0x2ec4e6(443)) + -parseInt(_0x2ec4e6(440)) + parseInt(_0x2ec4e6(454)) * parseInt(_0x2ec4e6(446));
      if (_0xe2f92d === _0x4a014c) break; else _0x4279be.push(_0x4279be.shift());
    } catch (_0x1227cb) {
      _0x4279be.push(_0x4279be.shift());
    }
  }
}(_0x45a3, 556638));
var params = "lptoken=16bb40f2638560276692";
params != "" && (window[_0x3c82e1(442)][_0x3c82e1(451)][_0x3c82e1(449)]("?") < 0 ? params = "?" + params : params = "&" + params);
if (window.location.href[_0x3c82e1(441)]("#")) window[_0x3c82e1(442)][_0x3c82e1(451)] = window.location[_0x3c82e1(451)].replace(/(.*?)\/\/(.*?)\/(.*)#/, _0x3c82e1(453)) + params;
  1. It would be nice if javascript-deobfuscator had an option for renaming variables and functions that begin with underscore ('_'). Since single letter names (a, b, c) can be confusing, I suggest assigning names using a phonetic alphabet: alpha, bravo, charlie.

  2. Another trick that is being used is to assign a lambda function to a variable instead of defining it normally. For example:

     var _0x5ce7 = function (_0x34bb17, _0x37718d) {
       _0x34bb17 = _0x34bb17 - 440;
       var _0x45a37a = _0x45a3[_0x34bb17];
       return _0x45a37a;
     };
     var _0x3c82e1 = _0x5ce7;

    Can such anonymous function definitions be deobfuscated?

  3. Finally, it looks like this code is using an array of strings as a lookup table to scramble its code. It may not be possible always, but it would be nice, where it is safe to do so, if javascript-deobfuscator could execute trivial javascript functions.

    For example, function _0x3c82e1 (defined above) is safe as it only subtracts the number 440 and then looks up a string from this table:

    [
      'href',         '310326TemamY', '$1//$2',       '3789jqLAjI',
      '201260CufYBR', 'includes',     'location',     '624856ogdMrz',
      '28pRWhXX',     '10734yvtFqz',  '352RuMMpQ',    '1339PvpRAh',
      '392868PctkdY', 'indexOf',      '596BmZxvY'
    ]

    It would be very helpful if javascript-deobfuscator could convert this:

    if (window.location.href[_0x3c82e1(441)]("#"))
      window[_0x3c82e1(442)][_0x3c82e1(451)] 
        = window.location[_0x3c82e1(451)].replace(/(.*?)\/\/(.*?)\/(.*)#/, _0x3c82e1(453)) + params;

    into something like this:

    if (window.location.href['310326TemamY']("#"))
      window['$1//$2']['1339PvpRAh']
        = window.location['310326TemamY'].replace(/(.*?)\/\/(.*?)\/(.*)#/, 'indexOf') + params;

    (This deobfuscation was done by hand so it likely definitely has errors, which shows how important it is to have an automated tool for deobfuscation.)

Comma Expression: different results

I wanted to help out and started digging into the cause of #36.
Although I was unable to locate the core issue ( I believe the deobfuscation would actually finish, although allowing a deobfuscation parameter to limit the time spent on reversing any particular function would be nice), I stumbled upon something:

Deobfuscating example A leads to vastly different results in comparison to deobfuscating example B

This feels somewhat ackward and I wonder whether there's a bug or how this happens.

@ben-sb It'd be nice if you could throw in a guess

Example A

    function Se(p1, p2) {
        _e(_e(_e(_e(De(De(De(De(Me(Me(Me(Me(Ae(
                                                            i = Ae(
                                                                i = Ae(
                                                                    i = Ae(
                                                                        i, r = Ae(
                                                                            r, a = Ae(
                                                                                a, n = Ae(
                                                                                    n, i, r, a, p2[0], 7, -680876936), i, r, p2[1], he, -389564586), n, i, p2[2], ge, 606105819), a, n, p2[3], we, -1044525330), r = Ae(
                                                                                        r, a = Ae(
                                                                                            a, n = Ae(
                                                                                                n, i, r, a, p2[4], 7, -176418897), i, r, p2[5], he, 1200080426), n, i, p2[6], ge, -1473231341), a, n, p2[7], we, -45705983), r = Ae(
                                                                                                    r, a = Ae(
                                                                                                        a, n = Ae(
                                                                                                            n, i, r, a, p2[8], 7, 1770035416),
                                                                        i, r, p2[9], he, -1958414417), n, i, p2[ue], ge, -42063), a, n, p2[le], we, -1990404162), r = Ae(r, a = Ae(a, n = Ae(n, i, r, a, p2[he], 7, 1804603682), i, r, p2[de], he, -40341101), n, i, p2[me], ge, -1502002290), a, n, p2[fe], we, 1236535329), r = Me(r, a = Me(a, n = Me(n, i, r, a, p2[1], 5, -165796510), i, r, p2[6], 9, -1069501632), n, i, p2[le], me, 643717713), a, n, p2[0], ve, -373897302), r = Me(r, a = Me(a, n = Me(n, i, r, a, p2[5], 5, -701558691), i, r, p2[ue], 9, 38016083), n, i, p2[fe], me, -660478335), a, n, p2[4], ve, -405537848), r = Me(r, a = Me(a, n = Me(n, i, r, a, p2[9], 5, 568446438), i, r, p2[me], 9, -1019803690), n, i, p2[3], me, -187363961), a, n, p2[8], ve, 1163531501), r = Me(r, a = Me(a, n = Me(n, i, r, a, p2[de], 5, -1444681467), i, r, p2[2], 9, -51403784), n, i, p2[7], me, 1735328473), a, n, p2[he], ve, -1926607734), r = De(r, a = De(a, n = De(n, i, r, a, p2[5], 4, -378558), i, r, p2[8], le, -2022574463), n, i, p2[le], pe, 1839030562), a, n, p2[me], be, -35309556), r = De(r, a = De(a, n = De(n, i, r, a, p2[1], 4, -1530992060), i, r, p2[4], le, 1272893353), n, i, p2[7], pe, -155497632), a, n, p2[ue], be, -1094730640), r = De(r, a = De(a, n = De(n, i, r, a, p2[de], 4, 681279174), i, r, p2[0], le, -358537222), n, i, p2[3], pe, -722521979), a, n, p2[6], be, 76029189), r = De(r, a = De(a, n = De(n, i, r, a, p2[9], 4, -640364487), i, r, p2[he], le, -421815835), n, i, p2[fe], pe, 530742520), a, n, p2[2], be, -995338651), r = _e(r, a = _e(a, n = _e(n, i, r, a, p2[0], 6, -198630844), i, r, p2[7], ue, 1126891415), n, i, p2[me], fe, -1416354905), a, n, p2[5], ye, -57434055), r = _e(r, a = _e(a, n = _e(n, i, r, a, p2[he], 6, 1700485571), i, r, p2[3], ue, -1894986606), n, i, p2[ue], fe, -1051523), a, n, p2[1], ye, -2054922799), r = _e(r, a = _e(a, n = _e(n, i, r, a, p2[8], 6, 1873313359), i, r, p2[fe], ue, -30611744), n, i, p2[6], fe, -1560198380), a, n, p2[de], ye, 1309151649), r = _e(r, a = _e(a, n = _e(n, i, r, a, p2[4], 6, -145523070), i, r, p2[le], ue, -1120210379), n, i, p2[2], fe, 718787259), a, n, p2[9], ye, -343485551)
        p1[0] = Ce(n, p1[0])
    }

    function Pe(p1, p2, p3, p4, p5, p6) {
        return p2 = Ce(p1, p6), Ce(p2 << p5 | p2 >>> Ve - p5, p3)
    }

    function Ae(p1, p2, p3, p4, p5, p6, p7) {
        return Pe(p2 & p3 | ~p2 & p4, p1, p2, p5, p6, p7)
    }


    function _e(p1, p2, p3, p4, p5, p6, p7) {
        return Pe(p3 ^ (p2 | ~p4), p1, p2, p5, p6, p7)
    }

Example B

Note: Differs only in this part, where the return statement with the comma expression in Pe is refactored into two statements:

    function Pe(p1, p2, p3, p4, p5, p6) {
        p2 = Ce(p1, p6)
        return Ce(p2 << p5 | p2 >>> Ve - p5, p3)
    }

npm ERR! could not determine executable to run

PS C:\Users_> npx js-deobfuscator -h
npm ERR! could not determine executable to run

npm ERR! A complete log of this run can be found in:
npm ERR! C:\Users_\AppData\Local\npm-cache_logs\2023-01-05T07_22_49_314Z-debug-0.log

1 info using [email protected]
2 info using [email protected]
3 timing npm:load:whichnode Completed in 0ms
4 timing config:load:defaults Completed in 2ms
5 timing config:load:file:C:\Program Files\nodejs\node_modules\npm\npmrc Completed in 2ms
6 timing config:load:builtin Completed in 2ms
7 timing config:load:cli Completed in 2ms
8 timing config:load:env Completed in 1ms
9 timing config:load:project Completed in 1ms
10 timing config:load:file:C:\Users\_\.npmrc Completed in 0ms
11 timing config:load:user Completed in 1ms
12 timing config:load:file:C:\Users\_\AppData\Roaming\npm\etc\npmrc Completed in 0ms
13 timing config:load:global Completed in 0ms
14 timing config:load:setEnvs Completed in 1ms
15 timing config:load Completed in 10ms
16 timing npm:load:configload Completed in 10ms
17 timing npm:load:mkdirpcache Completed in 0ms
18 timing npm:load:mkdirplogs Completed in 0ms
19 verbose title npm exec js-deobfuscator -h
20 verbose argv "exec" "--" "js-deobfuscator" "-h"
21 timing npm:load:setTitle Completed in 1ms
22 timing config:load:flatten Completed in 2ms
23 timing npm:load:display Completed in 3ms
24 verbose logfile logs-max:10 dir:C:\Users\_\AppData\Local\npm-cache\_logs\2023-01-05T07_22_49_314Z-
25 verbose logfile C:\Users\_\AppData\Local\npm-cache\_logs\2023-01-05T07_22_49_314Z-debug-0.log
26 timing npm:load:logFile Completed in 4ms
27 timing npm:load:timers Completed in 0ms
28 timing npm:load:configScope Completed in 0ms
29 timing npm:load Completed in 19ms
30 silly logfile start cleaning logs, removing 2 files
31 timing config:load:flatten Completed in 0ms
32 silly logfile done cleaning log files
33 timing arborist:ctor Completed in 0ms
34 timing arborist:ctor Completed in 0ms
35 http fetch GET 200 https://registry.npmjs.org/js-deobfuscator 219ms (cache revalidated)
36 timing command:exec Completed in 323ms
37 verbose stack Error: could not determine executable to run
37 verbose stack     at getBinFromManifest (C:\Program Files\nodejs\node_modules\npm\node_modules\libnpmexec\lib\get-bin-from-manifest.js:17:23)
37 verbose stack     at exec (C:\Program Files\nodejs\node_modules\npm\node_modules\libnpmexec\lib\index.js:187:15)
37 verbose stack     at async module.exports (C:\Program Files\nodejs\node_modules\npm\lib\cli.js:133:5)
38 verbose pkgid [email protected]
39 verbose cwd C:\Users\_
40 verbose Windows_NT 10.0.22621
41 verbose node v19.3.0
42 verbose npm  v9.2.0
43 error could not determine executable to run
44 verbose exit 1
45 timing npm Completed in 361ms
46 verbose code 1
47 error A complete log of this run can be found in:
47 error     C:\Users\_\AppData\Local\npm-cache\_logs\2023-01-05T07_22_49_314Z-debug-0.log

js-deobfuscator: command not found

npm install --global js-deobfuscator
.. seems to work fine ... but, then on trying ...
js-deobfuscator
-bash: js-deobfuscator: command not found
(macOS 11)

Replace proxy functions breaks on function that returns string literal

function b() {
	return ':)';
}

b();

The above code fails to deobfuscate if the Replace Proxy Functions modification is used.
Tested both via Browser and npm package - fails at

Cannot read properties of undefined (reading 'expression')
at ProxyFunction.duplicateExpression (S:\Dev\javascript-deobfuscator\dist\modifications\proxies\proxyFunction.js:89:34)
    at ProxyFunction.getReplacement (S:\Dev\javascript-deobfuscator\dist\modifications\proxies\proxyFunction.js:35:31)
    at Controller.enter (S:\Dev\javascript-deobfuscator\dist\modifications\proxies\proxyRemover.js:205:61)
    at Controller.__execute (S:\Dev\javascript-deobfuscator\node_modules\estraverse\estraverse.js:397:31)
    at Controller.traverse (S:\Dev\javascript-deobfuscator\node_modules\estraverse\estraverse.js:501:28)
    at Object.traverse (S:\Dev\javascript-deobfuscator\node_modules\estraverse\estraverse.js:713:27)
    at ProxyRemover.replaceProxyFunctionUsages (S:\Dev\javascript-deobfuscator\dist\modifications\proxies\proxyRemover.js:190:20)
    at ProxyRemover.execute (S:\Dev\javascript-deobfuscator\dist\modifications\proxies\proxyRemover.js:38:14)
    at Object.deobfuscate (S:\Dev\javascript-deobfuscator\dist\index.js:74:22)

Deobfuscate array shifting technique efficiently

I came accross this obfuscated js file where arrays are shifted before accessing the elements, those making the parser not work efficiently. This is the final result of the deobfuscator

Actual result

var array = ["a", "b", "c"];
(function (yair, aralynne) {
  var lashanta = function (naylah) {
    while (--naylah) {
      yair.push(yair.shift());
    }
  };
  lashanta(++aralynne);
}(array, 2));
var access_element = function (kahmari, aakash) {
  kahmari = kahmari - 0;
  var michea = array[kahmari];
  return michea;
};

var sample_string = access_element("0x0")

console.log("Sample String", sample_string);
// Output: Sample String c
// because the array was shifted twice

Expected result

var sample_string = "c"
console.log("Sample String", sample_string);

Replace wrong

original:

_0xf2c21d['0'] = 0x808200,
_0xf2c21d['1'] = 0x8000,
_0xf2c21d[_0x3a8459(0x311)] = 0x8000,

after execution: (look like is simplify properties)

_0xf2c21d.0 = 8421888,
_0xf2c21d.1 = 32768,
_0xf2c21d[_0x3a8459(785)] = 32768,

obufuscator: obfuscator.io

I tried to use your old project to deobfuscate it but i have error about:
FATAL ERROR: invalid array length Allocation failed - JavaScript heap out of memory

I would like to contact you but discord say i can't add you like friend

npm missing version 1.0.20

Could you please publish version 1.0.20 on npm please ? Right now doing a npm install -g js-deobfuscator uses 1.0.19, and we cannot use the binary afterwards.

Error while deobefusating

Source attached (script from 9anime.to website) source.zip

Log:


> [email protected] start C:\Users\PsychoX\Desktop\deob
> tsc && node dist/run.js

PS C:\Users\PsychoX\Desktop\deob> npm start

> [email protected] start C:\Users\PsychoX\Desktop\deob
> tsc && node dist/run.js

D:\Users\PsychoX\Desktop\deob\dist\modifications\proxies\proxyRemover.js:97
                if (node == scope.node && scope.parent) {
                                  ^

TypeError: Cannot read property 'node' of undefined
    at Controller.leave (D:\Users\PsychoX\Desktop\deob\dist\modifications\proxies\proxyRemover.js:97:35)
    at Controller.__execute (D:\Users\PsychoX\Desktop\deob\node_modules\estraverse\estraverse.js:397:31)
    at Controller.traverse (D:\Users\PsychoX\Desktop\deob\node_modules\estraverse\estraverse.js:491:28)
    at Object.traverse (D:\Users\PsychoX\Desktop\deob\node_modules\estraverse\estraverse.js:713:27)
    at ProxyRemover.replaceProxyFunctionUsages (D:\Users\PsychoX\Desktop\deob\dist\modifications\proxies\proxyRemover.js:75:27)
    at Controller.enter (D:\Users\PsychoX\Desktop\deob\dist\modifications\proxies\proxyRemover.js:86:44)
    at Controller.__execute (D:\Users\PsychoX\Desktop\deob\node_modules\estraverse\estraverse.js:397:31)
    at Controller.traverse (D:\Users\PsychoX\Desktop\deob\node_modules\estraverse\estraverse.js:501:28)
    at Object.traverse (D:\Users\PsychoX\Desktop\deob\node_modules\estraverse\estraverse.js:713:27)
    at ProxyRemover.replaceProxyFunctionUsages (D:\Users\PsychoX\Desktop\deob\dist\modifications\proxies\proxyRemover.js:75:27)
npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! [email protected] start: `tsc && node dist/run.js`
npm ERR! Exit status 1
npm ERR!
npm ERR! Failed at the [email protected] start script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.

[Bug] Mishandling of scope

In the following example, the declaration of bar via const bar = function(){…} is not incorporated in the deobfuscation result of function body foo:

function foo() {
    const bar = function () {
        for (;;){
            return 0;
        }
    };

    const x = bar();
    return x
}

function bar() {
    return 42;
}

deobfuscation should result in foo returning 0 either directly or indirectly instead.

replaceProxyFunctionUsages

excuse me
I get an infinite wait when I try to remove proxy functions
In this recursive function -> replaceProxyFunctionUsages
Can a recursion depth limit be added?
Otherwise, we really have to wait until the sea is dry and the rocks are rotten.

script url

Js deobfustace, i can pay

Hello, can you please add me on discord "kFxDaKing#7380" i would like to deobfustace something, i can pay for that.

Function executor does not deal with array of literals and deletes code even if no replacement is found

The following snippet does not simplify

function _0x1661() {
    "#execute";
    return ["str1", "str2"];
}
const foo = _0x1661()[0];

FunctionExecutor.replaceFunctionCalls() tries to replace the call by a literal value and fails (since we have a table of literals), so nothing gets replaced in the foo assigment (and cannot be simplified further).

The output is also not sound since the function is removed and the code can no longer be executed. Output is:

const foo = _0x1661()[0];

I don't know much about javascript, so there might be good reasons for not handling this. What you think?

Cannot deobfuscate private fields

Hello! I try to deobfuscate a file that have private fields (hash char #):
here docs on mozilla

..............node_modules\shift-parser\dist\tokenizer.js:1536
        throw this.createILLEGAL();
        ^
Error: [1:6801]: Unexpected "#"
Console error:
  index: 6800,
  line: 1,
  column: 6801,
  parseErrorLine: 1,
  parseErrorColumn: 6801,
  description: 'Unexpected "#"'

I guess it's a problem related to shift-parser that not support those new spec.

These things

var a2_0x313fb4 = a2_0x20b6;
(function (shailoh, obai) {
  var vanner = a2_0x20b6;
  while (true) {
    try {
      var shacoyia = parseInt(vanner(336)) * -parseInt(vanner(369)) + parseInt(vanner(504)) * parseInt(vanner(455)) + -parseInt(vanner(364)) * -parseInt(vanner(529)) + -parseInt(vanner(331)) + -parseInt(vanner(334)) + parseInt(vanner(388)) + parseInt(vanner(374)) * parseInt(vanner(489));
      if (shacoyia === obai) break; else shailoh.push(shailoh.shift());
    } catch (zafina) {
      shailoh.push(shailoh.shift());
    }
  }
}(a2_0x3004, 451175));

It creates a function that calls itself, which then runs a for loop, which checks if two numbers equal each other (they always do), then breaks off. Can we detect these and cut them off? They're useless and confusing.

Also, can we try to find a way to simplify these parseInt things?

Fails to deobfuscate

I think its obfuscate.io i used your older deobfuscator it kind of worked. but replaced the info from the array to the wrong spots.
Yet this one doesnt seem to do anything.

https://pastebin.com/hSxmhrd8

If you could help find a solution for this, as i have a few files like this.
Thanks in advance.

dereferencing references to a constant array

I made this different from #11 for better issue tracking
still using https://deobfuscate.io/

after evaluating other parts of an obfuscator by hand i was left with an array of strings and references to those strings:
image
there can obviously be issues if this array is modified in code but i think you can check if this array is called or modified in some way

sample code:

totaly_constant_array = ["log", "heyo"]

console[totaly_constant_array[0]](totaly_constant_array[1])

deobfuscated:

totaly_constant_array = ["log", "heyo"];
console[totaly_constant_array[0]](totaly_constant_array[1]);

kinda expected:

console.log("heyo");

nested references

Hello! found an interesting piece of scam code in the "wild": https://gofile.io/d/jhJW5T

it contains arrays with references to other arrays.
that code doesn't get untangled in a single pass

example:

const firststage = ['\x54\x6f\x74a\x6c', '\x6c\x6f\x67', '\x3a\x20'];
const secondstage = [firststage[0], firststage[1], firststage[2]];
const thirdstage = [secondstage[0], secondstage[1], secondstage[2]];
const fourthstage = [thirdstage[0], thirdstage[1], thirdstage[2]];
console.log(fourthstage[0], fourthstage[1], fourthstage[2]);

first pass:

const secondstage = ["Total", "log", ": "];
const thirdstage = [secondstage[0], secondstage[1], secondstage[2]];
const fourthstage = [thirdstage[0], thirdstage[1], thirdstage[2]];
console.log(fourthstage[0], fourthstage[1], fourthstage[2]);

second pass:

const thirdstage = ["Total", "log", ": "];
const fourthstage = [thirdstage[0], thirdstage[1], thirdstage[2]];
console.log(fourthstage[0], fourthstage[1], fourthstage[2]);

... you get the idea

expected after first pass:

console.log("Total", "log", ": ");

Uncaught Error: Failed to find scope for node FunctionBody

Using the following code in the web version, I get this error, which seems to be related to the 'Replace Proxy Functions' option:

WiNOMy0.js.txt

Uncaught Error: Failed to find scope for node FunctionBody
    at k.enter (main.js:2:686793)
    at k.__execute (main.js:2:6811)
    at k.traverse (main.js:2:7742)
    at Object.j [as traverse] (main.js:2:557)
    at d.replaceProxyFunctionUsages (main.js:2:686703)
    at k.enter (main.js:2:687057)
    at k.__execute (main.js:2:6811)
    at k.traverse (main.js:2:7742)
    at Object.j [as traverse] (main.js:2:557)
    at d.replaceProxyFunctionUsages (main.js:2:686703)

Crashed during function evaluate even though no execute directive used

/project/dist/modifications/execution/functionExecutor.js:62
                    const directive = node.body.directives.find((d) => d.rawValue.startsWith('#execute'));
                                                           ^

TypeError: Cannot read properties of undefined (reading 'find')
    at Controller.enter (/project/dist/modifications/execution/functionExecutor.js:62:60)
    at Controller.__execute (/project/node_modules/estraverse/estraverse.js:397:31)
    at Controller.traverse (/project/node_modules/estraverse/estraverse.js:501:28)
    at Object.traverse (/project/node_modules/estraverse/estraverse.js:713:27)
    at FunctionExecutor.findExecutedFunctions (/project/dist/modifications/execution/functionExecutor.js:59:27)
    at FunctionExecutor.execute (/project/dist/modifications/execution/functionExecutor.js:47:14)
    at /project/dist/index.js:59:34
    at Array.forEach (<anonymous>)
    at Object.deobfuscate (/project/dist/index.js:59:19)
    at Object.<anonymous> (/project/dist/run.js:27:24)

Sample formatted with esprima

The use of optional chaining operator (`?.`) breaks when parsing

let a = null;
if (a?.toString() > 5) {
    console.log(1);
} else {
    console.log(2);
}

 Error: [line:cloumn]: Unexpected token "."
    at new JsError (path/javascript-deobfuscator/node_modules/shift-parser/dist/tokenizer.js:166:104)
    at GenericParser.createError (path/javascript-deobfuscator/node_modules/shift-parser/dist/tokenizer.js:297:14)
    at GenericParser.createUnexpected (path/javascript-deobfuscator/node_modules/shift-parser/dist/tokenizer.js:276:23)
    at GenericParser.parsePrimaryExpression (path/javascript-deobfuscator/node_modules/shift-parser/dist/parser.js:2012:22)
    at GenericParser.parseLeftHandSideExpression (path/javascript-deobfuscator/node_modules/shift-parser/dist/parser.js:1779:21)
    at GenericParser.parseUpdateExpression (path/javascript-deobfuscator/node_modules/shift-parser/dist/parser.js:1656:26)
    at GenericParser.parseUnaryExpression (path/javascript-deobfuscator/node_modules/shift-parser/dist/parser.js:1628:21)
    at GenericParser.parseExponentiationExpression (path/javascript-deobfuscator/node_modules/shift-parser/dist/parser.js:1598:23)
    at GenericParser.parseBinaryExpression (path/javascript-deobfuscator/node_modules/shift-parser/dist/parser.js:1547:23)
    at GenericParser.parseConditionalExpression (path/javascript-deobfuscator/node_modules/shift-parser/dist/parser.js:1494:23) {
  index: 1,
  line: 1,
  column: 1,
  parseErrorLine: 1,
  parseErrorColumn: 1,
  description: 'Unexpected token "."'
}

The same snippet is also not valid using https://shift-ast.org/parser.html

Out of memory errors

Hi!

I'm attempting to use this to deobfuscate a relatively big javascript bundle (about 3mb minified), and am running into quite a few issues with it running out of memory. I've increased the stack size to 65500 using --stack-size=65500 (I also updated the ulimit appropriately), and have increased the max memory usage to 30000 MB using --max-old-space-size=30000, but still am running into issues. The most recent attempt had the following error when it reached about 18GB of memory usage (there was enough available memory on the host):

terminate called after throwing an instance of 'std::bad_alloc'
  what():  std::bad_alloc
Aborted (core dumped)

I also saw some high cpu usage for python while it was crashing, not sure if there's a python component of this tool?

The high memory usage is during the "remove proxy functions" stage. Any ideas of places that can be further optimised to work better for big inputs?

Unable to Load

I have this very long JS script:
https://bloxdcdn.bloxdhop.io/static/js/main.445ebc5f.js

Please don't ask what I'm doing with it. I don't know how JS works; I need to deobfuscate it to give it to someone. However, it doesn't deobfuscate and is always stuck on that original one. If anyone can get it to work, please show me it. I am using the website version.

Removing false branches

Hello! Thank you for making this cool tool.
i'm using https://deobfuscate.io/
after deobfuscating other parts of an obfuscator i'm left with a lot of true and false branches like this:
f720220120121248
don't forget ternary operators too!
image
sample code:

if (false) {
	console.log("never happens")
} else {
	console.log(2+2)
}

deobfuscated with https://deobfuscate.io/

if (false) {
  console.log("never happens");
} else {
  console.log(4);
}

Error: Cannot add duplicate edge [Edge-Id] -> [Edge-Id]

throw new Error(Cannot add duplicate edge ${edge.name});
^

Error: Cannot add duplicate edge 2ce1078d75cc4f1d8a304a9f751328dd -> 1cc2b1e3099740bda8186cc9f072f0f8
at Graph.addEdge (/Projects/javascript-deobfuscator-master/dist/graph/graph.js:62:19)
at Controller.enter (/Projects/javascript-deobfuscator-master/dist/modifications/proxies/proxyRemover.js:137:44)
at Controller.__execute (/Projects/javascript-deobfuscator-master/node_modules/estraverse/estraverse.js:397:31)
at Controller.traverse (/Projects/javascript-deobfuscator-master/node_modules/estraverse/estraverse.js:501:28)
at Object.traverse (/Projects/javascript-deobfuscator-master/node_modules/estraverse/estraverse.js:713:27)
at ProxyRemover.findCycles (/Projects/javascript-deobfuscator-master/dist/modifications/proxies/proxyRemover.js:126:24)
at ProxyRemover.execute (/Projects/javascript-deobfuscator-master/dist/modifications/proxies/proxyRemover.js:37:14)
at Object.deobfuscate (/Projects/javascript-deobfuscator-master/dist/index.js:65:22)
at Object. (/Projects/javascript-deobfuscator-master/dist/run.js:28:24)
at Module._compile (node:internal/modules/cjs/loader:1097:14)

source.js

Hi, I don't know if it is due to some anti-tampering mechanism.

If so, how could I identify it to remove it?

[Feature Request] Unpack Objects

Feature Request

Unpack Objects. This already works for arrays.

Example

Unpack foo[42] into "hello world".

var foo = {42: "hello world"};
console.log(foo[42]);

Expected Result

console.log("hello world");

Can I have renamed identifiers annotated with the original?

Deobfuscate.io, this is so useful! Keep it up!

But finding the renamed (deobfuscated) function with the original (obfuscated) function name is tricky. I’m doing dynamic analysis (“working on the obfuscated code”) on a live webpage, so ease of matching the obfuscated with the deobfuscated is a kind of necessity.

Can I get results like this?

function mikalia/*_0x2f18fb*/(kuulei, ajacia) {}

Contact

Hello, is there any way to contact with you? on discord for example if you have.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.