Skip to content

Commit

Permalink
Fix CLI (#123)
Browse files Browse the repository at this point in the history
* Move cli logic to bin/deobfuscate.js

* Adjust usage documentation

* 2.0.2
  • Loading branch information
BenBaryoPX authored Oct 23, 2024
1 parent a832a8f commit 6009a3e
Show file tree
Hide file tree
Showing 6 changed files with 63 additions and 46 deletions.
32 changes: 25 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,13 @@ For comments and suggestions feel free to open an issue or find me on Twitter -

## Installation
### npm
```bash
npm install restringer
```shell
npm install -g restringer
```

### Clone The Repo
Requires Node 16 or newer.
```bash
```shell
git clone [email protected]:PerimeterX/restringer.git
cd restringer
npm install
Expand All @@ -44,7 +44,6 @@ there's a need to apply specific deobfuscation methods in order to circumvent an
preventing the script from being deobfuscated.

### Command-Line Usage

```
Usage: restringer input_filename [-h] [-c] [-q | -v] [-m M] [-o [output_filename]]
Expand All @@ -55,16 +54,35 @@ optional arguments:
-h, --help Show this help message and exit.
-c, --clean Remove dead nodes from script after deobfuscation is complete (unsafe).
-q, --quiet Suppress output to stdout. Output result only to stdout if the -o option is not set.
Does not go with the -v option.
Does not go with the -v option.
-m, --max-iterations M Run at most M iterations
-v, --verbose Show more debug messages while deobfuscating. Does not go with the -q option.
-o, --output [output_filename] Write deobfuscated script to output_filename.
Use <input_filename>-deob.js if no filename is provided.
<input_filename>-deob.js is used if no filename is provided.
```
Examples:
- Print the deobfuscated script to stdout.
```shell
restringer [target-file.js]
```
- Save the deobfuscated script to output.js.
```shell
restringer [target-file.js] -o output.js
```
- Deobfuscate and print debug info.
```shell
restringer [target-file.js] -v
```
- Deobfuscate without printing anything but the deobfuscated output.
```shell
restringer [target-file.js] -q
```


### Use as a Module

```javascript
const {REstringer} = require('restringer');
import {REstringer} from 'restringer';

const restringer = new REstringer('"RE" + "stringer"');
if (restringer.deobfuscate()) {
Expand Down
30 changes: 30 additions & 0 deletions bin/deobfuscate.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#!/usr/bin/env node
import {REstringer} from '../src/restringer.js';
import {argsAreValid, parseArgs} from'../src/utils/parseArgs.js';

try {
const args = parseArgs(process.argv.slice(2));
if (argsAreValid(args)) {
const fs = await import('node:fs');
let content = fs.readFileSync(args.inputFilename, 'utf-8');
const startTime = Date.now();

const restringer = new REstringer(content);
if (args.quiet) restringer.logger.setLogLevelNone();
else if (args.verbose) restringer.logger.setLogLevelDebug();
restringer.logger.log(`[!] REstringer v${REstringer.__version__}`);
restringer.logger.log(`[!] Deobfuscating ${args.inputFilename}...`);
if (args.maxIterations) {
restringer.maxIterations.value = args.maxIterations;
restringer.logger.log(`[!] Running at most ${args.maxIterations} iterations`);
}
if (restringer.deobfuscate()) {
restringer.logger.log(`[+] Saved ${args.outputFilename}`);
restringer.logger.log(`[!] Deobfuscation took ${(Date.now() - startTime) / 1000} seconds.`);
if (args.outputToFile) fs.writeFileSync(args.outputFilename, restringer.script, {encoding: 'utf-8'});
else console.log(restringer.script);
} else restringer.logger.log(`[-] Nothing was deobfuscated ¯\\_(ツ)_/¯`);
}
} catch (e) {
console.error(`[-] Critical Error: ${e}`);
}
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
{
"name": "restringer",
"version": "2.0.1",
"version": "2.0.2",
"description": "Deobfuscate Javascript with emphasis on reconstructing strings",
"main": "index.js",
"type": "module",
"bin": {
"restringer": "./src/restringer.js"
"restringer": "./bin/deobfuscate.js"
},
"directories": {
"prepare": "husky install",
Expand Down
37 changes: 3 additions & 34 deletions src/restringer.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
#!/usr/bin/env node
import {fileURLToPath} from 'node:url';
import {logger, applyIteratively} from 'flast';
import {logger as flastLogger, applyIteratively} from 'flast';
import {processors} from './processors/index.js';
import {detectObfuscation} from 'obfuscation-detector';
import {config, safe as safeMod, unsafe as unsafeMod, utils} from './modules/index.js';
Expand All @@ -21,6 +20,7 @@ for (const funcName in unsafeMod) {

export class REstringer {
static __version__ = __version__;
logger = flastLogger;

/**
* @param {string} script The target script to be deobfuscated
Expand All @@ -33,7 +33,6 @@ export class REstringer {
this.obfuscationName = 'Generic';
this._preprocessors = [];
this._postprocessors = [];
this.logger = logger;
this.logger.setLogLevelLog();
this.maxIterations = config.defaultMaxIterations;
this.detectObfuscationType = true;
Expand Down Expand Up @@ -94,7 +93,7 @@ export class REstringer {
({preprocessors: this._preprocessors, postprocessors: this._postprocessors} = processors[detectedObfuscationType]);
}
}
logger.log(`[+] Obfuscation type is ${this.obfuscationName}`);
this.logger.log(`[+] Obfuscation type is ${this.obfuscationName}`);
return this.obfuscationName;
}

Expand Down Expand Up @@ -147,34 +146,4 @@ export class REstringer {
this.script = applyIteratively(this.script, [processor], 1);
}
}
}

if (process.argv[1] === fileURLToPath(import.meta.url)) {
const {argsAreValid, parseArgs} = await import('./utils/parseArgs.js');
try {
const args = parseArgs(process.argv.slice(2));
if (argsAreValid(args)) {
const fs = await import('node:fs');
let content = fs.readFileSync(args.inputFilename, 'utf-8');
const startTime = Date.now();

const restringer = new REstringer(content);
if (args.quiet) restringer.logger.setLogLevelNone();
else if (args.verbose) restringer.logger.setLogLevelDebug();
logger.log(`[!] REstringer v${REstringer.__version__}`);
logger.log(`[!] Deobfuscating ${args.inputFilename}...`);
if (args.maxIterations) {
restringer.maxIterations.value = args.maxIterations;
restringer.logger.log(`[!] Running at most ${args.maxIterations} iterations`);
}
if (restringer.deobfuscate()) {
logger.log(`[+] Saved ${args.outputFilename}`);
logger.log(`[!] Deobfuscation took ${(Date.now() - startTime) / 1000} seconds.`);
if (args.outputToFile) fs.writeFileSync(args.outputFilename, restringer.script, {encoding: 'utf-8'});
else console.log(restringer.script);
} else logger.log(`[-] Nothing was deobfuscated ¯\\_(ツ)_/¯`);
}
} catch (e) {
logger.error(`[-] Critical Error: ${e}`);
}
}
2 changes: 1 addition & 1 deletion src/utils/parseArgs.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ optional arguments:
-m, --max-iterations M Run at most M iterations
-v, --verbose Show more debug messages while deobfuscating. Does not go with the -q option.
-o, --output [output_filename] Write deobfuscated script to output_filename.
Use <input_filename>-deob.js if no filename is provided.`;
<input_filename>-deob.js is used if no filename is provided.`;
}

export function parseArgs(args) {
Expand Down

0 comments on commit 6009a3e

Please sign in to comment.