diff --git a/src/modules/utils/createOrderedSrc.js b/src/modules/utils/createOrderedSrc.js index 6df718f..dbfea1d 100644 --- a/src/modules/utils/createOrderedSrc.js +++ b/src/modules/utils/createOrderedSrc.js @@ -2,6 +2,24 @@ import {parseCode} from 'flast'; const largeNumber = 999e8; const sortByNodeId = (a, b) => a.nodeId > b.nodeId ? 1 : b.nodeId > a.nodeId ? -1 : 0; +const funcStartRegexp = new RegExp('function[^(]*'); + +/** + * Add a name to a FunctionExpression. + * @param {ASTNode} n The target node + * @param {string} [name] The new name. Defaults to 'func + n.nodeId'. + * @return {ASTNode} The new node with the name set + */ +function addNameToFE(n, name) { + name = name || 'func' + n.nodeId; + const funcSrc = '(' + n.src.replace(funcStartRegexp, 'function ' + name) + ');'; + const newNode = parseCode(funcSrc); + if (newNode) { + newNode.nodeId = n.nodeId; + newNode.src = funcSrc; + return newNode; + } +} /** * Return the source code of the ordered nodes. @@ -23,30 +41,13 @@ function createOrderedSrc(nodes, preserveOrder = false) { } } else if (n.callee.type === 'FunctionExpression') { if (!preserveOrder) { - const altFuncName = (n.parentNode.type === 'VariableDeclarator' ? n.parentNode.id.name : 'func' + n.nodeId); - const funcStartRegexp = new RegExp('function[^(]*'); - const funcSrc = n.callee?.id ? n.src : n.src.replace(funcStartRegexp, 'function ' + altFuncName); - const src = `(${funcSrc});`; - const newNode = parseCode(src); - if (newNode) { - newNode.nodeId = n.nodeId + largeNumber; - newNode.src = src; - nodes[i] = newNode; - } + const newNode = addNameToFE(n, n.parentNode?.id?.name); + newNode.nodeId = newNode.nodeId + largeNumber; + nodes[i] = newNode; } else nodes[i] = n; } - } else if (n.type === 'FunctionExpression' && !n.id) { - if (n.parentNode.type === 'VariableDeclarator') { - const funcStartRegexp = new RegExp('function[^(]*'); - const funcSrc = n.src.replace(funcStartRegexp, 'function ' + n.parentNode.id.name); - const src = `(${funcSrc});`; - const parsedNode = parseCode(src); - if (parsedNode) { - parsedNode.nodeId = n.nodeId; - parsedNode.src = src; - nodes[i] = parsedNode; - } - } + } else if (n.type === 'FunctionExpression' && !n.id) { + nodes[i] = addNameToFE(n, n.parentNode?.id?.name); } n = nodes[i]; // In case the node was replaced if (!parsedNodes.includes(n)) parsedNodes.push(n); diff --git a/src/modules/utils/logger.js b/src/modules/utils/logger.js deleted file mode 100644 index d169071..0000000 --- a/src/modules/utils/logger.js +++ /dev/null @@ -1,44 +0,0 @@ -/** - * Debugging helper - * Set the environment variable DEOBDEBUG='true' to print out debug messages and save output as file - * Default behavior is to suppress debug messages and output deobfuscated code to standard output - * Debug mode can also be enabled from the outer scope when this module is being imported - */ -const logLevels = { - DEBUG: 1, - LOG: 2, - ERROR: 3, - NONE: 9e10, -}; -let currentLogLevel = logLevels.NONE; - -function createLoggerForLevel(logLevel) { - if (!Object.values(logLevels).includes(logLevel)) throw new Error(`Unknown log level ${logLevel}.`); - return msg => logLevel >= currentLogLevel ? console.log(msg) : undefined; -} -const debug = createLoggerForLevel(logLevels.DEBUG); -const log = createLoggerForLevel(logLevels.LOG); -const error = createLoggerForLevel(logLevels.ERROR); - -/** - * Set the current log level - * @param {number} newLogLevel - */ -function setLogLevel(newLogLevel) { - if (!Object.values(logLevels).includes(newLogLevel)) throw new Error(`Unknown log level ${newLogLevel}.`); - currentLogLevel = newLogLevel; -} - -function isLogging() { - return currentLogLevel > 0; -} - -module.exports = { - currentLogLevel, - debug, - error, - isLogging, - log, - logLevels, - setLogLevel, -}; \ No newline at end of file diff --git a/src/processors/augmentedArray.js b/src/processors/augmentedArray.js index a17fa2a..346a325 100644 --- a/src/processors/augmentedArray.js +++ b/src/processors/augmentedArray.js @@ -63,5 +63,5 @@ function replaceArrayWithStaticAugmentedVersion(arb) { return arb; } -export const preprocessors = [replaceArrayWithStaticAugmentedVersion, resolveFunctionToArray]; +export const preprocessors = [replaceArrayWithStaticAugmentedVersion, resolveFunctionToArray.default]; export const postprocessors = []; \ No newline at end of file diff --git a/tests/modules.test.js b/tests/modules.test.js index 807bcb8..a52160f 100644 --- a/tests/modules.test.js +++ b/tests/modules.test.js @@ -1057,3 +1057,83 @@ describe('UTILS: createNewNode', async () => { }); }); +describe('UTILS: createOrderedSrc', async () => { + const targetModule = (await import('../src/modules/utils/createOrderedSrc.js')).createOrderedSrc; + it('TP-1: Re-order nodes', () => { + const code = 'a; b;'; + const expected = `a\nb\n`; + const ast = generateFlatAST(code); + const targetNodes = [ + 4, // b() + 2, // a() + ]; + const result = targetModule(targetNodes.map(n => ast[n])); + assert.deepStrictEqual(result, expected); + }); + it('TP-2: Wrap calls in expressions', () => { + const code = 'a();'; + const expected = `a();\n`; + const ast = generateFlatAST(code);const targetNodes = [ + 2, // a() + ]; + const result = targetModule(targetNodes.map(n => ast[n])); + assert.deepStrictEqual(result, expected); + }); + it('TP-3: Push IIFEs to the end in order', () => { + const code = '(function(a){})(); a(); (function(b){})(); b();'; + const expected = `a();\nb();\n(function(a){})();\n(function(b){})();\n`; + const ast = generateFlatAST(code); + const targetNodes = [ + 10, // (function(b){})() + 15, // b() + 7, // a() + 2, // (function(a){})() + ]; + const result = targetModule(targetNodes.map(n => ast[n])); + assert.deepStrictEqual(result, expected); + }); + it('TP-4: Add dynamic name to IIFEs', () => { + const code = '!function(a){}(); a();'; + const expected = `a();\n(function func3(a){}());\n`; + const ast = generateFlatAST(code);const targetNodes = [ + 3, // function(a){}() + 8, // a() + ]; + const result = targetModule(targetNodes.map(n => ast[n])); + assert.deepStrictEqual(result, expected); + }); + it('TP-5: Add variable name to IIFEs', () => { + const code = 'const b = function(a){}(); a();'; + const expected = `a();\n(function b(a){}());\n`; + const ast = generateFlatAST(code);const targetNodes = [ + 4, // function(a){}() + 9, // a() + ]; + const result = targetModule(targetNodes.map(n => ast[n])); + assert.deepStrictEqual(result, expected); + }); + it(`TP-6: Preserve node order`, () => { + const code = '(function(a){})(); a(); (function(b){})(); b();'; + const expected = `(function(a){})();\na();\n(function(b){})();\nb();\n`; + const ast = generateFlatAST(code); + const targetNodes = [ + 10, // (function(b){})() + 7, // a() + 15, // b() + 2, // (function(a){})() + ]; + const result = targetModule(targetNodes.map(n => ast[n]), true); + assert.deepStrictEqual(result, expected); + }); + it(`TP-7: Standalone FEs`, () => { + const code = '~function(iife1){}();~function(iife2){}();'; + const expected = `(function func4(iife1){});\n(function func10(iife2){});\n`; + const ast = generateFlatAST(code); + const targetNodes = [ + 10, // function(iife2){} + 4, // function(iife1){} + ]; + const result = targetModule(targetNodes.map(n => ast[n]), true); + assert.deepStrictEqual(result, expected); + }); +});