UNPKG

js-confuser

Version:

JavaScript Obfuscation Tool.

398 lines (349 loc) 12 kB
import Template from "./templates/template"; // JS-Confuser.com imports this file for Type support, therefore some additional types are included here. type Stringed<V> = V extends string ? V : never; /** * Configurable probabilities for obfuscator options. * - **`false`** = this feature is disabled * - **`true`** = this feature is enabled, use default mode * - **`0.5`** = 50% chance * - **`"mode"`** = enabled, use specified mode * - **`["mode1", "mode2"]`** - enabled, choose random mode each occurrence * - **`{"mode1": 0.5, "mode2": 0.5}`** - enabled, choose based on specified probabilities * - **`{"mode1": 50, "mode2": 50}`** - enabled, each is divided based on total * - **`function(x){ return "custom_implementation" }`** - enabled, use specified function */ export type ProbabilityMap< T = boolean, F extends (...args: any[]) => any = () => boolean // Default to a generic function > = | false | true | number | F | (T extends never | boolean ? { value: ProbabilityMap<never, F>; limit?: number; } : T | T[] | { [key in Stringed<T>]?: number }); export interface CustomLock { /** * Template lock code that must contain: * * - `{countermeasures}` * * The countermeasures function will be invoked when the lock is triggered. * * ```js * if(window.navigator.userAgent.includes('Chrome')){ * {countermeasures} * } * ``` * * Multiple templates can be passed a string array, a random one will be chosen each time. */ code: string | string[] | Template; percentagePerBlock: number; maxCount?: number; minCount?: number; } export interface CustomStringEncoding { /** * Template string decoder that must contain: * * - `{fnName}` * * This function will be invoked by the obfuscated code to DECODE the string. * * ```js * function {fnName}(str){ * return Buffer.from(str, 'base64').toString('utf-8') * } * ``` */ code?: string | Template; encode: (str: string) => string; /** * Optional. A decoder function can be provided to ensure the string is able to decode properly. * @param str * @returns */ decode?: (str: string) => string; /** * Should be used when created 'shuffled' variants of the same encoding. */ identity?: string; } export interface ObfuscateOptions { /** * The preset to use for obfuscation. */ preset?: "high" | "medium" | "low" | false; /** * The execution context for your output. _Required_. * * 1. `"node"` * 2. `"browser"` */ target: "node" | "browser"; /** * Remove's whitespace from the final output. */ compact?: boolean; /** * Uses the hexadecimal representation for numbers. */ hexadecimalNumbers?: boolean; /** * Minifies redundant code. */ minify?: boolean; /** * Renames labeled statements. Enabled by default. */ renameLabels?: ProbabilityMap<boolean, (labelName: string) => boolean>; /** * Determines if variables should be renamed. */ renameVariables?: ProbabilityMap< boolean, (variableName: string, topLevel: boolean) => boolean >; /** * Renames top-level variables, turn this off for web-related scripts. Enabled by default. */ renameGlobals?: ProbabilityMap<boolean, (variableName: string) => boolean>; /** * Determines how variables are renamed. * * JS-Confuser tries to reuse names when possible, creating very potent code. */ identifierGenerator?: ProbabilityMap< "hexadecimal" | "randomized" | "zeroWidth" | "mangled" | "number", () => string >; /** * ⚠️ Significantly impacts performance, use sparingly! * * Control-flow Flattening hinders program comprehension by creating convoluted switch statements. * * Use a number to control the percentage from 0 to 1. */ controlFlowFlattening?: ProbabilityMap<boolean>; /** * Global Concealing hides global variables being accessed. */ globalConcealing?: ProbabilityMap<boolean, (globalName: string) => boolean>; /** * String Compression uses zlib compression algorithm to compress strings. * * `"console"` -> `inflate('replaĕ!ğğuģģ<~@')` */ stringCompression?: ProbabilityMap<boolean, (strValue: string) => boolean>; /** * String Concealing involves encoding strings to conceal plain-text values. * * `"console"` -> `decrypt('<~@rH7+Dert~>')` */ stringConcealing?: ProbabilityMap<boolean, (strValue: string) => boolean>; /** * Custom String Encodings allows you to define your own string encoding/decoding functions. */ customStringEncodings?: ( | CustomStringEncoding | ((encodingImplementations: { [identity: string]: CustomStringEncoding; }) => CustomStringEncoding | null) )[]; /** * String Encoding transforms a string into an escaped unicode representation. * * `"console"` -> `'\x63\x6f\x6e\x73\x6f\x6c\x65'` */ stringEncoding?: ProbabilityMap<boolean, (strValue: string) => boolean>; /** * String Splitting splits your strings into multiple expressions. * * `"console"` -> `String.fromCharCode(99) + 'ons' + 'ole'` */ stringSplitting?: ProbabilityMap<boolean, (strValue: string) => boolean>; /** * Duplicate Literals Removal replaces duplicate literals with a single variable name. */ duplicateLiteralsRemoval?: ProbabilityMap<boolean>; /** * Creates a middleman function to process function calls. */ dispatcher?: ProbabilityMap<boolean, (fnName: string) => boolean>; /** * RGF (Runtime-Generated-Functions) uses the [`new Function(code...)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/Function) syntax to construct executable code from strings. * * - **This can break your code.** * - **Due to the security concerns of arbitrary code execution, you must enable this yourself.** * - The arbitrary code is also obfuscated. * * ```js * // Input * function log(x){ * console.log(x) * } * * log("Hello World") * * // Output * var C6z0jyO=[new Function('a2Fjjl',"function OqNW8x(OqNW8x){console['log'](OqNW8x)}return OqNW8x(...Array.prototype.slice.call(arguments,1))")];(function(){return C6z0jyO[0](C6z0jyO,...arguments)}('Hello World')) * ``` * */ rgf?: ProbabilityMap<boolean, (fnName: string, isGlobal: boolean) => boolean>; /** * Local variables are consolidated into a rotating array. * * [Similar to Jscrambler's Variable Masking](https://docs.jscrambler.com/code-integrity/documentation/transformations/variable-masking) * * ```js * // Input * function add3(x, y, z){ * return x + y + z; * } * * // Output * function iVQoGQD(...iVQoGQD){ * ~(iVQoGQD.length = 3, iVQoGQD[215] = iVQoGQD[2], iVQoGQD[75] = 227, iVQoGQD[iVQoGQD[75] - (iVQoGQD[75] - 75)] = iVQoGQD[75] - (iVQoGQD[75] - 239), iVQoGQD[iVQoGQD[iVQoGQD[75] - 164] - 127] = iVQoGQD[iVQoGQD[75] - 238], iVQoGQD[iVQoGQD[75] - 104] = iVQoGQD[75] - 482, iVQoGQD[iVQoGQD[135] + 378] = iVQoGQD[iVQoGQD[135] + 318] - 335, iVQoGQD[21] = iVQoGQD[iVQoGQD[135] + 96], iVQoGQD[iVQoGQD[iVQoGQD[75] - 104] - (iVQoGQD[75] - 502)] = iVQoGQD[iVQoGQD[75] - 164] - 440); * return iVQoGQD[75] > iVQoGQD[75] + 90 ? iVQoGQD[iVQoGQD[135] - (iVQoGQD[135] + 54)] : iVQoGQD[iVQoGQD[135] + 117] + iVQoGQD[iVQoGQD[iVQoGQD[75] - (iVQoGQD[75] - (iVQoGQD[75] - 104))] - (iVQoGQD[135] - 112)] + iVQoGQD[215]; * }; * ``` */ variableMasking?: ProbabilityMap<boolean, (fnName: string) => boolean>; /** * Extracts object properties into separate variables. * * ```js * // Input * var utils = { * isString: x=>typeof x === "string", * isBoolean: x=>typeof x === "boolean" * } * if ( utils.isString("Hello") ) { * // ... * } * * // Output * var utils_isString = x=>typeof x === "string"; * var utils_isBoolean = x=>typeof x === "boolean" * if ( utils_isString("Hello") ) { * // ... * } * ``` */ objectExtraction?: ProbabilityMap<boolean, (objectName: string) => boolean>; /** * Declares functions at the top of the program, preserving their original scope. */ flatten?: ProbabilityMap<boolean, (fnName: string) => boolean>; /** * Randomly injects dead code. * * Use a number to control the percentage from 0 to 1. */ deadCode?: ProbabilityMap<boolean>; /** * Creates a calculator function to handle arithmetic and logical expressions. * */ calculator?: ProbabilityMap<boolean>; lock?: { /** * Prevents the use of code beautifiers or formatters against your code. * * [Identical to Obfuscator.io's Self Defending](https://github.com/javascript-obfuscator/javascript-obfuscator#selfdefending) * */ selfDefending?: boolean; /** * Adds `debugger` statements throughout the code. */ antiDebug?: ProbabilityMap<boolean>; /** * Tamper Protection safeguards the runtime behavior from being altered by JavaScript pitfalls. * * **⚠️ Tamper Protection requires eval and ran in a non-strict mode environment!** * * - **This can break your code.** * - **Due to the security concerns of arbitrary code execution, you must enable this yourself.** * * @see https://github.com/MichaelXF/js-confuser/blob/master/TamperProtection.md */ tamperProtection?: boolean | ((varName: string) => boolean); /** * When the program is first able to be used. (`number` or `Date`) * * Number should be in milliseconds. */ startDate?: number | Date | false; /** * When the program is no longer able to be used. (`number` or `Date`) * * Number should be in milliseconds. */ endDate?: number | Date | false; /** * Array of regex strings that the `window.location.href` must follow. */ domainLock?: RegExp[] | string[] | false; /** * Integrity ensures the source code is unchanged. * * @see https://github.com/MichaelXF/js-confuser/blob/master/Integrity.md */ integrity?: ProbabilityMap<boolean, (fnName: string) => boolean>; /** * A custom callback function to invoke when a lock is triggered. (`string/false`) * * This could be due to an invalid domain, incorrect time, or code's integrity changed. * * If no countermeasures function is provided (`undefined` or `true`), the obfuscator falls back to crashing the process. * * If `countermeasures` is `false`, no crash will occur. * * @see https://github.com/MichaelXF/js-confuser/blob/master/Countermeasures.md */ countermeasures?: string | boolean; customLocks?: CustomLock[]; }; /** * Moves variable declarations to the top of the context. */ movedDeclarations?: ProbabilityMap<boolean>; /** * An [Opaque Predicate](https://en.wikipedia.org/wiki/Opaque_predicate) is a predicate(true/false) that is evaluated at runtime, this can confuse reverse engineers * understanding your code. */ opaquePredicates?: ProbabilityMap<boolean>; /** * Shuffles the initial order of arrays. The order is brought back to the original during runtime. (`"hash"/true/false/0-1`) */ shuffle?: ProbabilityMap<boolean>; /** * Modified functions will retain the correct `function.length` property. Enabled by default. */ preserveFunctionLength?: boolean; /** * Semantically changes the AST to bypass automated tools. */ astScrambler?: boolean; /** * Packs the output code into a single `Function()` call. * * Designed to escape strict mode constraints. */ pack?: ProbabilityMap<boolean, (globalName: string) => boolean>; /** * Set of global variables. *Optional*. */ globalVariables?: Set<string>; /** * Enable logs to view the obfuscator's state. */ verbose?: boolean; }