js-confuser
Version:
JavaScript Obfuscation Tool.
644 lines (639 loc) • 20.2 kB
TypeScript
// Generated by dts-bundle-generator v9.5.1
import { GeneratorResult } from '@babel/generator';
import { NodePath, Visitor } from '@babel/traverse';
import * as babelTypes from '@babel/types';
import { File as File$1 } from '@babel/types';
declare class NameGen {
private identifierGenerator;
options: {
avoidReserved: boolean;
avoidObjectPrototype: boolean;
};
generatedNames: Set<string>;
notSafeForReuseNames: Set<string>;
private counter;
private zeroWidthGenerator;
constructor(identifierGenerator?: ObfuscateOptions["identifierGenerator"], options?: {
avoidReserved: boolean;
avoidObjectPrototype: boolean;
});
private attemptGenerate;
generate(isSafeForReuse?: boolean): string;
}
declare class PluginInstance {
pluginOptions: {
name?: string;
order?: number;
};
obfuscator: Obfuscator;
constructor(pluginOptions: {
name?: string;
order?: number;
}, obfuscator: Obfuscator);
changeData: {
[key: string]: number;
};
computeProbabilityMap: Obfuscator["computeProbabilityMap"];
get name(): string;
get order(): number;
get options(): ObfuscateOptions;
get globalState(): {
lock: {
integrity: {
sensitivityRegex: RegExp;
};
createCountermeasuresCode: () => babelTypes.Statement[];
};
renamedVariables: Map<babelTypes.Node, Map<string, string>>;
internals: {
nativeFunctionName: string;
integrityHashName: string;
invokeCountermeasuresFnName: string;
};
};
skip<T extends babelTypes.Node>(path: NodePath<T> | T | NodePath<T>[]): T;
/**
* Returns `true` if the given path has been skipped by this plugin.
*/
isSkipped(path: NodePath): boolean;
private setFunctionLengthName;
setFunctionLength(path: NodePath<babelTypes.Function>, originalLength: number): void;
/**
* Returns a random string.
*
* Used for creating temporary variables names, typically before RenameVariables has ran.
*
* These long temp names will be converted to short, mangled names by RenameVariables.
*/
getPlaceholder(suffix?: string): string;
/**
* Logs a message to the console, only if `verbose` is enabled.
* @param messages
*/
log(...messages: any[]): void;
/**
* Logs a warning to the console, only if `verbose` is enabled.
* @param messages
*/
warn(...messages: any[]): void;
/**
* Throws an error with the given message.
* @param messages
*/
error(...messages: any[]): never;
}
declare const FN_LENGTH: unique symbol;
declare const GEN_NODE: unique symbol;
declare const JsConfuser: {
obfuscate: typeof obfuscate;
obfuscateAST: typeof obfuscateAST;
obfuscateWithProfiler: typeof obfuscateWithProfiler;
Obfuscator: typeof Obfuscator;
presets: {
high: ObfuscateOptions;
medium: ObfuscateOptions;
low: ObfuscateOptions;
};
Template: typeof Template;
};
declare const MULTI_TRANSFORM: unique symbol;
declare const NO_REMOVE: unique symbol;
declare const NO_RENAME: unique symbol;
declare const PREDICTABLE: unique symbol;
declare const SKIP: unique symbol;
declare const UNSAFE: unique symbol;
declare const WITH_STATEMENT: unique symbol;
declare enum Order {
Preparation = 0,
ObjectExtraction = 1,
Flatten = 2,
Lock = 3,
RGF = 4,
Dispatcher = 6,
DeadCode = 8,
Calculator = 9,
GlobalConcealing = 12,
OpaquePredicates = 13,
StringSplitting = 16,
StringConcealing = 17,
VariableMasking = 20,
DuplicateLiteralsRemoval = 22,
ControlFlowFlattening = 24,
MovedDeclarations = 25,
RenameLabels = 27,
Minify = 28,
AstScrambler = 29,
RenameVariables = 30,
Finalizer = 35,
Pack = 36,
Integrity = 37
}
export declare class Obfuscator {
parentObfuscator?: Obfuscator;
plugins: {
plugin: PluginObject;
pluginInstance: PluginInstance;
}[];
options: ObfuscateOptions;
totalPossibleTransforms: number;
globalState: {
lock: {
integrity: {
sensitivityRegex: RegExp;
};
createCountermeasuresCode: () => babelTypes.Statement[];
};
renamedVariables: Map<babelTypes.Node, Map<string, string>>;
internals: {
nativeFunctionName: string;
integrityHashName: string;
invokeCountermeasuresFnName: string;
};
};
packInterface: PackInterface;
isInternalVariable(name: string): boolean;
shouldTransformNativeFunction(nameAndPropertyPath: string[]): boolean;
getObfuscatedVariableName(originalName: string, programNode: babelTypes.Node): string;
/**
* The main Name Generator for `Rename Variables`
*/
nameGen: NameGen;
constructor(userOptions: ObfuscateOptions, parentObfuscator?: Obfuscator);
index: number;
obfuscateAST(ast: babelTypes.File, options?: {
profiler?: ProfilerCallback;
}): babelTypes.File;
obfuscate(sourceCode: string): Promise<ObfuscationResult>;
getPlugin(order: Order): {
plugin: PluginObject;
pluginInstance: PluginInstance;
};
hasPlugin(order: Order): boolean;
/**
* Calls `Obfuscator.generateCode` with the current instance options
*/
generateCode<T extends babelTypes.Node = babelTypes.File>(ast: T): GeneratorResult;
/**
* Generates code from an AST using `@babel/generator`
*/
static generateCode<T extends babelTypes.Node = babelTypes.File>(ast: T, options?: ObfuscateOptions): GeneratorResult;
/**
* Parses the source code into an AST using `t.parseSync`
*/
static parseCode(sourceCode: string): babelTypes.File;
probabilityMapCounter: WeakMap<Object, number>;
/**
* Evaluates a ProbabilityMap.
* @param map The setting object.
* @param customFnArgs Args given to user-implemented function, such as a variable name.
*/
computeProbabilityMap<T, F extends (...args: any[]) => any = (...args: any[]) => any>(map: ProbabilityMap<T, F>, ...customImplementationArgs: F extends (...args: infer P) => any ? P : never): boolean | string;
/**
* Determines if a probability map can return a positive result (true, or some string mode).
* - Negative probability maps are used to remove transformations from running entirely.
* @param map
*/
isProbabilityMapProbable<T>(map: ProbabilityMap<T>): boolean;
}
export declare class Template {
private templates;
private defaultVariables;
private requiredVariables;
private astVariableMappings;
private astIdentifierPrefix;
private symbols;
constructor(...templates: string[]);
addSymbols(...symbols: NodeSymbolKeys[]): this;
setDefaultVariables(defaultVariables: TemplateVariables): this;
private findRequiredVariables;
private interpolateTemplate;
private isASTVariable;
private interpolateAST;
file(variables?: TemplateVariables): babelTypes.File;
compile(variables?: TemplateVariables): babelTypes.Statement[];
single<T extends babelTypes.Statement>(variables?: TemplateVariables): T;
expression<T extends babelTypes.Expression>(variables?: TemplateVariables): T;
}
/**
* Built-in obfuscator presets.
*/
export declare const presets: {
high: ObfuscateOptions;
medium: ObfuscateOptions;
low: ObfuscateOptions;
};
export declare function obfuscate(sourceCode: string, options: ObfuscateOptions): Promise<ObfuscationResult>;
export declare function obfuscateAST(ast: babelTypes.File, options: ObfuscateOptions): Promise<babelTypes.File>;
export declare function obfuscateWithProfiler(sourceCode: string, options: ObfuscateOptions, profiler?: {
callback?: ProfilerCallback;
performance?: {
now(): number;
};
}): Promise<ObfuscationResult & {
profileData: ProfileData;
}>;
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";
/**
* Removes 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" | "chinese", () => 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 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?: ProbabilityMap<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[];
/**
* The default 'maxCount' for obfuscator and custom locks. Defaults to 25.
*/
defaultMaxCount?: number;
};
/**
* 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>;
/**
* 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>;
/**
* Source map options
*/
sourceMap?: boolean | SourceMapOptions;
/**
* Enable logs to view the obfuscator's state.
*/
verbose?: boolean;
}
/**
* Obfuscation result object.
*/
export interface ObfuscationResult {
/**
* Obfuscated code.
*/
code: string;
map?: GeneratorResult["map"];
ast?: File$1;
}
/**
* Profile report for the obfuscation process.
*/
export interface ProfileData {
obfuscationTime: number;
compileTime: number;
parseTime: number;
totalPossibleTransforms: number;
totalTransforms: number;
transforms: {
[transformName: string]: {
transformTime: number;
changeData: PluginInstance["changeData"];
fileSize?: string;
};
};
}
/**
* The current progress of the obfuscation process.
*/
export interface ProfilerLog {
index: number;
currentTransform: string;
nextTransform: string;
totalTransforms: number;
}
/**
* 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> = false | true | number | F | (T extends never | boolean ? {
value: ProbabilityMap<never, F>;
limit?: number;
} : T | T[] | {
[key in Stringed<T>]?: number;
});
/**
* A callback function that is called when a transform is applied.
*/
export type ProfilerCallback = (log: ProfilerLog, transformEntry?: object, ast?: File$1) => void;
interface NodeSymbol {
[UNSAFE]?: boolean;
[PREDICTABLE]?: boolean;
[SKIP]?: boolean | number;
[FN_LENGTH]?: number;
[NO_RENAME]?: string | number;
[GEN_NODE]?: boolean;
[MULTI_TRANSFORM]?: boolean;
[WITH_STATEMENT]?: boolean;
[NO_REMOVE]?: boolean;
}
interface PackInterface {
objectName: string;
mappings: Map<string, string>;
setterPropsNeeded: Set<string>;
typeofMappings: Map<string, string>;
}
interface PluginObject {
visitor?: Visitor;
finalASTHandler?: (ast: babelTypes.File) => babelTypes.File;
post?: () => void;
}
interface SourceMapOptions {
/** Filename of the original source; appears in the map's `sources` array */
fileName?: string;
}
interface TemplateVariables {
[varName: string]: string | number | (() => babelTypes.Node | babelTypes.Node[] | Template) | babelTypes.Node | babelTypes.Node[] | Template;
}
type NodeSymbolKeys = keyof {
[K in keyof NodeSymbol as K extends symbol ? K : never]: NodeSymbol[K];
};
type Stringed<V> = V extends string ? V : never;
export {
JsConfuser as default,
};
export {};