Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

restringer

Package Overview
Dependencies
Maintainers
1
Versions
45
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

restringer - npm Package Compare versions

Comparing version 1.2.3 to 1.2.4

src/processors/proxiedAugArrFunc.js

2

package.json
{
"name": "restringer",
"version": "1.2.3",
"version": "1.2.4",
"description": "Deobfuscate Javascript with emphasis on reconstructing strings",

@@ -5,0 +5,0 @@ "main": "index.js",

@@ -14,5 +14,8 @@ # Restringer

* [Installation](#installation)
* [npm](#npm)
* [Clone The Repo](#clone-the-repo)
* [Usage](#usage)
* [Command-Line Usage](#command-line-usage)
* [Use as a Module](#use-as-a-module)
* [Create Custom Deobfuscators](#create-custom-deobfuscators)
* [Read More](#read-more)

@@ -22,2 +25,8 @@ ***

## Installation
### npm
```bash
npm install restringer
```
### Clone The Repo
Requires Node 16 or newer.

@@ -41,6 +50,6 @@ ```bash

```
Usage: restringer input_filename [-h] [-c] [-q|-v] [-o [output_filename]]
Usage: restringer input_filename [-h] [-c] [-q | -v] [-m M] [-o [output_filename]]
positional arguments:
input_filename The obfuscated JS file
input_filename The obfuscated JS file

@@ -52,2 +61,3 @@ optional arguments:

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.

@@ -72,3 +82,41 @@ -o, --output [output_filename] Write deobfuscated script to output_filename.

***
## Create Custom Deobfuscators
REstringer is highly modularized. It exposes modules that allow creating custom deobfuscators
that can solve specific problems.
The basic structure of such a deobfuscator would be an array of deobfuscation modules
(either [safe](src/modules/safe) or [unsafe](src/modules/unsafe)), run via the [runLoop](src/modules/utils/runLoop.js) util function.
Unsafe modules run code through `eval` (using [vm2](https://www.npmjs.com/package/vm2) to be on the safe side) while safe modules do not.
```javascript
const {
safe: {normalizeComputed},
unsafe: {resolveDefiniteBinaryExpressions, resolveLocalCalls}
} = require('restringer').modules;
let script = 'obfuscated JS here';
const deobModules = [
resolveDefiniteBinaryExpressions,
resolveLocalCalls,
normalizeComputed,
];
script = runLoop(script, deobModules);
console.log(script); // Deobfuscated script
```
With the additional `candidateFilter` function argument, it's possible to narrow down the targeted nodes:
```javascript
const {unsafe: {resolveLocalCalls}} = require('restringer').modules;
let script = 'obfuscated JS here';
// It's better to define a function with a name that can show up in the log (otherwise you'll get 'undefined')
function resolveLocalCallsInGlobalScope(arb) {
return resolveLocalCalls(arb, n => n.parentNode?.type === 'Program');
}
script = runLoop(script, [resolveLocalCallsInGlobalScope]);
console.log(script); // Deobfuscated script
```
***
## Read More

@@ -75,0 +123,0 @@ * [Processors](src/processors/README.md)

@@ -6,8 +6,10 @@ /**

* @param {Arborist} arb
* @param {Function} candidateFilter (optional) a filter to apply on the candidates list
* @return {Arborist}
*/
function consolidateNestedBlockStatements(arb) {
function consolidateNestedBlockStatements(arb, candidateFilter = () => true) {
const candidates = arb.ast.filter(n =>
n.type === 'BlockStatement' &&
n.parentNode.type === 'BlockStatement');
n.parentNode.type === 'BlockStatement' &&
candidateFilter(n));

@@ -14,0 +16,0 @@ for (const c of candidates) {

@@ -8,5 +8,6 @@ const {badIdentifierCharsRegex, validIdentifierBeginning} = require(__dirname + '/../config');

* @param {Arborist} arb
* @param {Function} candidateFilter (optional) a filter to apply on the candidates list
* @return {Arborist}
*/
function normalizeComputed(arb) {
function normalizeComputed(arb, candidateFilter = () => true) {
const candidates = arb.ast.filter(n =>

@@ -34,3 +35,4 @@ n.computed && // Filter for only member expressions using bracket notation

validIdentifierBeginning.test(n.key.value) &&
!badIdentifierCharsRegex.test(n.key.value)));
!badIdentifierCharsRegex.test(n.key.value)) &&
candidateFilter(n));

@@ -37,0 +39,0 @@ for (const c of candidates) {

/**
* Remove unrequired empty statements.
* @param {Arborist} arb
* @param {Function} candidateFilter (optional) a filter to apply on the candidates list
* @return {Arborist}
*/
function normalizeEmptyStatements(arb) {
const candidates = arb.ast.filter(n => n.type === 'EmptyStatement');
function normalizeEmptyStatements(arb, candidateFilter = () => true) {
const candidates = arb.ast.filter(n =>
n.type === 'EmptyStatement' &&
candidateFilter(n));

@@ -9,0 +12,0 @@ for (const c of candidates) {

@@ -7,8 +7,10 @@ const createNewNode = require(__dirname + '/../utils/createNewNode');

* @param {Arborist} arb
* @param {Function} candidateFilter (optional) a filter to apply on the candidates list
* @return {Arborist}
*/
function parseTemplateLiteralsIntoStringLiterals(arb) {
function parseTemplateLiteralsIntoStringLiterals(arb, candidateFilter = () => true) {
const candidates = arb.ast.filter(n =>
n.type === 'TemplateLiteral' &&
!n.expressions.find(exp => exp.type !== 'Literal'));
!n.expressions.find(exp => exp.type !== 'Literal') &&
candidateFilter(n));

@@ -15,0 +17,0 @@ for (const c of candidates) {

@@ -8,9 +8,11 @@ const getDescendants = require(__dirname + '/../utils/getDescendants');

* @param {Arborist} arb
* @param {Function} candidateFilter (optional) a filter to apply on the candidates list
* @return {Arborist}
*/
function rearrangeSwitches(arb) {
function rearrangeSwitches(arb, candidateFilter = () => true) {
const candidates = arb.ast.filter(n =>
n.type === 'SwitchStatement' &&
n.discriminant.type === 'Identifier' &&
n?.discriminant.declNode?.parentNode?.init?.type === 'Literal');
n?.discriminant.declNode?.parentNode?.init?.type === 'Literal' &&
candidateFilter(n));

@@ -17,0 +19,0 @@ for (const c of candidates) {

@@ -8,9 +8,11 @@ const relevantParents = ['VariableDeclarator', 'AssignmentExpression', 'FunctionDeclaration', 'ClassDeclaration'];

* @param {Arborist} arb
* @param {Function} candidateFilter (optional) a filter to apply on the candidates list
* @return {Arborist}
*/
function removeDeadNodes(arb) {
function removeDeadNodes(arb, candidateFilter = () => true) {
const candidates = arb.ast.filter(n =>
n.type === 'Identifier' &&
relevantParents.includes(n.parentNode.type) &&
(!n?.declNode?.references?.length && !n?.references?.length))
(!n?.declNode?.references?.length && !n?.references?.length) &&
candidateFilter(n))
.map(n => n.parentNode);

@@ -17,0 +19,0 @@

@@ -7,5 +7,6 @@ /**

* @param {Arborist} arb
* @param {Function} candidateFilter (optional) a filter to apply on the candidates list
* @return {Arborist}
*/
function replaceCallExpressionsWithUnwrappedIdentifier(arb) {
function replaceCallExpressionsWithUnwrappedIdentifier(arb, candidateFilter = () => true) {
const candidates = arb.ast.filter(n =>

@@ -17,3 +18,4 @@ n.type === 'CallExpression' &&

(n.callee.declNode.parentNode.type === 'FunctionDeclaration' &&
n.callee.declNode.parentKey === 'id')));
n.callee.declNode.parentKey === 'id')) &&
candidateFilter(n));

@@ -20,0 +22,0 @@ for (const c of candidates) {

@@ -12,5 +12,6 @@ const {generateFlatAST} = require('flast');

* @param {Arborist} arb
* @param {Function} candidateFilter (optional) a filter to apply on the candidates list
* @return {Arborist}
*/
function replaceEvalCallsWithLiteralContent(arb) {
function replaceEvalCallsWithLiteralContent(arb, candidateFilter = () => true) {
const cache = getCache(arb.ast[0].scriptHash);

@@ -20,3 +21,4 @@ const candidates = arb.ast.filter(n =>

n.callee?.name === 'eval' &&
n.arguments[0]?.type === 'Literal');
n.arguments[0]?.type === 'Literal' &&
candidateFilter(n));

@@ -23,0 +25,0 @@ for (const c of candidates) {

/**
* Functions which only return a single literal or identifier will have their references replaced with the actual return value.
* @param {Arborist} arb
* @param {Function} candidateFilter (optional) a filter to apply on the candidates list
* @return {Arborist}
*/
function replaceFunctionShellsWithWrappedValue(arb) {
function replaceFunctionShellsWithWrappedValue(arb, candidateFilter = () => true) {
const candidates = arb.ast.filter(n =>

@@ -11,3 +12,4 @@ n.type === 'FunctionDeclaration' &&

n.body.body[0].type === 'ReturnStatement' &&
['Literal', 'Identifier'].includes(n.body.body[0].argument?.type));
['Literal', 'Identifier'].includes(n.body.body[0].argument?.type) &&
candidateFilter(n));

@@ -14,0 +16,0 @@ for (const c of candidates) {

/**
* Functions which only return a single literal or identifier will have their references replaced with the actual return value.
* @param {Arborist} arb
* @param {Function} candidateFilter (optional) a filter to apply on the candidates list
* @return {Arborist}
*/
function replaceFunctionShellsWithWrappedValueIIFE(arb) {
function replaceFunctionShellsWithWrappedValueIIFE(arb, candidateFilter = () => true) {
const candidates = arb.ast.filter(n =>

@@ -13,3 +14,4 @@ n.type === 'FunctionExpression' &&

n.body.body[0].type === 'ReturnStatement' &&
['Literal', 'Identifier'].includes(n.body.body[0].argument?.type))
['Literal', 'Identifier'].includes(n.body.body[0].argument?.type) &&
candidateFilter(n))
.map(n => n.parentNode);

@@ -16,0 +18,0 @@

@@ -6,8 +6,10 @@ const areReferencesModified = require(__dirname + '/../utils/areReferencesModified');

* @param {Arborist} arb
* @param {Function} candidateFilter (optional) a filter to apply on the candidates list
* @return {Arborist}
*/
function replaceIdentifierWithFixedAssignedValue(arb) {
function replaceIdentifierWithFixedAssignedValue(arb, candidateFilter = () => true) {
const candidates = arb.ast.filter(n =>
n?.declNode?.parentNode?.init?.type === 'Literal' &&
!(n.parentKey === 'property' && n.parentNode.type === 'ObjectExpression'));
!(n.parentKey === 'property' && n.parentNode.type === 'ObjectExpression') &&
candidateFilter(n));

@@ -14,0 +16,0 @@ for (const c of candidates) {

@@ -8,5 +8,6 @@ const areReferencesModified = require(__dirname + '/../utils/areReferencesModified');

* @param {Arborist} arb
* @param {Function} candidateFilter (optional) a filter to apply on the candidates list
* @return {Arborist}
*/
function replaceIdentifierWithFixedValueNotAssignedAtDeclaration(arb) {
function replaceIdentifierWithFixedValueNotAssignedAtDeclaration(arb, candidateFilter = () => true) {
const candidates = arb.ast.filter(n =>

@@ -28,3 +29,4 @@ n.parentNode?.type === 'VariableDeclarator' &&

r.parentNode.parentNode?.parentNode?.parentNode?.type,
].includes('ConditionalExpression')));
].includes('ConditionalExpression')) &&
candidateFilter(n));

@@ -31,0 +33,0 @@ for (const c of candidates) {

@@ -8,8 +8,10 @@ /**

* @param {Arborist} arb
* @param {Function} candidateFilter (optional) a filter to apply on the candidates list
* @return {Arborist}
*/
function resolveDeterministicIfStatements(arb) {
function resolveDeterministicIfStatements(arb, candidateFilter = () => true) {
const candidates = arb.ast.filter(n =>
n.type === 'IfStatement' &&
n.test.type === 'Literal');
n.test.type === 'Literal' &&
candidateFilter(n));

@@ -16,0 +18,0 @@ for (const c of candidates) {

@@ -7,5 +7,6 @@ const {generateFlatAST} = require('flast');

* @param {Arborist} arb
* @param {Function} candidateFilter (optional) a filter to apply on the candidates list
* @return {Arborist}
*/
function resolveFunctionConstructorCalls(arb) {
function resolveFunctionConstructorCalls(arb, candidateFilter = () => true) {
const candidates = arb.ast.filter(n =>

@@ -15,3 +16,5 @@ n.type === 'CallExpression' &&

(n.callee.property?.name || n.callee.property?.value) === 'constructor' &&
n.arguments.length && n.arguments.slice(-1)[0].type === 'Literal');
n.arguments.length && n.arguments.slice(-1)[0].type === 'Literal' &&
candidateFilter(n));
for (const c of candidates) {

@@ -18,0 +21,0 @@ let args = '';

@@ -12,5 +12,6 @@ const logger = require(__dirname + '/../utils/logger');

* @param {Arborist} arb
* @param {Function} candidateFilter (optional) a filter to apply on the candidates list
* @return {Arborist}
*/
function resolveMemberExpressionReferencesToArrayIndex(arb) {
function resolveMemberExpressionReferencesToArrayIndex(arb, candidateFilter = () => true) {
const candidates = arb.ast.filter(n =>

@@ -20,3 +21,4 @@ n.type === 'VariableDeclarator' &&

n.id?.references &&
n.init.elements.length > minArrayLength);
n.init.elements.length > minArrayLength &&
candidateFilter(n));

@@ -23,0 +25,0 @@ for (const c of candidates) {

@@ -9,5 +9,6 @@ /**

* @param {Arborist} arb
* @param {Function} candidateFilter (optional) a filter to apply on the candidates list
* @return {Arborist}
*/
function resolveMemberExpressionsWithDirectAssignment(arb) {
function resolveMemberExpressionsWithDirectAssignment(arb, candidateFilter = () => true) {
const candidates = arb.ast.filter(n =>

@@ -17,3 +18,4 @@ n.type === 'MemberExpression' &&

n.parentNode.type === 'AssignmentExpression' &&
n.parentNode.right.type === 'Literal');
n.parentNode.right.type === 'Literal' &&
candidateFilter(n));

@@ -20,0 +22,0 @@ for (const c of candidates) {

@@ -15,5 +15,6 @@ /**

* @param {Arborist} arb
* @param {Function} candidateFilter (optional) a filter to apply on the candidates list
* @return {Arborist}
*/
function resolveProxyCalls(arb) {
function resolveProxyCalls(arb, candidateFilter = () => true) {
const candidates = arb.ast.filter(n =>

@@ -25,3 +26,4 @@ n.type === 'FunctionDeclaration' &&

n.body.body[0].argument.arguments.length === n.params.length &&
n.body.body[0].argument.callee.type === 'Identifier');
n.body.body[0].argument.callee.type === 'Identifier' &&
candidateFilter(n));

@@ -28,0 +30,0 @@ for (const c of candidates) {

@@ -12,5 +12,6 @@ const getDescendants = require(__dirname + '/../utils/getDescendants');

* @param {Arborist} arb
* @param {Function} candidateFilter (optional) a filter to apply on the candidates list
* @return {Arborist}
*/
function resolveProxyReferences(arb) {
function resolveProxyReferences(arb, candidateFilter = () => true) {
const candidates = arb.ast.filter(n =>

@@ -20,3 +21,4 @@ (n.type === 'VariableDeclarator' &&

['Identifier', 'MemberExpression'].includes(n.init?.type)) &&
!/For.*Statement/.test(n.parentNode?.parentNode?.type));
!/For.*Statement/.test(n.parentNode?.parentNode?.type) &&
candidateFilter(n));

@@ -23,0 +25,0 @@ for (const c of candidates) {

@@ -9,8 +9,12 @@ const areReferencesModified = require(__dirname + '/../utils/areReferencesModified');

* @param {Arborist} arb
* @param {Function} candidateFilter (optional) a filter to apply on the candidates list
* @return {Arborist}
*/
function resolveProxyVariables(arb) {
const candidates = [...new Set(arb.ast.filter(n =>
n.type === 'VariableDeclarator' &&
n?.init?.type === 'Identifier'))];
function resolveProxyVariables(arb, candidateFilter = () => true) {
const candidates = [
...new Set(arb.ast.filter(n =>
n.type === 'VariableDeclarator' &&
n?.init?.type === 'Identifier' &&
candidateFilter(n)))
];

@@ -17,0 +21,0 @@ for (const c of candidates) {

@@ -7,8 +7,10 @@ /**

* @param {Arborist} arb
* @param {Function} candidateFilter (optional) a filter to apply on the candidates list
* @return {Arborist}
*/
function resolveRedundantLogicalExpressions(arb) {
function resolveRedundantLogicalExpressions(arb, candidateFilter = () => true) {
const candidates = arb.ast.filter(n =>
n.type === 'IfStatement' &&
n.test.type === 'LogicalExpression');
n.test.type === 'LogicalExpression' &&
candidateFilter(n));

@@ -15,0 +17,0 @@ for (const c of candidates) {

@@ -11,5 +11,6 @@ /**

* @param {Arborist} arb
* @param {Function} candidateFilter (optional) a filter to apply on the candidates list
* @return {Arborist}
*/
function unwrapFunctionShells(arb) {
function unwrapFunctionShells(arb, candidateFilter = () => true) {
const candidates = arb.ast.filter(n =>

@@ -21,3 +22,4 @@ ['FunctionDeclaration', 'FunctionExpression'].includes(n.type) &&

n.body.body[0].argument.arguments?.length === 2 &&
n.body.body[0].argument.callee.object.type === 'FunctionExpression');
n.body.body[0].argument.callee.object.type === 'FunctionExpression' &&
candidateFilter(n));

@@ -24,0 +26,0 @@ for (const c of candidates) {

@@ -10,9 +10,11 @@ const evalInVm = require(__dirname + '/evalInVm');

* @param {Arborist} arb
* @param {Function} candidateFilter (optional) a filter to apply on the candidates list
* @return {Arborist}
*/
function normalizeRedundantNotOperator(arb) {
function normalizeRedundantNotOperator(arb, candidateFilter = () => true) {
const candidates = arb.ast.filter(n =>
n.operator === '!' &&
n.type === 'UnaryExpression' &&
relevantNodeTypes.includes(n.argument.type));
relevantNodeTypes.includes(n.argument.type) &&
candidateFilter(n));

@@ -19,0 +21,0 @@ for (const c of candidates) {

@@ -10,7 +10,9 @@ const evalInVm = require(__dirname + '/evalInVm');

* @param {Arborist} arb
* @param {Function} candidateFilter (optional) a filter to apply on the candidates list
* @return {Arborist}
*/
function resolveAugmentedFunctionWrappedArrayReplacements(arb) {
function resolveAugmentedFunctionWrappedArrayReplacements(arb, candidateFilter = () => true) {
const candidates = arb.ast.filter(n =>
n.type === 'FunctionDeclaration' && n.id);
n.type === 'FunctionDeclaration' && n.id &&
candidateFilter(n));

@@ -17,0 +19,0 @@ for (const c of candidates) {

@@ -11,9 +11,11 @@ const evalInVm = require(__dirname + '/evalInVm');

* @param {Arborist} arb
* @param {Function} candidateFilter (optional) a filter to apply on the candidates list
* @return {Arborist}
*/
function resolveBuiltinCalls(arb) {
function resolveBuiltinCalls(arb, candidateFilter = () => true) {
const availableSafeImplementations = Object.keys(safeImplementations);
const callsWithOnlyLiteralArugments = arb.ast.filter(n =>
n.type === 'CallExpression' &&
!n.arguments.find(a => a.type !== 'Literal'));
!n.arguments.find(a => a.type !== 'Literal') &&
candidateFilter(n));

@@ -20,0 +22,0 @@ const candidates = callsWithOnlyLiteralArugments.filter(n =>

@@ -11,8 +11,10 @@ const evalInVm = require(__dirname + '/evalInVm');

* @param {Arborist} arb
* @param {Function} candidateFilter (optional) a filter to apply on the candidates list
* @return {Arborist}
*/
function resolveDefiniteBinaryExpressions(arb) {
function resolveDefiniteBinaryExpressions(arb, candidateFilter = () => true) {
const candidates = arb.ast.filter(n =>
n.type === 'BinaryExpression' &&
doesBinaryExpressionContainOnlyLiterals(n));
doesBinaryExpressionContainOnlyLiterals(n) &&
candidateFilter(n));

@@ -19,0 +21,0 @@ for (const c of candidates) {

@@ -10,5 +10,6 @@ const evalInVm = require(__dirname + '/evalInVm');

* @param {Arborist} arb
* @param {Function} candidateFilter (optional) a filter to apply on the candidates list
* @return {Arborist}
*/
function resolveDefiniteMemberExpressions(arb) {
function resolveDefiniteMemberExpressions(arb, candidateFilter = () => true) {
const candidates = arb.ast.filter(n =>

@@ -21,3 +22,4 @@ n.type === 'MemberExpression' &&

['ArrayExpression', 'Literal'].includes(n.object.type) &&
(n.object?.value?.length || n.object?.elements?.length));
(n.object?.value?.length || n.object?.elements?.length) &&
candidateFilter(n));

@@ -24,0 +26,0 @@ for (const c of candidates) {

@@ -8,8 +8,10 @@ const evalInVm = require(__dirname + '/evalInVm');

* @param {Arborist} arb
* @param {Function} candidateFilter (optional) a filter to apply on the candidates list
* @return {Arborist}
*/
function resolveDeterministicConditionalExpressions(arb) {
function resolveDeterministicConditionalExpressions(arb, candidateFilter = () => true) {
const candidates = arb.ast.filter(n =>
n.type === 'ConditionalExpression' &&
n.test.type === 'Literal');
n.test.type === 'Literal' &&
candidateFilter(n));

@@ -16,0 +18,0 @@ for (const c of candidates) {

@@ -10,5 +10,6 @@ const {parseCode} = require('flast');

* @param {Arborist} arb
* @param {Function} candidateFilter (optional) a filter to apply on the candidates list
* @return {Arborist}
*/
function resolveEvalCallsOnNonLiterals(arb) {
function resolveEvalCallsOnNonLiterals(arb, candidateFilter = () => true) {
const candidates = arb.ast.filter(n =>

@@ -18,3 +19,4 @@ n.type === 'CallExpression' &&

n.arguments.length === 1 &&
n.arguments[0].type !== 'Literal');
n.arguments[0].type !== 'Literal' &&
candidateFilter(n));

@@ -21,0 +23,0 @@ for (const c of candidates) {

@@ -12,5 +12,6 @@ const evalInVm = require(__dirname + '/evalInVm');

* @param {Arborist} arb
* @param {Function} candidateFilter (optional) a filter to apply on the candidates list
* @return {Arborist}
*/
function resolveInjectedPrototypeMethodCalls(arb) {
function resolveInjectedPrototypeMethodCalls(arb, candidateFilter = () => true) {
const candidates = arb.ast.filter(n =>

@@ -21,3 +22,4 @@ n.type === 'AssignmentExpression' &&

n.operator === '=' &&
(/FunctionExpression|Identifier/.test(n.right?.type)));
(/FunctionExpression|Identifier/.test(n.right?.type)) &&
candidateFilter(n));

@@ -24,0 +26,0 @@ for (const c of candidates) {

@@ -13,5 +13,6 @@ const evalInVm = require(__dirname + '/evalInVm');

* @param {Arborist} arb
* @param {Function} candidateFilter (optional) a filter to apply on the candidates list
* @return {Arborist}
*/
function resolveLocalCalls(arb) {
function resolveLocalCalls(arb, candidateFilter = () => true) {
const cache = getCache(arb.ast[0].scriptHash);

@@ -23,3 +24,4 @@ const candidates = arb.ast.filter(n =>

!skipProperties.includes(n.callee.property?.value || n.callee.property?.name)) ||
n.callee?.object?.type === 'Literal'));
n.callee?.object?.type === 'Literal') &&
candidateFilter(n));

@@ -26,0 +28,0 @@ const frequency = {};

@@ -19,9 +19,11 @@ const evalInVm = require(__dirname + '/evalInVm');

* @param {Arborist} arb
* @param {Function} candidateFilter (optional) a filter to apply on the candidates list
* @return {Arborist}
*/
function resolveMemberExpressionsLocalReferences(arb) {
function resolveMemberExpressionsLocalReferences(arb, candidateFilter = () => true) {
const candidates = arb.ast.filter(n =>
n.type === 'MemberExpression' &&
['Identifier', 'Literal'].includes(n.property.type) &&
!skipProperties.includes(n.property?.name || n.property?.value));
!skipProperties.includes(n.property?.name || n.property?.value) &&
candidateFilter(n));

@@ -28,0 +30,0 @@ for (const c of candidates) {

@@ -10,5 +10,6 @@ const evalInVm = require(__dirname + '/evalInVm');

* @param {Arborist} arb
* @param {Function} candidateFilter (optional) a filter to apply on the candidates list
* @return {Arborist}
*/
function resolveMinimalAlphabet(arb) {
function resolveMinimalAlphabet(arb, candidateFilter = () => true) {
const candidates = arb.ast.filter(n =>

@@ -21,3 +22,4 @@ (n.type === 'UnaryExpression' &&

(n.left.type !== 'MemberExpression' && Number.isNaN(parseFloat(n.left?.value))) &&
![n.left?.type, n.right?.type].includes('ThisExpression')));
![n.left?.type, n.right?.type].includes('ThisExpression')) &&
candidateFilter(n));

@@ -24,0 +26,0 @@ for (const c of candidates) {

@@ -30,3 +30,3 @@ const {Arborist} = require('flast');

let arborist = new Arborist(script, logger.log);
while (arborist.ast.length && scriptSnapshot !== script && currentIteration < maxIterations && !hasGlobalMaxIterationBeenReached()) {
while (arborist.ast?.length && scriptSnapshot !== script && currentIteration < maxIterations && !hasGlobalMaxIterationBeenReached()) {
const cycleStartTime = Date.now();

@@ -40,3 +40,3 @@ scriptSnapshot = script;

arborist = func(arborist);
if (!arborist.ast.length) break;
if (!arborist.ast?.length) break;
// If the hash doesn't exist it means the Arborist was replaced

@@ -62,3 +62,3 @@ const numberOfNewChanges = arborist.getNumberOfChanges() + +!arborist.ast[0].scriptHash;

logger.log(`[+] ==> Cycle ${globalIterationsCounter} completed in ${(Date.now() - cycleStartTime) / 1000} seconds` +
` with ${changesCounter ? changesCounter : 'no'} changes (${arborist.ast.length} nodes)`);
` with ${changesCounter ? changesCounter : 'no'} changes (${arborist.ast?.length || '???'} nodes)`);
}

@@ -65,0 +65,0 @@ if (changesCounter) script = arborist.script;

@@ -11,3 +11,3 @@ /**

'augmented_array_function_replacements': () => require(__dirname + '/augmentedArray.js'),
'proxied_augmented_array_function_replacements': () => require(__dirname + '/augmentedArray.js'),
'augmented_proxied_array_function_replacements': () => require(__dirname + '/augmentedArray.js'),
};

@@ -198,4 +198,3 @@ #!/usr/bin/env node

}
restringer.deobfuscate();
if (restringer.modified) {
if (restringer.deobfuscate()) {
logger.log(`[+] Saved ${args.outputFilename}`);

@@ -202,0 +201,0 @@ logger.log(`[!] Deobfuscation took ${(Date.now() - startTime) / 1000} seconds.`);

@@ -5,6 +5,6 @@ function printHelp() {

Usage: restringer input_filename [-h] [-c] [-q|-v] [-m M] [-o [output_filename]]
Usage: restringer input_filename [-h] [-c] [-q | -v] [-m M] [-o [output_filename]]
positional arguments:
input_filename The obfuscated JS file
input_filename The obfuscated JS file

@@ -11,0 +11,0 @@ optional arguments:

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc