JavaScript Obfuscator 是一款功能强大的免费 JavaScript 混淆器,包含多种功能,可为您的源代码提供保护。
主要特征:
- 变量重命名
- 字符串提取和加密
- 死代码注入
- 控制流扁平化
- 各种代码转换
- 还有更多...
插件:
- Webpack plugin: webpack-obfuscator
- Webpack loader: obfuscator-loader
- Gulp: gulp-javascript-obfuscator
- Grunt: grunt-contrib-obfuscator
- Rollup: rollup-plugin-javascript-obfuscator
- Weex: weex-devtool
- Malta: malta-js-obfuscator
在线版本:
⚠️ 注意
仅仅混淆属于您的代码。
不建议混淆第三方库文件,因为混淆后的代码要慢 15-80%(取决于怎么配置),而且文件要大得多。
安装
npm install javascript-obfuscator -g
使用
混淆单个文件
javascript-obfuscator input_file.js
执行后,会生成input_file_obfuscated.js
批量混淆
-
javascript-obfuscator ./ --output ./
:采用递归的方式混淆当前目录下的所有js文件(包括子文件),对原文件进行修改,不会生成新的js文件 -
javascript-obfuscator ./
:采用递归的方式混淆当前目录下的所有js文件(包括子文件),对原文件进行拷贝,会生成新的js文件,在新的js文件中进行修改。
--ouput a.js
:指定输出文件名
--ouput ./output
:指定输出目录
效果
原始js文件:
var welcome = function(name) {
return `welcome${name}`;
}
console.log(welcome("aa"));
console.log(welcome("bb"));
混淆后的文件
var a0_0x26ed16=a0_0x10fd;(function(_0x1442b9,_0x22b0d4){var _0x2d7fdd=a0_0x10fd,_0x1f1760=_0x1442b9();while(!![]){try{var _0x2dd2e5=-parseInt(_0x2d7fdd(0x91))/0x1+parseInt(_0x2d7fdd(0x8f))/0x2+parseInt(_0x2d7fdd(0x8b))/0x3+parseInt(_0x2d7fdd(0x8a))/0x4+parseInt(_0x2d7fdd(0x8d))/0x5+-parseInt(_0x2d7fdd(0x8c))/0x6*(-parseInt(_0x2d7fdd(0x90))/0x7)+-parseInt(_0x2d7fdd(0x8e))/0x8;if(_0x2dd2e5===_0x22b0d4)break;else _0x1f1760['push'](_0x1f1760['shift']());}catch(_0x45972f){_0x1f1760['push'](_0x1f1760['shift']());}}}(a0_0x37ea,0x40f71));var welcome=function(_0x1adb13){var _0x4b4afe=a0_0x10fd;return _0x4b4afe(0x93)+_0x1adb13;};function a0_0x10fd(_0x2e5e0a,_0x2b7804){var _0x37ea85=a0_0x37ea();return a0_0x10fd=function(_0x10fd94,_0x491768){_0x10fd94=_0x10fd94-0x8a;var _0x2a25f6=_0x37ea85[_0x10fd94];return _0x2a25f6;},a0_0x10fd(_0x2e5e0a,_0x2b7804);}function a0_0x37ea(){var _0x4d028c=['1619632VlYCof','20745QJxTYh','246654sbQVxA','1290425RuLxuv','4184280NHKkFh','532838XbZkeu','49APPhdD','434958kZhPSm','log','welcome'];a0_0x37ea=function(){return _0x4d028c;};return a0_0x37ea();}console[a0_0x26ed16(0x92)](welcome('aa')),console['log'](welcome('bb'));
JavaScript Obfuscator Options
如果不适用默认的混淆配置,需要在项目根目录中创建 javascript-obfuscator 的配置文件 obfuscator.config.json
,再根据自己的需要去衡量设置
下面是混淆的配置项:
配置:
{
compact: true,
controlFlowFlattening: false,
controlFlowFlatteningThreshold: 0.75,
deadCodeInjection: false,
deadCodeInjectionThreshold: 0.4,
debugProtection: false,
debugProtectionInterval: 0,
disableConsoleOutput: false,
domainLock: [],
domainLockRedirectUrl: 'about:blank',
forceTransformStrings: [],
identifierNamesCache: null,
identifierNamesGenerator: 'hexadecimal',
identifiersDictionary: [],
identifiersPrefix: '',
ignoreImports: false,
inputFileName: '',
log: false,
numbersToExpressions: false,
optionsPreset: 'default',
renameGlobals: false,
renameProperties: false,
renamePropertiesMode: 'safe',
reservedNames: [],
reservedStrings: [],
seed: 0,
selfDefending: false,
simplify: true,
sourceMap: false,
sourceMapBaseUrl: '',
sourceMapFileName: '',
sourceMapMode: 'separate',
sourceMapSourcesMode: 'sources-content',
splitStrings: false,
splitStringsChunkLength: 10,
stringArray: true,
stringArrayCallsTransform: true,
stringArrayCallsTransformThreshold: 0.5,
stringArrayEncoding: [],
stringArrayIndexesType: [
'hexadecimal-number'
],
stringArrayIndexShift: true,
stringArrayRotate: true,
stringArrayShuffle: true,
stringArrayWrappersCount: 1,
stringArrayWrappersChainedCalls: true,
stringArrayWrappersParametersMaxCount: 2,
stringArrayWrappersType: 'variable',
stringArrayThreshold: 0.75,
target: 'browser',
transformObjectKeys: false,
unicodeEscapeSequence: false
}
CLI 配置:
-v, --version
-h, --help
-o, --output
--compact <boolean>
--config <string>
--control-flow-flattening <boolean>
--control-flow-flattening-threshold <number>
--dead-code-injection <boolean>
--dead-code-injection-threshold <number>
--debug-protection <boolean>
--debug-protection-interval <boolean>
--disable-console-output <boolean>
--domain-lock '<list>' (comma separated)
--exclude '<list>' (comma separated)
--identifier-names-generator <string> [dictionary, hexadecimal, mangled, mangled-shuffled]
--identifiers-dictionary '<list>' (comma separated)
--identifiers-prefix <string>
--log <boolean>
--numbers-to-expressions <boolean>
--options-preset <string> [default, low-obfuscation, medium-obfuscation, high-obfuscation]
--rename-globals <boolean>
--rename-properties <boolean>
--reserved-names '<list>' (comma separated)
--reserved-strings '<list>' (comma separated)
--rotate-string-array <boolean>
--seed <string|number>
--self-defending <boolean>
--shuffle-string-array <boolean>
--simplify <boolean>
--source-map <boolean>
--source-map-base-url <string>
--source-map-file-name <string>
--source-map-mode <string> [inline, separate]
--split-strings <boolean>
--split-strings-chunk-length <number>
--string-array <boolean>
--string-array-encoding '<list>' (comma separated) [none, base64, rc4]
--string-array-threshold <number>
--target <string> [browser, browser-no-eval, node]
--transform-object-keys <boolean>
--unicode-escape-sequence <boolean>
compact
类型:boolean
默认值:true
压缩代码输出在一行。
config
类型:string
默认值:``
包含模糊处理程序选项的JS/JSON配置文件的名称。这些选项将被直接传递给CLI的选项覆盖
controlFlowFlattening
类型:boolean
默认:false
⚠️ 此选项极大地影响性能,运行时速度降低1.5倍。使用controlFlowFlatteningThreshold
设置将受控制流展平影响的节点的百分比。
启用代码控制流展平。控制流扁平化是源代码的一种结构转换,它阻碍了程序的理解。
Example:
// input
(function(){
function foo () {
return function () {
var sum = 1 + 2;
console.log(1);
console.log(2);
console.log(3);
console.log(4);
console.log(5);
console.log(6);
}
}
foo()();
})();
// output
(function () {
function _0x3bfc5c() {
return function () {
var _0x3260a5 = {
'WtABe': '4|0|6|5|3|2|1',
'GokKo': function _0xf87260(_0x427a8e, _0x43354c) {
return _0x427a8e + _0x43354c;
}
};
var _0x1ad4d6 = _0x3260a5['WtABe']['split']('|'), _0x1a7b12 = 0x0;
while (!![]) {
switch (_0x1ad4d6[_0x1a7b12++]) {
case '0':
console['log'](0x1);
continue;
case '1':
console['log'](0x6);
continue;
case '2':
console['log'](0x5);
continue;
case '3':
console['log'](0x4);
continue;
case '4':
var _0x1f2f2f = _0x3260a5['GokKo'](0x1, 0x2);
continue;
case '5':
console['log'](0x3);
continue;
case '6':
console['log'](0x2);
continue;
}
break;
}
};
}
_0x3bfc5c()();
}());
controlFlowFlatteningThreshold
类型:number
默认值:0.75
最小值:0
最大值:1
controlFlowFlattening
转换将应用于任何给定节点的概率。
此设置对于较大的代码量特别有用,因为大量的控制流转换会降低代码速度并增加代码大小。
controlFlowFlatteningThreshold: 0
等于controlFlowFlattening: false
。
deadCodeInjection
类型:boolean
默认:false
⚠️ 大大增加了模糊代码的大小(最多200%),只有在混淆代码的大小无关紧要时才使用。使用deadCodeInjectionThreshold
设置将受死代码注入影响的节点的百分比。
⚠️ 此选项强制启用stringArray
选项。
使用这个选项,随机的死代码块将被添加到模糊代码中。
Example:
// input
(function(){
if (true) {
var foo = function () {
console.log('abc');
console.log('cde');
console.log('efg');
console.log('hij');
};
var bar = function () {
console.log('klm');
console.log('nop');
console.log('qrs');
};
var baz = function () {
console.log('tuv');
console.log('wxy');
console.log('z');
};
foo();
bar();
baz();
}
})();
// output
var _0x5024 = [ 'zaU', 'log', 'tuv', 'wxy', 'abc', 'cde', 'efg', 'hij', 'QhG', 'TeI', 'klm', 'nop', 'qrs', 'bZd', 'HMx'];
var _0x4502 = function (_0x1254b1, _0x583689) {
_0x1254b1 = _0x1254b1 - 0x0;
var _0x529b49 = _0x5024[_0x1254b1];
return _0x529b49;
};
(function () {
if (!![]) {
var _0x16c18d = function () {
if (_0x4502('0x0') !== _0x4502('0x0')) {
console[_0x4502('0x1')](_0x4502('0x2'));
console[_0x4502('0x1')](_0x4502('0x3'));
console[_0x4502('0x1')]('z');
} else {
console[_0x4502('0x1')](_0x4502('0x4'));
console[_0x4502('0x1')](_0x4502('0x5'));
console[_0x4502('0x1')](_0x4502('0x6'));
console[_0x4502('0x1')](_0x4502('0x7'));
}
};
var _0x1f7292 = function () {
if (_0x4502('0x8') === _0x4502('0x9')) {
console[_0x4502('0x1')](_0x4502('0xa'));
console[_0x4502('0x1')](_0x4502('0xb'));
console[_0x4502('0x1')](_0x4502('0xc'));
} else {
console[_0x4502('0x1')](_0x4502('0xa'));
console[_0x4502('0x1')](_0x4502('0xb'));
console[_0x4502('0x1')](_0x4502('0xc'));
}
};
var _0x33b212 = function () {
if (_0x4502('0xd') !== _0x4502('0xe')) {
console[_0x4502('0x1')](_0x4502('0x2'));
console[_0x4502('0x1')](_0x4502('0x3'));
console[_0x4502('0x1')]('z');
} else {
console[_0x4502('0x1')](_0x4502('0x4'));
console[_0x4502('0x1')](_0x4502('0x5'));
console[_0x4502('0x1')](_0x4502('0x6'));
console[_0x4502('0x1')](_0x4502('0x7'));
}
};
_0x16c18d();
_0x1f7292();
_0x33b212();
}
}());
deadCodeInjectionThreshold
类型:number
默认值:0.4
最小值:0
最大值:1
允许设置受deadCodeInjection
影响的节点的百分比。
debugProtection
类型:boolean
默认:false
⚠️ 如果打开开发人员工具,可以冻结浏览器。
这个选项使得几乎不可能使用开发人员工具的debugger
函数(在WebKit-based和Mozilla Firefox上)。
debugProtectionInterval
类型:boolean
默认:false
⚠️ 可以冻结你的浏览器!使用风险自负。
如果选中,则使用一个间隔来强制Console选项卡上的debug模式,这使得使用开发人员工具的其他功能更加困难。如果启用debugProtection
,则有效。
disableConsoleOutput
类型:boolean
默认:false
通过将console.log
、console.info
、console.error
、console.warn
、console.debug
、console.exception
和console.trace
替换为空函数来禁用它们。这使得调试器的使用更加困难。
domainLock
类型:string[]
默认:[]
⚠️ 此选项不适用于target: 'node'
只允许在特定域和/或sub-domains上运行模糊处理的源代码。这使得人们很难复制并粘贴源代码并在别处运行。
多域和sub-domains
可以将代码锁定到多个域或sub-domain。例如,要锁定它,使代码只在www.example.comaddwww.example.com
上运行。要使它在根域上工作,包括sub-domain(example.com
,sub.example.com
),请使用.example.com
。
exclude
类型:string[]
默认值:[]
表示要从模糊处理中排除的文件的文件名或全局名。
identifierNamesGenerator
类型:string
默认值:hexadecimal
设置标识符名称生成器。
Available values:
dictionary
:来自identifiersDictionary
列表的标识符名称hexadecimal
:标识符名称,如_0xabc123
mangled
:短标识符名称,如a
、b
、c
mangled-shuffled
:与mangled
相同,但字母表混乱
identifiersDictionary
类型:string[]
默认:[]
为identifierNamesGenerator
:dictionary
选项设置标识符字典。字典中的每个标识符将用于几个变体中,每个字符的大小写都不同。因此,字典中标识符的数量应该取决于原始源代码的标识符数量。
identifiersPrefix
类型:string
默认值:''
为所有全局标识符设置前缀。
如果要模糊处理多个文件,请使用此选项。此选项有助于避免这些文件的全局标识符之间的冲突。每个文件的前缀应该不同。
inputFileName
类型:string
默认值:''
允许使用源代码设置输入文件的名称。此名称将在内部用于源映射生成。
log
类型:boolean
默认值:false
允许将信息记录到控制台。
numbersToExpressions
类型:boolean
默认值:false
启用数字转换为表达式
Example:
// input
const foo = 1234;
// output
const foo=-0xd93+-0x10b4+0x41*0x67+0x84e*0x3+-0xff8;
optionsPreset
类型:string
默认值:default
允许设置预设选项。
Available values:
default
;low-obfuscation
;medium-obfuscation
;high-obfuscation
.
所有添加选项将与选定的选项预设合并。
renameGlobals
类型:boolean
默认值:false
⚠️ 这个选项会破坏你的代码。只有当你知道它的作用时才启用它!
使用声明启用全局变量和函数名的模糊处理。
renameProperties
类型:boolean
默认值:false
⚠️ 在大多数情况下,此选项将破坏代码。只有当你知道它的作用时才启用它!
启用属性名称的重命名。所有built-inDOM属性和核心JavaScript类中的属性都将被忽略。
要设置重命名属性名的格式,请使用identifierNamesGenerator
选项。
要控制将重命名哪些属性,请使用reservedNames
选项。
Example:
// input
(function () {
const foo = {
prop1: 1,
prop2: 2,
calc: function () {
return this.prop1 + this.prop2;
}
};
console.log(foo.calc());
})();
// output
(function () {
const _0x46529b = {
'_0x10cec7': 0x1,
'_0xc1c0ca': 0x2,
'_0x4b961d': function () {
return this['_0x10cec7'] + this['_0xc1c0ca'];
}
};
console['log'](_0x46529b['_0x4b961d']());
}());
reservedNames
类型:string[]
默认值:[]
禁用由传递的RegExp模式匹配的混淆和标识符生成。
Example:
{
reservedNames: [
'^someVariable',
'functionParameter_\d'
]
}
reservedStrings
类型:string[]
默认值:[]
禁用由传递的RegExp模式匹配的字符串文本的转换。
Example:
{
reservedStrings: [
'react-native',
'./src/test',
'some-string_\d'
]
}
rotateStringArray
类型:boolean
默认值:true
⚠️ stringArray
必须启用
将stringArray
数组移动一个固定的和随机的(在代码混淆处生成的)位置。这使得将移除的字符串的顺序与它们的原始位置相匹配变得更加困难。
如果原始源代码不小,建议使用此选项,因为helper函数可以引起注意。
seed
类型:string|number
默认值:0
此选项为随机生成器设置种子。这对于创建可重复的结果非常有用。
如果种子是0
-随机生成器将在没有种子的情况下工作。
selfDefending
类型:boolean
默认值:false
⚠️ 使用此选项进行模糊处理后,请不要以任何方式更改混淆的代码,因为任何类似代码丑陋的更改都会触发自我保护,代码将不再工作!
⚠️ 此选项强制将compact
值设置为true
此选项使输出代码对格式化和变量重命名具有弹性。如果一个人试图在模糊的代码上使用JavaScript美化器,代码将不再工作,这使得理解和修改它变得更加困难。
shuffleStringArray
类型:boolean
默认值:true
⚠️ stringArray
必须启用
随机洗牌stringArray
数组项。
simplify
类型:boolean
默认:true
通过简化实现额外的代码混淆。
⚠️ 在将来的版本中,boolean
文本的模糊处理(true
=>!![]
)将移动到该选项下。
Example:
// input
if (condition1) {
const foo = 1;
const bar = 2;
console.log(foo);
return bar;
} else if (condition2) {
console.log(1);
console.log(2);
console.log(3);
return 4;
} else {
return 5;
}
// output
if (condition1) {
const foo = 0x1, bar = 0x2;
return console['log'](foo), bar;
} else
return condition2 ? (console['log'](0x1), console['log'](0x2), console['log'](0x3), 0x4) : 0x5;
sourceMap
类型:boolean
默认值:false
启用模糊代码的源映射生成。
源代码映射可以帮助您调试模糊的JavaScript源代码。如果希望或需要在生产环境中调试,可以将单独的源映射文件上载到一个秘密位置,然后将浏览器指向该位置。
sourceMapBaseUrl
类型:string
默认值:``
当sourceMapMode: 'separate'
时,将基url设置为源映射导入url。
CLI example:
javascript-obfuscator input.js --output out.js --source-map true --source-map-base-url 'http://localhost:9000'
Result:
//# sourceMappingURL=http://localhost:9000/out.js.map
sourceMapFileName
类型:string
默认值:``
设置sourceMapMode: 'separate'
时输出源映射的文件名。
CLI example:
javascript-obfuscator input.js --output out.js --source-map true --source-map-base-url 'http://localhost:9000' --source-map-file-name example
Result:
//# sourceMappingURL=http://localhost:9000/example.js.map
sourceMapMode
类型:string
默认:separate
指定源映射生成模式:
inline
-使用源映射生成单个文件,而不是使用单独的文件;separate
-使用源映射生成相应的'.map'文件。如果您通过CLI运行模糊处理程序-使用模糊处理代码//# sourceMappingUrl=file.js.map
将指向源映射文件的链接添加到文件末尾。
splitStrings
类型:boolean
默认:false
{strings}长度为48的字符串,拆分成文本长度为970的文本块。
Example:
// input
(function(){
var test = 'abcdefg';
})();
// output
(function(){
var _0x5a21 = 'ab' + 'cd' + 'ef' + 'g';
})();
splitStringsChunkLength
类型:number
默认:10
设置splitStrings
选项的块长度。
stringArray
类型:boolean
默认:true
移除字符串文字并将其放入特殊数组中。例如,var m = "Hello World";
中的字符串"Hello World"
将替换为var m = _0x12c456[0x1];
stringArrayEncoding
类型:string[]
默认值:[]
⚠️ stringArray
选项必须启用
此选项会减慢脚本的速度。
使用base64
或rc4
对stringArray
的所有字符串文本进行编码,并插入一个在运行时用于解码的特殊代码。
每个stringArray
值将由从传递的列表中随机选取的编码进行编码。这使得使用多个编码成为可能。
Available values:
'none'
(boolean
):不编码stringArray
值'base64'
(string
):使用base64
对stringArray
值进行编码'rc4'
(string
):使用rc4
对stringArray
值进行编码。大约30-50比base64
慢,但更难获得初始值。建议在使用rc4
编码时禁用unicodeEscapeSequence
选项,以防止出现非常大的混淆代码。
例如,对于以下选项值,某些stringArray
值将不会被编码,而某些值将使用base64
和rc4
编码进行编码:
stringArrayEncoding: [
'none',
'base64',
'rc4'
]
stringArrayThreshold
类型:number
默认值:0.8
最小值:0
最大值:1
⚠️ stringArray
选项必须启用
您可以使用此设置来调整将字符串文本插入stringArray
的概率(从0到1)。
此设置对于较大的代码量特别有用,因为它反复调用string array
,并且会降低代码的速度。
stringArrayThreshold: 0
等于stringArray: false
。
target
类型:string
默认值:browser
允许为模糊代码设置目标环境。
Available values:
browser
;browser-no-eval
;node
.
当前browser
和node
目标的输出代码是相同的,但某些browser-specific选项不允许与node
目标一起使用。browser-no-eval
目标的输出代码未使用eval
。
transformObjectKeys
类型:boolean
默认:false
启用对象键的转换。
Example:
// input
(function(){
var object = {
foo: 'test1',
bar: {
baz: 'test2'
}
};
})();
// output
var _0x2fae = [
'baz',
'test2',
'foo',
'test1',
'bar'
];
var _0x377c = function (_0x1fbd3f, _0x59c72f) {
_0x1fbd3f = _0x1fbd3f - 0x0;
var _0x14fada = _0x2fae[_0x1fbd3f];
return _0x14fada;
};
(function () {
var _0x8a12db = {};
_0x8a12db[_0x377c('0x0')] = _0x377c('0x1');
var _0xc75419 = {};
_0xc75419[_0x377c('0x2')] = _0x377c('0x3');
_0xc75419[_0x377c('0x4')] = _0x8a12db;
var _0x191393 = _0xc75419;
}());
unicodeEscapeSequence
类型:boolean
默认:false
允许启用/禁用字符串转换为unicode转义序列。
Unicode转义序列大大增加了代码的大小,字符串可以很容易地恢复到其原始视图。建议仅对小源代码启用此选项。