Skip to main content

Overview

The transform scripts use jscodeshift to perform Abstract Syntax Tree (AST) transformations on obfuscated JavaScript code. The transformation pipeline consists of 11 sequential transforms that progressively deobfuscate and refactor the code.

Transform Pipeline

All transforms are chained together in refactor-obfuscated-code-jscodeshift-chained.js and executed sequentially:
ast = new Void0Transformer(0, ast, output, outputBaseName).transform();
ast = new UnaryExpressionTransformer(1, ast, output, outputBaseName).transform();
ast = new RefactorVariableTransformer(2, ast, output, outputBaseName).transform();
ast = new VariableReplacementTransformer(3, ast, output, outputBaseName).transform();
ast = new ParameterRefactorTransformer(4, ast, output, outputBaseName).transform();
ast = new FunctionRefactorTransformer(5, ast, output, outputBaseName).transform();
ast = new RemoveKeywordsTransformer(6, ast, output, outputBaseName).transform();
ast = new BracketToDotNotationTransformer(7, ast, output, outputBaseName).transform();
ast = new RemovedUnusedParametersTransformer(8, ast, output, outputBaseName).transform();
ast = new RemovedClosestTransformer(9, ast, output, outputBaseName).transform();
ast = new RemoveStaleIdentifierTransformer(10, ast, output, outputBaseName).transform();

Base Transformer Class

All transformers extend the AstTransformer base class:
mitmproxy/src/javascript/refactor-obfuscated-code-jscodeshift-common.js
class AstTransformer {
    constructor(stepNumber, jscodeshiftAst, output, outputBaseName) {
        this.stepNumber = stepNumber;
        this.jscodeshiftAst = jscodeshiftAst;
        this.output = output;
        this.outputBaseName = outputBaseName;
    }

    performTransform() {
        throw new Error("implement");
    }

    transform() {
        this.performTransform();
        if (this.output) {
            this.outputToFile();
        }
        return this.jscodeshiftAst;
    }
}
stepNumber
number
required
The sequential step number in the transformation pipeline
jscodeshiftAst
Collection
required
The jscodeshift AST collection to transform
output
boolean
required
Whether to write intermediate output files for debugging
outputBaseName
string
Base name for output files (defaults to deobfuscated-output)

Transform Stages

Converts void 0 expressions to undefined literals.Location: mitmproxy/src/javascript/refactor-obfuscated-code-jscodeshift-0.js:10
// Before
var a = void 0;

// After
var a = undefined;
Implementation:
this.jscodeshiftAst.find(j.UnaryExpression, {operator: 'void', argument: {value: 0}})
    .replaceWith(path => j.identifier('undefined'));
Simplifies unary expressions like !0 and !1 to boolean literals.Location: mitmproxy/src/javascript/refactor-obfuscated-code-jscodeshift-1.js:13
// Before
var flag = !0;
var disabled = !1;

// After
var flag = true;
var disabled = false;
Operators:
  • !0true
  • !1false
Renames obfuscated variable names to meaningful identifiers based on a 288-entry mapping.Location: mitmproxy/src/javascript/refactor-obfuscated-code-jscodeshift-2.js:296Key variable mappings:
  • _0x588211globalState
  • _0x478891tape
  • _0x4951e9functions
  • _0x38dc1bmodules
  • _0xfe71f0globalStateWriteIndex
  • _0x551c19globalStateReadIndex1
  • _0x20e93aglobalStateReadIndex2
// Before
var _0x588211 = [];

// After
var globalState = [];
Replaces and removes redundant variable declarations.Location: mitmproxy/src/javascript/refactor-obfuscated-code-jscodeshift-3.js:13Replacements:
  • _0x49b7bfglobalStateContextValues
  • _0x173146window
Also removes self-assignments like x = x.
Renames function parameters to meaningful names, with scope-aware renaming.Location: mitmproxy/src/javascript/refactor-obfuscated-code-jscodeshift-4.js:45Key parameter mappings:
  • _0x343255tapeBase64
  • _0x58916abase64Tape
  • _0x2a2310globalStateContexts
  • _0x2461da['keywordArray', 'keywordArray', 'index'] (scope-specific)
Supports scope-aware renaming where the same obfuscated parameter name can be renamed differently based on the function scope.
Renames obfuscated function names to descriptive identifiers.Location: mitmproxy/src/javascript/refactor-obfuscated-code-jscodeshift-5.js:19Function mappings:
  • _0x21f1e2getModule
  • _0x2facc3bootstrapModule
  • _0x50286dinitialiseState
  • _0x68e20aexecuteFunctionAtExecutionIndex
  • _0x4fdfceexecuteFunction
  • _0x50ee92base64ToBytes
  • _0x5953e4createPaddedBinaryString
Removes keyword array lookup operations that are no longer needed after deobfuscation.Location: mitmproxy/src/javascript/refactor-obfuscated-code-jscodeshift-6.jsThis transform cleans up artifact references to the obfuscated keyword lookup system.
Converts bracket notation to dot notation for common property access.Location: mitmproxy/src/javascript/refactor-obfuscated-code-jscodeshift-7.js:12
// Before
array['push'](item);
obj['length'];

// After
array.push(item);
obj.length;
Converted properties: push, shift, code, length, call, exports, charCodeAt, fromCharCode, toString, charAt, substr, indexOf, pow, pop, apply, slice, from, repeat, bind, prototype, and more.
Removes unused function parameters identified during analysis.Location: mitmproxy/src/javascript/refactor-obfuscated-code-jscodeshift-8.jsCleans up parameters marked as unused in the refactoring process.
Removes unnecessary closest selector patterns or wrapper functions.Location: mitmproxy/src/javascript/refactor-obfuscated-code-jscodeshift-9.js
Final cleanup pass to remove any remaining stale or unused identifiers.Location: mitmproxy/src/javascript/refactor-obfuscated-code-jscodeshift-10.js

Usage

Running the Transform Pipeline

node mitmproxy/src/javascript/refactor-obfuscated-code-jscodeshift.js \
  mitmproxy/src/javascript/obfuscated-original.js \
  mitmproxy/src/javascript/deobfuscated-output.js
input
string
required
Path to the obfuscated JavaScript file
output
string
required
Path where deobfuscated output will be written
outputIntermediateSteps
boolean
default:"true"
Whether to output intermediate files after each transform step

Development Workflow

For continuous development with automatic recompilation:
watchexec -e js "touch mitmproxy/src/python/download-payload.py && \
node mitmproxy/src/javascript/refactor-obfuscated-code-jscodeshift.js \
mitmproxy/src/javascript/obfuscated-original.js \
mitmproxy/src/javascript/deobfuscated-output.js && \
node mitmproxy/src/javascript/pre-transform-code.js"
This watches for changes in any .js files and automatically reruns the transformation pipeline.

Output Files

When outputIntermediateSteps is enabled, each transformer generates a separate output file:
  • deobfuscated-output-0.js - After Void0Transformer
  • deobfuscated-output-1.js - After UnaryExpressionTransformer
  • deobfuscated-output-2.js - After RefactorVariableTransformer
  • … and so on through step 10
Intermediate output files are useful for debugging transformation issues. You can inspect the AST state at each stage to identify where unexpected transformations occur.

AST Visualization

For developing new transforms or debugging issues, use AST Explorer to visualize and test transformations interactively.

Code Generation

The final AST is converted back to JavaScript using:
  1. jscodeshift - Converts the AST collection to source code
  2. esprima - Parses the source into a standard ESTree AST
  3. escodegen - Generates formatted JavaScript code
const ast = esprima.parseScript(transformedJscodeshiftAst.toSource());
const refactoredJsCode = escodegen.generate(ast);

Build docs developers (and LLMs) love