UNPKG

js-confuser

Version:

JavaScript Obfuscation Tool.

105 lines (89 loc) 3.13 kB
import { PluginArg, PluginObject } from "../plugin"; import { Order } from "../../order"; import { getRandomInteger } from "../../utils/random-utils"; import { HashFunction } from "../../templates/integrityTemplate"; import * as t from "@babel/types"; import Template from "../../templates/template"; import { NodePath } from "@babel/traverse"; export interface IntegrityInterface { fnPath: NodePath<t.FunctionDeclaration>; fnName: string; } export const INTEGRITY = Symbol("Integrity"); export interface NodeIntegrity { [INTEGRITY]?: IntegrityInterface; } /** * Integrity has two passes: * * - First in the 'lock' plugin to select functions and prepare them for Integrity * - Secondly here to apply the integrity check * * This transformation must run last as any changes to the code will break the hash */ export default ({ Plugin }: PluginArg): PluginObject => { const me = Plugin(Order.Integrity, { changeData: { functions: 0, }, }); return { visitor: { Program: { enter(path) { path.scope.crawl(); }, }, FunctionDeclaration: { exit(funcDecPath) { const integrityInterface = (funcDecPath.node as NodeIntegrity)[ INTEGRITY ]; if (!integrityInterface) return; const newFnPath = integrityInterface.fnPath; if (newFnPath.removed) return; const newFunctionDeclaration = newFnPath.node; if ( !newFunctionDeclaration || !t.isFunctionDeclaration(newFunctionDeclaration) ) return; const { integrityHashName: hashFnName } = me.globalState.internals; const obfuscatedHashFnName = me.obfuscator.getObfuscatedVariableName( hashFnName, funcDecPath.find((p) => p.isProgram()).node ); const newFnName = newFunctionDeclaration.id.name; const binding = newFnPath.scope.getBinding(newFnName); // Function is redefined, do not apply integrity if (!binding || binding.constantViolations.length > 0) return; var code = me.obfuscator.generateCode(newFunctionDeclaration); var codeTrimmed = code.replace( me.globalState.lock.integrity.sensitivityRegex, "" ); var seed = getRandomInteger(0, 10000000); var hashCode = HashFunction(codeTrimmed, seed); // me.log(codeTrimmed, hashCode); me.changeData.functions++; funcDecPath.node.body = t.blockStatement( new Template(` var hash = ${obfuscatedHashFnName}(${newFunctionDeclaration.id.name}, ${seed}); if(hash === ${hashCode}) { {originalBody} } else { {countermeasures} } `).compile({ originalBody: funcDecPath.node.body.body, countermeasures: () => me.globalState.lock.createCountermeasuresCode(), }), // Preserve directives funcDecPath.node.body.directives ); }, }, }, }; };