javascriptnode.jsgruntjsgrunt-contrib-uglify

Uglifying javascript code with grunt-contrib-uglify


I have the following file: package.json

{
  "name": "uglify",
  "devDependencies": {
    "grunt": "^1.0.1",
    "grunt-contrib-uglify": "^3.0.0"
  }
}

also the following file: Gruntfile.js

module.exports = function(grunt) {
    grunt.initConfig({
        uglify: {
            options: {
                beautify: true,
                mangle: {
                    properties: true
                }
            },
            log_sum_9: {
                src: 'log_sum_9.js',
                dest: 'log_sum_9.min.js'
            }
        }
    });
    grunt.loadNpmTasks('grunt-contrib-uglify');

    grunt.registerTask('log_sum_9', ['uglify:log_sum_9']);
}

also the following file: log_sum_9.js

(function() {
    var
        sum = "2+3+4",
        calc = function(operation) {
            return eval(operation);
        }
    ;
    console.log(calc(sum));
})();

Then I do:

to install the required NodeJS modules:

$ npm install

to uglify log_sum_9.js:

$ grunt log_sum_9

then I get the uglified file: log_sum_9.min.js:

!function() {
    var sum = "2+3+4", calc = function(operation) {
        return eval(operation);
    };
    console.log(calc("2+3+4"));
}();

Both scripts works properly:

$ node log_sum_9.js
9

$ node log_sum_9.min.js
9

My problem is that the uglified file log_sum_9.min.js didn't change the names of the variables: sum, calc, operation (all these variables are local variables).

If the content of the file log_sum_9.js is introduced on the following online obfuscator: https://www.javascriptobfuscator.com/Javascript-Obfuscator.aspx

then you get the following code:

var _0x257f = ["\x32\x2B\x33\x2B\x34", "\x6C\x6F\x67"];
(function() {
    var _0xb897x1 = _0x257f[0],
        _0xb897x2 = function(_0xb897x3) {
            return eval(_0xb897x3)
        };
    console[_0x257f[1]](_0xb897x2(_0xb897x1))
})()

where as you can see the previous 3 variables: sum, calc, operation has changed their names.

If you put the above code on the file: log_sum_9.online.js, then you can do:

$ node log_sum_9.online.js
9

(it works properly too)

My question is:

How do I have to configure the file: Gruntfile.js to get the previous 3 variables been obfuscated?


Solution

  • grunt-contrib-uglify, (as far as I'm aware), doesn't offer the same level of obfuscation as the online tool you linked to in your post - whereby it appears to encode Strings using JavaScript Hexadecimal Escape codes/sequences.

    However, grunt-contrib-uglify utlilizes uglify-js which provides options for mangling names. You can set the mangle values for both the toplevel and eval properties to true.

    Gruntfile.js

    The options in your uglify Task can be set as follows:

    // ...
    options: {
        beautify: true,
        mangle: {
            properties: true,
            toplevel: true, // <-- Add this
            eval: true  // <-- Add this
        }
    },
    // ...
    

    Note: When mangling names you need to be diligent to ensure your code still function as intended. There may be certain names that you don't want to be mangled (e.g. jQuery is quite a common one). An excerpt from the uglify-js documentation reads:

    When mangling is enabled but you want to prevent certain names from being mangled, you can declare those names with --mangle reserved — pass a comma-separated list of names...

    To exclude certain names from being mangled in your grunt uglify Task you can provide an Array of names using the reserved property:

    For example

    The following configuration mangles all names excluding operation and jQuery:

    // ...
    options: {
        beautify: true,
        mangle: {
            properties: true,
            toplevel: true,
            eval: true,
            reserved: ['operation', 'jQuery'] // Exclude mangling specific names.
        }
    },
    // ...