Code obfuscation in Electron Forge

ElectronJSJavaScriptEnglish

November 05, 2021

An ElectronJS app is very easy to reverse. As you may already know, JS code in Electron.js is just packaged in an .asar file, not binary compiled. So, It is easy to inspect and modify. By nature, it is always possible to reverse ingineer an application. With more or less easy way.

What is obfuscation?

First of all, obfuscation is not encryption. No need to decrypt anything, the code always works as is. Obfuscation is more slow down a reverse engineering attempt. The concept is simple to understand, we inject some dead code (code that does nothing) in order to mix it with the real code (your code). This way the person who will want to deobfuscate your project first needs to clean up the code. What to discourage more than one.

But we can go further. Encoding the strings is indispensable. In this way, the code is by default unreadable for a human. And requires additional processing.

To illustrate the concept, here a simple JavaScript code:

function hi() {
  console.log("Hello World!");
}
hi();

And the version after obfuscation:

(function(_0x5b511e,_0x5bf77d){var _0x397bb1=_0x4805,_0x4fd9e4=_0x5b511e();while(!![]){try{var _0xc88849=parseInt(_0x397bb1(0x104))/0x1+parseInt(_0x397bb1(0x108))/0x2+parseInt(_0x397bb1(0x105))/0x3+-parseInt(_0x397bb1(0x101))/0x4*(parseInt(_0x397bb1(0x100))/0x5)+parseInt(_0x397bb1(0x107))/0x6+parseInt(_0x397bb1(0x109))/0x7+-parseInt(_0x397bb1(0x102))/0x8;if(_0xc88849===_0x5bf77d)break;else _0x4fd9e4['push'](_0x4fd9e4['shift']());}catch(_0x51247a){_0x4fd9e4['push'](_0x4fd9e4['shift']());}}}(_0x328c,0xbede7));function _0x328c(){var _0x27e658=['1257035uiqqLn','221529rUGTPj','Hello\x20World!','7152360MVCehS','1368044nSNPpR','9700243nljpLt','5tUquDe','694092RcCghm','29099096xFIwyL','log'];_0x328c=function(){return _0x27e658;};return _0x328c();}function _0x4805(_0xf6ca69,_0x2361c7){var _0x328c21=_0x328c();return _0x4805=function(_0x4805b5,_0x138e44){_0x4805b5=_0x4805b5-0x100;var _0x41323e=_0x328c21[_0x4805b5];return _0x41323e;},_0x4805(_0xf6ca69,_0x2361c7);}function hi(){var _0x248ce9=_0x4805;console[_0x248ce9(0x103)](_0x248ce9(0x106));}hi();

It is the same code, with the same result. But more complex to read and modify.

How to implement it in Electron Forge

In this post, I show you how to setup obfuscation inside a clean electron forge project, with Webpack. So, It is not limited to Electron Forge and can be easily used inside another template. And also for vanilla or node JavaScript project.

A basic implementation is not hard to achieve. First, create a new Electron Forge project with the following command yarn create electron-app my-app --template=webpack.
Next, run yarn add javascript-obfuscator webpack-obfuscator -D to add dependencies.

Update your webpack.main.config.js as follow to obfuscate the main code (Electron side), only in production:

const Obfuscate = require('webpack-obfuscator');

const obfuscatePlugin = new Obfuscate({
  rotateUnicodeArray: true,
  deadCodeInjection: true
});

module.exports = {
  /**
   * This is the main entry point for your application, it's the first file
   * that runs in the main process.
   */
  entry: './src/main/main.js',
  // Put your normal webpack config below here
  module: {
    rules: require('./webpack.rules'),
  },
  plugins: [
    ...(process.env.NODE_ENV === 'production' ? [obfuscatePlugin] : [])
  ],
};

Now, we need to do the same for the rendering side, so your code executing inside Chromium. Update the webpack.plugins.js as follows or create it if it not exist:

const Obfuscate = require('webpack-obfuscator');

const obfuscatePlugin = new Obfuscate({
    rotateUnicodeArray: true,
    deadCodeInjection: true
});

module.exports = [
    ...(process.env.NODE_ENV === 'production' ? [obfuscatePlugin] : [])
];

And in webpack.renderer.config.js:

const rules = require('./webpack.rules');
const plugins = require('./webpack.plugins');

rules.push({
  test: /\.css$/,
  use: [{ loader: 'style-loader'  }, { loader: 'css-loader' }],
});

module.exports = {
  // Put your normal webpack config below here
  module: {
    rules,
  },
  plugins: plugins,
};

And voilà! You can run yarn make. Once your app has been built, open the .webpack folder and edit any .js file. You will see that your code is now obfuscate (Important to build in production BEFORE).