js-confuser
Version:
JavaScript Obfuscation Tool.
398 lines (349 loc) • 12 kB
text/typescript
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;
}