asarmor

repository·master·Indexed 43 days ago

https://github.com/sleeyax/asarmor

A security utility for Electron applications designed to protect .asar archive files from extraction and reverse engineering. Version 3.0.2 provides protection through patching and JavaScript file encryption, offering a CLI and a library API for integration into build pipelines like electron-builder and electron-forge.

Tokens
8K
Snippets
32
Records
36
Agent score
54%

What's inside asarmor

  1. What is asarmor

    master

    asarmor is a tool designed to protect Electron .asar files from being extracted using the standard asar extract command. It provides layers of protection to make reverse engineering more difficult.

    Note that the protection strategies provided are not bulletproof and should be considered a first level of defense rather than absolute security.

  2. How asarmor protection strategies work

    master

    asarmor uses two primary methods to protect your application files:

    1. Patches: Applies modifications to the .asar file to make extraction challenging without affecting the application's functionality. However, many traditional patching methods have been mitigated by the asar project itself.
    2. Encryption: Encrypts all JavaScript files within the .asar archive. This method is highly recommended in conjunction with patching. A key advantage is that it requires no Electron recompilation.

    For maximum effectiveness, it is strongly recommended to enable both patching and encryption.

  3. Integrate asarmor with electron-builder

    master

    To protect your Electron application using electron-builder, you must use afterPack and beforePack hooks to encrypt the ASAR and include the required native .node files.

    Steps:

    1. Update afterPack.js: Use asarmor.encrypt and asarmor.open().patch() to secure the app.asar.
    2. Create beforePack.js: Copy main.node and renderer.node from the asarmor build directory to your project's release folder.
    3. Update package.json:
      • Set afterPack and beforePack hooks.
      • Change the main entrypoint from .js to the path of main.node.
    4. Configure BrowserWindow:
      • nodeIntegration MUST be true.
      • contextIsolation MUST be false.
      • Preload scripts are NOT supported.
    5. Bootstrap the Render Process: Use executeJavaScript to require the native .node and the renderer .js files.
    6. Main Process Entrypoint: Export a default function that accepts a Uint8Array decryption key to bootstrap the application.
    // Example afterPack.js logic
    const asarPath = join(packager.getResourcesDir(appOutDir), 'app.asar');
    const archive = await asarmor.open(asarPath);
    archive.patch();
    await archive.write(asarPath);
  4. Integrate asarmor with electron-forge

    master

    For electron-forge (specifically Vite + TypeScript setups), use the packageAfterCopy and postPackage hooks.

    Steps:

    1. Update forge.config.ts hooks:
      • packageAfterCopy: Copy main.node and renderer.node from asarmor's release folder to your build directory.
      • postPackage: Encrypt the app.asar and apply patches.
    2. Update package.json: Change main entrypoint to point to the .node file (e.g., .vite/build/main.node).
    3. Vite Configuration (Optional): If using Vite, it is recommended to disable chunk splitting for renderer assets to ensure correct bootstrapping.
    4. Configure BrowserWindow:
      • nodeIntegration MUST be true.
      • contextIsolation MUST be false.
      • Preload scripts are NOT supported.
    5. Bootstrap the Render Process: Use executeJavaScript to require the native renderer.node and your renderer asset (e.g., ./assets/index.js).
    6. Main Process Entrypoint: Export a default function accepting a Uint8Array decryption key to initialize the app.
    // Example postPackage hook in forge.config.ts
    postPackage: async (forgeConfig, buildPath) => {
      const asarPath = `${buildPath.outputPaths[0]}/resources/app.asar`;
      await asarmor.encrypt({ src: asarPath, dst: asarPath });
      const archive = await asarmor.open(asarPath);
      archive.patch();
      await archive.write(asarPath);
    }
  5. Run the Node.js asarmor example

    master

    To use the Node.js example project, install the dependencies and then run the build and test commands. The build process generates both the 'original' and the 'protected' asar archives. The test suite verifies that the protected archive prevents extraction while still allowing calls to its exported functions.

    # Install dependencies
    $ npm i
    
    # Build both 'original' and 'protected' asar archives
    $ npm run build
    
    # Verify that the protected archive can't be extracted, but still allows calls to exported functions within
    $ npm test
  6. Build asarmor before running examples

    master

    Before attempting to run any of the provided examples (Node.js or Electron.js), you must first build the asarmor project from the repository root to ensure the necessary binaries and assets are available.

    npm run build
  7. Integrate asarmor with Electron Forge via hooks

    master

    To use asarmor in an Electron Forge project, you must use the hooks configuration to handle native dependency copying and the encryption/patching process.

    1. packageAfterCopy: Use this hook to copy the native asarmor binaries (main.node and renderer.node) from your node_modules into the build directory. This ensures the native modules are available in the packaged application.
    2. postPackage: Use this hook to perform the security operations. This involves calling asarmor.encrypt to encrypt JavaScript files within the .asar archive and using asarmor.open followed by .patch() and .write() to apply security patches to the archive.
    const config: ForgeConfig = {
      // ... other config
      hooks: {
        packageAfterCopy: async (forgeConfig, buildPath) => {
          const release = join(__dirname, 'node_modules', 'asarmor', 'build', 'Release');
          // Copy main.node
          await copyFile(
            join(release, 'main.node'),
            join(buildPath, '.vite', 'build', 'main.node')
          );
          // Copy renderer.node
          await copyFile(
            join(release, 'renderer.node'),
            join(buildPath, '.vite', 'renderer', 'main_window', 'renderer.node')
          );
        },
        postPackage: async (forgeConfig, buildPath) => {
          const asarPath = `${buildPath.outputPaths[0]}/resources/app.asar`;
          
          // Encrypt JS files in the ASAR
          await asarmor.encrypt({
            src: asarPath,
            dst: asarPath,
          });
    
          // Apply patches to the ASAR
          const archive = await asarmor.open(asarPath);
          archive.patch();
          await archive.write(asarPath);
        },
      },
    };
  8. Report bugs or request features in asarmor

    master
    If you encounter a bug or have questions regarding asarmor, you should open an issue on the GitHub repository. If you intend to contribute major changes via a Pull Request, it is recommended to open an issue first to discuss the proposed changes.