diff --git a/src/transforms/controlFlowFlattening/controlFlowFlattening.ts b/src/transforms/controlFlowFlattening/controlFlowFlattening.ts index 05b0d21..eca4bdb 100644 --- a/src/transforms/controlFlowFlattening/controlFlowFlattening.ts +++ b/src/transforms/controlFlowFlattening/controlFlowFlattening.ts @@ -47,6 +47,7 @@ import ChoiceFlowObfuscation from "./choiceFlowObfuscation"; import ControlFlowObfuscation from "./controlFlowObfuscation"; import ExpressionObfuscation from "./expressionObfuscation"; import SwitchCaseObfuscation from "./switchCaseObfuscation"; +import { isModuleSource } from "../string/stringConcealing"; var flattenStructures = new Set([ "IfStatement", @@ -226,6 +227,13 @@ export default class ControlFlowFlattening extends Transform { fnNames.delete(illegal); }); + var importDeclarations = []; + for (var stmt of body) { + if (stmt.type === "ImportDeclaration") { + importDeclarations.push(stmt); + } + } + var fraction = 0.9; if (body.length > 20) { fraction /= Math.max(1.2, body.length - 18); @@ -285,6 +293,7 @@ export default class ControlFlowFlattening extends Transform { if ( o.type == "Literal" && typeof o.value == "string" && + !isModuleSource(o, p) && !o.regex && Math.random() / (Object.keys(stringBank).length / 2 + 1) > 0.5 ) { @@ -318,7 +327,10 @@ export default class ControlFlowFlattening extends Transform { }; body.forEach((stmt, i) => { - if (functionDeclarations.has(stmt)) { + if ( + functionDeclarations.has(stmt) || + stmt.type === "ImportDeclaration" + ) { return; } @@ -1045,6 +1057,9 @@ export default class ControlFlowFlattening extends Transform { var discriminant = Template(`${stateVars.join("+")}`).single().expression; body.length = 0; + for (var importDeclaration of importDeclarations) { + body.push(importDeclaration); + } if (functionDeclarations.size) { functionDeclarations.forEach((x) => { diff --git a/test/transforms/controlFlowFlattening/controlFlowFlattening.test.ts b/test/transforms/controlFlowFlattening/controlFlowFlattening.test.ts index 98ced88..1b85912 100644 --- a/test/transforms/controlFlowFlattening/controlFlowFlattening.test.ts +++ b/test/transforms/controlFlowFlattening/controlFlowFlattening.test.ts @@ -672,3 +672,39 @@ test("Variant #20: Don't apply when functions are redefined", async () => { eval(output); expect(TEST_ARRAY).toStrictEqual([0, 0, 0]); }); + +// https://github.com/MichaelXF/js-confuser/issues/70 +test("Variant #21: Don't move Import Declarations", async () => { + var output = await JsConfuser( + ` + import {createHash} from "crypto"; + var inputString = "Hash this string"; + var hashed = createHash("sha256").update(inputString).digest("hex"); + TEST_OUTPUT = hashed; + `, + { + target: "node", + controlFlowFlattening: true, + } + ); + + // Ensure Control Flow FLattening was applied + expect(output).toContain("switch"); + + // Ensure the import declaration wasn't moved + expect(output.startsWith("import")).toStrictEqual(true); + + // Convert to runnable code + output = output.replace( + `import{createHash}from'crypto';`, + "const {createHash}=require('crypto');" + ); + + var TEST_OUTPUT = ""; + + eval(output); + + expect(TEST_OUTPUT).toStrictEqual( + "1cac63f39fd68d8c531f27b807610fb3d50f0fc3f186995767fb6316e7200a3e" + ); +});