Skip to content

Commit

Permalink
Merge pull request #14 from sleeyax/2.0
Browse files Browse the repository at this point in the history
  • Loading branch information
sleeyax authored Nov 2, 2021
2 parents 64315d5 + 964be22 commit 3c99137
Show file tree
Hide file tree
Showing 42 changed files with 38,360 additions and 622 deletions.
1 change: 1 addition & 0 deletions .github/FUNDING.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
patreon: sleeyax
21 changes: 21 additions & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
name: CI
on:
- push
- pull_request
jobs:
test:
name: Node.js ${{ matrix.node-version }}
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
node-version:
- 16
- 14
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v2
with:
node-version: ${{ matrix.node-version }}
- run: npm install
- run: npm test
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
.idea/
node_modules/
build/
mytests/
103 changes: 70 additions & 33 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,74 +6,111 @@ This is not bulletproof, but can be useful as a first level of protection.
`$ npm i asarmor`

## usage

### CLI
```
$ asarmor --help
Usage: asarmor [options]
Options:
-V, --version output the version number
-a, --archive <archive> input asar file (required)
-o, --output <output> output asar file (required)
-v, --verbose enable verbose console output
-b, --backup create backup
-r, --restore restore backup (protections aren't applied)
-f, --filetocrash <filename size...> corrupt specified file within the archive
-bl, --bloat [gigabytes] add huge random files to disk on extraction attempt
-t, --trashify [junkfiles...] add fake files to the archive
-h, --help display help for command
-V, --version output the version number
-a, --archive <archive> input asar file (required)
-o, --output <output> output asar file (required)
-b, --backup create backup
-r, --restore restore backup
-bl, --bloat [gigabytes] add huge random files to disk on extraction attempt
-t, --trashify [junkfiles...] add fake files to the archive
-h, --help display help for command
Examples:
$ asarmor -a app.asar -o asarmor.asar --filetocrash index_dummy.js
$ asarmor -a app.asar -o asarmor.asar --filetocrash index_dummy.js -999
$ asarmor -a app.asar -o asarmor.asar --bloat 1000
$ asarmor -a app.asar -o asarmor.asar --trashify bee-movie.txt foo.js bar.ts
$ asarmor -a app.asar -o asarmor.asar --trashify --backup
$ asarmor -a app.asar --restore
```

### library
```javascript
const {Asarmor, FileCrash, Trashify, Bloat} = require('asarmor');

const asarmor = new Asarmor('app.asar');
asarmor.createBackup('~/Documents/backups/app.asar.backup');
asarmor.applyProtection(new FileCrash('target.js', -999));
asarmor.applyProtection(new Trashify(['foo', 'bar'], Trashify.Randomizers.randomExtension(['js', 'ts', 'txt'])));
asarmor.applyProtection(new Trashify(['baz'], Trashify.Randomizers.junkExtension()));
asarmor.applyProtection(new Bloat(100)); // add 100 GB of bloat files to disk when someone tries to run 'asar extract'
asarmor.write('app.asar')
.then(outputPath => console.log(`successfully wrote changes to ${outputPath}`))
.catch(console.error);
const asarmor = require('asarmor');

(async () => {
// Read & parse the asar file.
// This can take a while depending on the size.
const archive = await asarmor.open('app.asar');

// Create a backup, which can be restored at any point in time through CLI or code.
archive.createBackup({backupPath: '~/Documents/backups/app.asar.backup'});

// Apply customized trash patch; this will make sure `asar extract` fails.
archive.patch(asarmor.createTrashPatch({
filenames: ['foo', 'bar'],
beforeWrite: (filename) => {
const extensions = ['js', 'ts', 'tsx', 'txt'];
const extension = extensions[Math.floor(Math.random() * extensions.length)];
return filename + '.' + extension;
}
}));

// Apply customized bloat patch; this will write randomness to disk on extraction attempt.
archive.patch(asarmor.createBloatPatch(50)); // adds 50 GB of bloat in total

// Write result back to file.
const outputPath = await archive.write('app.asar');
console.log('successfully wrote changes to ' + outputPath);
})();
```

#### advanced
```javascript
const asarmor = require('asarmor');

(async () => {
const archive = await asarmor.open('app.asar');

// Apply a fully customized patch.
// You can play around with the different values to see what works for you.
archive.patch({
header: {
files: {
'foo.js': {offset: 0, size: -999},
'bar.js': {offset: -123, size: 1337},
}
},
});

// Write result back to file.
await archive.write('protected.asar');
})();
```

### electron-builder
You can easily include asarmor in your packaging process using an [afterPack](https://www.electron.build/configuration/configuration.html#afterpack) hook:
```javascript
const { Asarmor, Trashify } = require('asarmor');
const asarmor = require('asarmor');
const { join } = require("path");

exports.default = async ({ appOutDir, packager }) => {
try {
const asarPath = join(packager.getResourcesDir(appOutDir), 'app.asar');
console.log(`applying asarmor protections to ${asarPath}`);
const asarmor = new Asarmor(asarPath);
asarmor.applyProtection(new Trashify(['.git', '.env']));
await asarmor.write(asarPath);
console.log(`applying asarmor patches to ${asarPath}`);
const archive = await asarmor.open(asarPath);
archive.patch(); // apply default patches
await archive.write(asarPath);
} catch (err) {
console.error(err);
}
};
```

### FAQ
### examples
See [examples](example) for detailed code examples.

## FAQ
**Do protections affect my (electron) app performance?**

Nope. Electron can still read your asar file at the same speed as if nothing changed.
The same should be true for other frameworks that utilise the asar format (unless the implementation differs drastically for some reason, which is out of my control).

**The 'filecrash' protection broke my app?**

Filecrash is the oldest protection and initial PoC for asarmor and should be avoided if you don't know what you're doing. It will *corrupt* specified file in the archive, so make sure the file you are targetting isn't a valid soure file (e.g. `index.js` or `main.js`) that your app depends on.

## support
Found a bug or have a question? [Open an issue](https://github.com/sleeyax/asarmor/issues) if it doesn't exist yet. Pull Requests are welcome, but please open an issue first if you're adding major changes!
6 changes: 6 additions & 0 deletions babel.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
module.exports = {
presets: [
['@babel/preset-env', { targets: { node: 'current' } }],
'@babel/preset-typescript',
],
};
48 changes: 22 additions & 26 deletions bin/asarmor.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
#!/usr/bin/env node
import { Command } from 'commander';
import { Asarmor, FileCrash } from '../src';
import Trashify from '../src/protections/trashify';
import Bloat from '../src/protections/bloat';
import {open, createBloatPatch, createTrashPatch} from '../src';
const { version } = require('../package.json');

const program = new Command();
Expand All @@ -11,17 +9,13 @@ program
.version(version)
.option('-a, --archive <archive>', 'input asar file (required)')
.option('-o, --output <output>', 'output asar file (required)')
.option('-v, --verbose', 'enable verbose console output')
.option('-b, --backup', 'create backup')
.option('-r, --restore', 'restore backup (protections aren\'t applied)')
.option('-f, --filetocrash <filename size...>', 'corrupt specified file within the archive')
.option('-r, --restore', 'restore backup')
.option('-bl, --bloat [gigabytes]', 'add huge random files to disk on extraction attempt')
.option('-t, --trashify [junkfiles...]', 'add fake files to the archive')
.on('--help', () => {
console.log('');
console.log('Examples:');
console.log(' $ asarmor -a app.asar -o asarmor.asar --filetocrash index_dummy.js');
console.log(' $ asarmor -a app.asar -o asarmor.asar --filetocrash index_dummy.js -999');
console.log(' $ asarmor -a app.asar -o asarmor.asar --bloat 1000');
console.log(' $ asarmor -a app.asar -o asarmor.asar --trashify bee-movie.txt foo.js bar.ts');
console.log(' $ asarmor -a app.asar -o asarmor.asar --trashify --backup');
Expand All @@ -34,23 +28,25 @@ if (!program.archive || !program.output) {
program.exit();
}

if (program.verbose) process.env.VERBOSE = 'true';

const asarmor = new Asarmor(program.archive);

if (program.restore) {
asarmor.restoreBackup();
async function main() {
const asarmor = await open(program.archive);

if (program.restore) {
asarmor.restoreBackup();
}
else if (program.output) {
if (program.backup)
asarmor.createBackup();

if (program.trashify)
asarmor.patch(createTrashPatch({
filenames: program.trashify === true ? undefined : program.trashify,
}));
if (program.bloat)
asarmor.patch(createBloatPatch(program.bloat === true ? undefined : program.bloat));

await asarmor.write(program.output);
}
}
else if (program.output) {
if (program.backup)
asarmor.createBackup();

if (program.filetocrash)
asarmor.applyProtection(new FileCrash(program.filetocrash[0], +program.filetocrash[1]));
if (program.trashify)
asarmor.applyProtection(new Trashify(program.trashify === true ? undefined : program.trashify));
if (program.bloat)
asarmor.applyProtection(new Bloat(program.bloat === true ? undefined : program.bloat));

asarmor.write(program.output).catch(console.error);
}
main();
7 changes: 7 additions & 0 deletions example/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# examples
This directory contains some examples to demonstrate how asarmor can be used in production.

Make sure you've built asarmor (run `npm run build` at project root) before you try them out!

- [Node.js](node)
- [Electron.js](electron)
6 changes: 6 additions & 0 deletions example/electron/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
.DS_Store
dist/
node_modules/
thumbs.db
.idea/
extracted/
20 changes: 20 additions & 0 deletions example/electron/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Electron.js example
This project is based on the [electron-webpack-quick-start](https://github.com/electron-userland/electron-webpack-quick-start) boilerplate.

## Installation
Install dependencies:

`$ npm i`

## Usage
Run the following command to build this project:
```
# create unpacked build with electron-builder
$ npm run dist:dir
```

An [afterPack](https://www.electron.build/configuration/configuration.html#afterpack) hook that applies asarmor patches is already included in the build step.

To verify that the electron app still runs fine, go to `dist/<os>-unpacked/` and run the `asarmor-electron-example` executable. For example on Windows the path to the executable should be `dist/win-unpacked/asarmor-electron-example.exe`.

Finally, try to run `asar extract dist/<os>-unpacked/resources/app.asar extracted` and notice that it won't work :)
14 changes: 14 additions & 0 deletions example/electron/afterPack.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
const asarmor = require('../../build/src');
const { join } = require("path");

exports.default = async ({ appOutDir, packager }) => {
try {
const asarPath = join(packager.getResourcesDir(appOutDir), 'app.asar');
console.log(`applying asarmor patches to ${asarPath}`);
const archive = await asarmor.open(asarPath);
archive.patch(); // apply default patches
await archive.write(asarPath);
} catch (err) {
console.error(err);
}
};
Loading

0 comments on commit 3c99137

Please sign in to comment.