How to deobfuscate JavaScript code

What is obfuscation?

Obfuscation is source code modification as a result it becomes difficult to read and understand, but so that its functionality does not change. Obfuscation is used for source code in interpreted (rather than compiled) programming languages. That is, it is JavaScript, PHP, obfuscation can be used for HTML (although it is a markup language, not a programming language), CSS and others, programs on which do not compile, but run in plain text.

Obfuscation is especially relevant for JavaScript, because, unlike, for example, PHP that runs on the web server, JavaScript is loaded into the browser and each user can have access to scripts.

Obfuscation uses different tricks. One of them is the removal of spaces. This is called code minify and is used not only to obfuscate, but to speed up script downloads. As a side effect, this code is really hard to figure out.

Often during obfuscation, the code turns into a meaningless set of functions and lines that cannot be understood, but which ultimately do exactly the same thing as the source code. But there are really amazing examples of obfuscation, for example, JSFuck can display any JavaScript code with just the following six characters []()!+

For example, the following code is workable JavaScript code:

[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[
]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]][([][(![]+[])[+[]]+([![]]+[][[]
])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+
(!![]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+
!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![
]+[])[+!+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+(!![]
+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(![]+[])[+[]]+([![]]+[][[]])[
+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!!
[]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[][(![]+[])[+[]]+([![
]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[
]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]]((![]+[])[+!+[]]+(![
]+[])[!+[]+!+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]+(!![]+[])[+[]]+(!
[]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])
[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[!+[]+!+[]+[+[]]]+[+!+[]]+(
!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[
])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[!+[]+!+[]+[+[]]])()

Obfuscation is used by both legitimate users who want to protect their ideas and their code from theft, and hackers to make it difficult to analyze their methods and programs.

What is deobfuscation

Deobfuscation is the reverse process of obfuscation, that is, the translation of code from a hard-to-read form into an understandable one.

Since there are many obfuscation methods, deobfuscation methods and tools are also many and they have different capabilities and varying degrees of effectiveness.

Deobfuscation is needed both in the analysis of malicious code and in the study of the target site to understand the logic of its operation and search for vulnerabilities.

An example of the use of deobfuscation will be shown in the next article during the site “hacking”.

1. Readable JavaScript in browser

Modern web browsers can beautify compressed to save traffic code to its original state.

In Google Chrome (or Chromium) go to Webmaster Tools (F12 button), select the Sources tab and the file of interest:

Click on the curly brackets icon { } and the code will be transformed into an easy-to-read form:

In Firefox, this button is available on the Debugger tab:

Result:

2. JStillery

JStillery performs advanced JavaScript deobfuscation via partial evaluation.

JStillery can be used without installation – the program is available as an online service from the author: https://mindedsecurity.github.io/jstillery/.

Ho to install JStillery

Installation on Kali Linux

git clone https://github.com/mindedsecurity/JStillery
cd JStillery
sudo npm install

To compile the server (if you need not only a tool with a command line interface, but you also want to use the web interface):

npm run build_server

To start the server:

npm run start_server

After that, the web interface will be available at http://localhost:3001

Installation in BlackArch

sudo pacman -S jstillery

The use is very simple, just specify the path to the file for deobfuscation:

jstillery /path/to/file

3. Universal deobfuscator of JavaScript code de4js

de4js is a JavaScript source code deobfuscator and unpacker.

It supports (de-obfuscates) the result of the following tools, services, methods:

Information about installation and launch can be found on the program page: https://en.kali.tools/?p=1372

de4js runs as a small server to which you can connect with a web browser. That is, the program has a web interface.

Go to the folder with the program:

cd bin/de4js

Start the server:

npm start

In a web browser open the address http://127.0.0.1:4000/de4js/

In the web interface, select one of the following methods for entering obfuscated source code:

  • String – insert code into the web interface window
  • Local File – select a local file on the computer
  • Remote File – specify the URL address of a remote file

Below you can specify the way the JavaScript code was obfuscated:

  • None
  • Eval
  • Array
  • Obfuscator IO
  • _Number
  • JSFuck
  • JJencode
  • AAencode
  • URLencode
  • Packer
  • JS Obfuscator
  • My Obfuscate
  • Wise Eval
  • Wise Function
  • Clean Source
  • Unreadable

Alternatively, you can click the “Auto Decode” button for de4js to automatically detect the obfuscation method. The deobfuscated code will be shown in the window below.

Additional options that you can turn on or off:

  • Line numbers – show line numbers
  • Format Code – code formatting and syntax highlighting
  • Unescape strings – convert strings from escaped sequences to normal form
  • Recover object-path – restore object-path
  • Execute expression – perform arithmetic and other operations on expressions
  • Merge strings - concatenate strings
  • Remove grouping

de4js online: https://lelinhtinh.github.io/de4js/

4. JavaScript online deobfuscator deobfuscatejavascript.com

Service Address: http://deobfuscatejavascript.com/

The source code of this service is not hosted on GitHub, but this product is also open source, since all operations are performed in the browser, and the deobfuscation functions are located in the file http://deobfuscatejavascript.com/deobfuscate.js.

The code analyzed by this tool will be executed in your browser. This tool is designed only to intercept calls made by the eval() and write() functions, which are commonly used as the final function in malicious JavaScript scripts. Some malicious scripts may not use these features and therefore may infect your browser.

This tool is designed to help analysts deobfuscate malicious JavasSripts. It does not interpret HTML, so any HTML must be removed to properly deobfuscate the code. The script also should not contain syntax errors to get the correct results.

Black holes, landing pages, and exploit kits use obfuscation to hide code intent while reducing the chance of detection. When the scripts are packaged, the source code becomes data, and the visible code becomes a deobfuscation procedure. At run time, the data is unpacked by the subroutine, and the result is a string that must be processed as code to execute. This tool during the deobfuscation procedure returns this line of code, but does not start its execution. The resulting code is shown with syntax highlighting.

5. Deobfuscation Obfuscator.IO

The author of the Obfuscator.IO website is looking for programs that are able to deobfuscate the code created on this service and constantly changes, fixes obfuscation, as a result of which the deobfuscation tools stop working. Therefore, automatic deobfuscation tools (including de4js) usually lag behind the most recent version, that is, they can deobfuscate the code created earlier on Obfuscator.IO, but cannot deobfuscate the latest version of the code. But this does not mean that this is a reliable tool to secure your source code – projects regularly appear that bypass all deobfuscation methods. In addition, custom-made specialists can deobfuscate any code.

6. JS Beautifier

JS Beautifier improves the appearance of JavaScript code by reformatting and indenting. In addition it knows how to unpack scripts packaged by the popular packer from Dean Edward. It can partially deobfuscate scripts processed by the npm javascript-obfuscator package. It is used to improve readability of JavaScript code.

The program is available as an online service from the authors: https://beautifier.io/

How to install JS Beautifier

Installation on Kali Linux

sudo apt install npm
sudo npm -g install js-beautify
js-beautify -h

Installation in BlackArch

There are two installation options – from repositories and as an NPM package. The Python version is available in BlackArch repositories, its features are that html-beautify is completely absent, and css-beautify cannot be installed due to an error. There are also some other differences.

If you want to install from standard repositories then run the following command:

sudo pacman -S python-jsbeautifier

If you want to install Node.js JavaScript version, then run the following commands:

sudo pacman -R python-jsbeautifier
sudo pacman -S npm
sudo npm -g install js-beautify
js-beautify -h

Windows installation

Start by installing Python in the article “How to install Python and PIP on Windows 10”.

After installing Python and PIP, run the commands:

sudo pip3 install jsbeautifier
sudo pip3 install cssbeautifier

How to install JS Beautifier on Debian, Linux Mint, Ubuntu you can find on this page: https://en.kali.tools/?p=1359

Usage:

jsbeautifier.py [OPTIONS] <INPUT FILE>

For instance:

jsbeautifier.py [ОПЦИИ] <INPUT FILE>

All js-beautify options:

CLI Options:
  -f, --file       Input file(s) (Pass '-' for stdin)
  -r, --replace    Write output in-place, replacing input
  -o, --outfile    Write output to file (default stdout)
  --config         Path to config file
  --type           [js|css|html] ["js"]
  -q, --quiet      Suppress logging to stdout
  -h, --help       Show this help
  -v, --version    Show the version

Beautifier Options:
  -s, --indent-size                 Indentation size [4]
  -c, --indent-char                 Indentation character [" "]
  -t, --indent-with-tabs            Indent with tabs, overrides -s and -c
  -e, --eol                         Character(s) to use as line terminators.
                                    [first newline in file, otherwise "\n]
  -n, --end-with-newline            End output with newline
  --indent-empty-lines              Keep indentation on empty lines
  --templating                      List of templating languages (auto,none,django,erb,handlebars,php) ["auto"] auto = none in JavaScript, all in html
  --editorconfig                    Use EditorConfig to set up the options
  -l, --indent-level                Initial indentation level [0]
  -p, --preserve-newlines           Preserve line-breaks (--no-preserve-newlines disables)
  -m, --max-preserve-newlines       Number of line-breaks to be preserved in one chunk [10]
  -P, --space-in-paren              Add padding spaces within paren, ie. f( a, b )
  -E, --space-in-empty-paren        Add a single space inside empty paren, ie. f( )
  -j, --jslint-happy                Enable jslint-stricter mode
  -a, --space-after-anon-function   Add a space before an anonymous function's parens, ie. function ()
  --space_after_named_function      Add a space before a named function's parens, ie. function example ()
  -b, --brace-style                 [collapse|expand|end-expand|none][,preserve-inline] [collapse,preserve-inline]
  -u, --unindent-chained-methods    Don't indent chained method calls
  -B, --break-chained-methods       Break chained method calls across subsequent lines
  -k, --keep-array-indentation      Preserve array indentation
  -x, --unescape-strings            Decode printable characters encoded in xNN notation
  -w, --wrap-line-length            Wrap lines that exceed N characters [0]
  -X, --e4x                         Pass E4X xml literals through untouched
  --good-stuff                      Warm the cockles of Crockford's heart
  -C, --comma-first                 Put commas at the beginning of new line instead of end
  -O, --operator-position           Set operator position (before-newline|after-newline|preserve-newline) [before-newline]

7. UglifyJS

The UglifyJS toolkit performs various actions with code written in JavaScript without changing its functionality. The program can parse, compress, obfuscate or, conversely, make JavaScript scripts more readable.

In terms of deobfuscation, UglifyJS can make compressed JavaScript code readable.

Installation on Kali Linux

sudo apt install uglifyjs

Installation in BlackArch

sudo pacman -S uglify-js

How to install UglifyJS on Debian, Linux Mint, Ubuntu you can find on this page: https://en.kali.tools/?p=1365

Launch example: to improve the appearance of JavaScript code in the file, use the -b option; a file (or several files) must be specified before the options:

uglifyjs medium.js -b

The program can also process files piped in standard input:

cat medium.js | uglifyjs -b

All UglifyJS options:

    -h, --help                  Print usage information.
                                `--help options` for details on available options.
    -V, --version               Print version number.
    -p, --parse <options>       Specify parser options:
                                `acorn`  Use Acorn for parsing.
                                `bare_returns`  Allow return outside of functions.
                                                Useful when minifying CommonJS
                                                modules and Userscripts that may
                                                be anonymous function wrapped (IIFE)
                                                by the .user.js engine `caller`.
                                `expression`  Parse a single expression, rather than
                                              a program (for parsing JSON).
                                `spidermonkey`  Assume input files are SpiderMonkey
                                                AST format (as JSON).
    -c, --compress [options]    Enable compressor/specify compressor options:
                                `pure_funcs`  List of functions that can be safely
                                              removed when their return values are
                                              not used.
    -m, --mangle [options]      Mangle names/specify mangler options:
                                `reserved`  List of names that should not be mangled.
    --mangle-props [options]    Mangle properties/specify mangler options:
                                `builtins`  Mangle property names that overlaps
                                            with standard JavaScript globals.
                                `debug`  Add debug prefix and suffix.
                                `domprops`  Mangle property names that overlaps
                                            with DOM properties.
                                `keep_quoted`  Only mangle unquoted properties.
                                `regex`  Only mangle matched property names.
                                `reserved`  List of names that should not be mangled.
    -b, --beautify [options]    Beautify output/specify output options:
                                `beautify`  Enabled with `--beautify` by default.
                                `preamble`  Preamble to prepend to the output. You
                                            can use this to insert a comment, for
                                            example for licensing information.
                                            This will not be parsed, but the source
                                            map will adjust for its presence.
                                `quote_style`  Quote style:
                                               0 - auto
                                               1 - single
                                               2 - double
                                               3 - original
                                `wrap_iife`  Wrap IIFEs in parenthesis. Note: you may
                                             want to disable `negate_iife` under
                                             compressor options.
    -O, --output-opts [options] Specify output options (`beautify` disabled by default).
    -o, --output <file>         Output file path (default STDOUT). Specify `ast` or
                                `spidermonkey` to write UglifyJS or SpiderMonkey AST
                                as JSON to STDOUT respectively.
    --comments [filter]         Preserve copyright comments in the output. By
                                default this works like Google Closure, keeping
                                JSDoc-style comments that contain "@license" or
                                "@preserve". You can optionally pass one of the
                                following arguments to this flag:
                                - "all" to keep all comments
                                - a valid JS RegExp like `/foo/` or `/^!/` to
                                keep only matching comments.
                                Note that currently not *all* comments can be
                                kept when compression is on, because of dead
                                code removal or cascading statements into
                                sequences.
    --config-file <file>        Read `minify()` options from JSON file.
    -d, --define <expr>[=value] Global definitions.
    -e, --enclose [arg[:value]] Embed everything in a big function, with configurable
                                argument(s) & value(s).
    --ie8                       Support non-standard Internet Explorer 8.
                                Equivalent to setting `ie8: true` in `minify()`
                                for `compress`, `mangle` and `output` options.
                                By default UglifyJS will not try to be IE-proof.
    --keep-fnames               Do not mangle/drop function names.  Useful for
                                code relying on Function.prototype.name.
    --name-cache <file>         File to hold mangled name mappings.
    --self                      Build UglifyJS as a library (implies --wrap UglifyJS)
    --source-map [options]      Enable source map/specify source map options:
                                `base`  Path to compute relative paths from input files.
                                `content`  Input source map, useful if you're compressing
                                           JS that was generated from some other original
                                           code. Specify "inline" if the source map is
                                           included within the sources.
                                `filename`  Filename and/or location of the output source
                                            (sets `file` attribute in source map).
                                `includeSources`  Pass this flag if you want to include
                                                  the content of source files in the
                                                  source map as sourcesContent property.
                                `names` Include symbol names in the source map.
                                `root`  Path to the original source to be included in
                                        the source map.
                                `url`  If specified, path to the source map to append in
                                       `//# sourceMappingURL`.
    --timings                   Display operations run time on STDERR.
    --toplevel                  Compress and/or mangle variables in top level scope.
    --verbose                   Print diagnostic messages.
    --warn                      Print warning messages.
    --wrap <name>               Embed everything in a big function, making the
                                “exports” and “global” variables available. You
                                need to pass an argument to this option to
                                specify the name that your module will take
                                when included in, say, a browser.

Conclusion

If I missed some tool to deobfuscate JavaScript code, then write in the comments!

In the next article, we will try to circumvent the protection of the site, which is written in JavaScript – we will use different approaches, in the most difficult cases, tools for deobfuscation will be useful to us. See the sequel to “JavaScript Attacks”.

Recommended for you:

One Comment to How to deobfuscate JavaScript code

  1. Tarun Soni says:

    Superb article and very helpfull too.

Leave a Reply

Your email address will not be published. Required fields are marked *