JavaScript obfuscator

JavaScript obfuscator 是一款功能强大的免费JavaScript混淆处理程序,包含多种功能,可为源代码提供保护。

github:https://github.com/javascript-obfuscator/javascript-obfuscator

构建工具插件

常用webpack与rollup的插件

选项

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
{
  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
}

选项说明

compact

Type: boolean Default: true

在一行上输出紧凑的代码。

config

Type: string Default: ``

包含混淆器选项的JS/JSON配置文件的名称。这些将被直接传递给CLI的选项覆盖

controlFlowFlattening

Type: boolean Default: false

此选项极大地影响性能,最多可使运行时速度慢1.5倍。使用controlFlowFlatteningThreshold值来设置受控制流扁平化影响的节点百分比。

启用代码控制流扁平化。控制流扁平化是一种阻碍程序理解的源代码结构转换。

Example:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
// 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

Type: number Default: 0.75 Min: 0 Max: 1

controlFlowFlattening变换将应用于任何给定节点的概率。

此设置对于大代码特别有用,因为大量的控制流转换会降低代码速度并增加代码大小。

controlFlowFlatteningThreshold: 0 等于 controlFlowFlattening: false.

deadCodeInjection

Type: boolean Default: false

⚠️ 显著增加混淆代码的大小(高达200%),仅在混淆代码的大小无关紧要时使用。使用deadCodeInjectionThreshold设置受死代码注入影响的节点百分比。
⚠️ 该选项强制启用stringArray选项。

使用此选项,随机的死代码块将被添加到混淆的代码中。

Example:

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
// input
(function () {
  if (true) {
    var foo = function () {
      console.log("abc");
    };
    var bar = function () {
      console.log("def");
    };
    var baz = function () {
      console.log("ghi");
    };
    var bark = function () {
      console.log("jkl");
    };
    var hawk = function () {
      console.log("mno");
    };

    foo();
    bar();
    baz();
    bark();
    hawk();
  }
})();

// output
var _0x37b8 = [
  "YBCtz",
  "GlrkA",
  "urPbb",
  "abc",
  "NMIhC",
  "yZgAj",
  "zrAId",
  "EtyJA",
  "log",
  "mno",
  "jkl",
  "def",
  "Quzya",
  "IWbBa",
  "ghi",
];
function _0x43a7(_0x12cf56, _0x587376) {
  _0x43a7 = function (_0x2f87a8, _0x47eac2) {
    _0x2f87a8 = _0x2f87a8 - (0x16a7 * 0x1 + 0x5 * 0x151 + -0x1c92);
    var _0x341e03 = _0x37b8[_0x2f87a8];
    return _0x341e03;
  };
  return _0x43a7(_0x12cf56, _0x587376);
}
(function () {
  if (!![]) {
    var _0xbbe28f = function () {
      var _0x2fc85f = _0x43a7;
      if (_0x2fc85f(0xaf) === _0x2fc85f(0xae)) {
        _0x1dd94f[_0x2fc85f(0xb2)](_0x2fc85f(0xb5));
      } else {
        console[_0x2fc85f(0xb2)](_0x2fc85f(0xad));
      }
    };
    var _0x5e46bc = function () {
      var _0x15b472 = _0x43a7;
      if (_0x15b472(0xb6) !== _0x15b472(0xaa)) {
        console[_0x15b472(0xb2)](_0x15b472(0xb5));
      } else {
        _0x47eac2[_0x15b472(0xb2)](_0x15b472(0xad));
      }
    };
    var _0x3669e8 = function () {
      var _0x47a442 = _0x43a7;
      if (_0x47a442(0xb7) !== _0x47a442(0xb0)) {
        console[_0x47a442(0xb2)](_0x47a442(0xb8));
      } else {
        _0x24e0bf[_0x47a442(0xb2)](_0x47a442(0xb3));
      }
    };
    var _0x28b05a = function () {
      var _0x497902 = _0x43a7;
      if (_0x497902(0xb1) === _0x497902(0xb1)) {
        console[_0x497902(0xb2)](_0x497902(0xb4));
      } else {
        _0x59c9c6[_0x497902(0xb2)](_0x497902(0xb4));
      }
    };
    var _0x402a54 = function () {
      var _0x1906b7 = _0x43a7;
      if (_0x1906b7(0xab) === _0x1906b7(0xac)) {
        _0xb89cd0[_0x1906b7(0xb2)](_0x1906b7(0xb8));
      } else {
        console[_0x1906b7(0xb2)](_0x1906b7(0xb3));
      }
    };
    _0xbbe28f();
    _0x5e46bc();
    _0x3669e8();
    _0x28b05a();
    _0x402a54();
  }
})();

deadCodeInjectionThreshold

Type: number Default: 0.4 Min: 0 Max: 1

允许设置受deadCodeInjection影响的节点百分比。

debugProtection

Type: boolean Default: false

⚠️ 如果打开开发者工具,则可以冻结浏览器。

这个选项使得几乎不可能使用开发人员工具的调试器功能(无论是在基于webkit的还是在Mozilla Firefox上)。

debugProtectionInterval

Type: number Default: 0

⚠️ 可以冻结您的浏览器!使用风险自负。!2.6.0版本类型为boolean,默认false

如果设置了,将使用以毫秒为单位的间隔强制控制台选项卡上的调试模式,从而使使用开发者工具的其他功能更加困难。启用debugProtection时生效。建议取值范围是2000 ~ 4000毫秒。

2.6.0版本的描述:如果选中,则会使用一个间隔来强制“console”选项卡上的调试模式,从而使开发人员工具的其他功能更难使用。如果启用了debugProtection,则有效。

disableConsoleOutput

Type: boolean Default: false

⚠️ 此选项全局禁用所有脚本的console调用

禁用 console.log, console.info, console.error, console.warn, console.debug, console.exceptionconsole.trace 通过用空函数替换它们。这使得调试器的使用更加困难。

domainLock

Type: string[] Default: []

⚠️ 此选项不适用于target: 'node'

允许只在特定的域和/或子域上运行混淆的源代码。这使得别人很难复制粘贴您的源代码并在其他地方运行。

如果源代码没有在此选项指定的域上运行,浏览器将被重定向到传递给domainLockRedirectUrl选项URL的地址。

多个域和子域

可以将代码锁定到多个域或子域。例如,要锁定它,使代码仅在www.example.com上运行,请添加www.example.com。要使它在包括任何子域(example.comsub.example.com)在根域上工作,请使用.example.com

domainLockRedirectUrl

Type: string Default: about:blank

⚠️ 此选项不适用于target: 'node'

如果源代码未在domainLock指定的域上运行,则允许将浏览器重定向到传递的URL

exclude

Type: string[] Default: []

一种文件名或globs,表示要从混淆处理中排除的文件。

forceTransformStrings

Type: string[] Default: []

启用字符串文字的强制转换,这些文字由传递的RegExp模式匹配。

⚠️ 此选项只影响不应该由stringArrayThreshold(或将来可能的其他阈值)转换的字符串

该选项的优先级高于reservedStrings选项,但没有高于条件注释的优先级。

Example:

1
2
3
{
  forceTransformStrings: ["some-important-value", "some-string_d"];
}

identifierNamesCache

Type: Object | null Default: null

该选项的主要目标是在混淆多个源/文件时使用相同的标识符名称。

目前支持两种类型的标识符:

  • 全局标识符:

  • 所有全局标识符将被写入缓存;

  • 所有匹配的未声明的全局标识符将被缓存中的值替换。

  • 属性标识符,仅当启用renameProperties选项时:

  • 所有属性标识符都将写入缓存;

  • 所有匹配的属性标识符将被缓存中的值替换。

Node.js API

如果传递了null值,则完全禁用缓存。

如果传递了一个空对象({}),则启用将标识符名称写入缓存对象(TIdentifierNamesCache类型)。将通过ObfuscationResult对象的getIdentifierNamesCache方法调用来访问此缓存对象。

生成的缓存对象接下来可以用作identifierNamesGenerator选项值,用于在混淆下一个源的所有匹配标识符名称期间使用这些名称。

Example:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
const source1ObfuscationResult = JavaScriptObfuscator.obfuscate(
  `
        function foo(arg) {
           console.log(arg)
        }
        
        function bar() {
            var bark = 2;
        }
    `,
  {
    compact: false,
    identifierNamesCache: {},
    renameGlobals: true,
  }
);

console.log(source1ObfuscationResult.getIdentifierNamesCache());
/*
    { 
        globalIdentifiers: {
            foo: '_0x5de86d',
            bar: '_0x2a943b'
        }
    }
*/

const source2ObfuscationResult = JavaScriptObfuscator.obfuscate(
  `
        // Expecting that these global functions are defined in another obfuscated file
        foo(1);
        bar();
        
        // Expecting that this global function is defined in third-party package
        baz();
    `,
  {
    compact: false,
    identifierNamesCache: source1ObfuscationResult.getIdentifierNamesCache(),
    renameGlobals: true,
  }
);

console.log(source2ObfuscationResult.getObfuscatedCode());
/*
    _0x5de86d(0x1);
    _0x2a943b();
    baz();
 */

CLI

CLI有一个不同的选项--identifier-names-cache-path,它允许定义现有.json文件的路径,该文件将用于读取和写入标识符名称缓存。

如果将传递到空文件的路径,则标识符名称缓存将写入该文件。

这个具有现有缓存的文件可以再次用作--identifier-names-cache-path选项值,用于在混淆下一个文件的所有匹配的标识符名称时使用这些名称。

identifierNamesGenerator

Type: string Default: hexadecimal

设置标识符名称生成器。

可用值:

  • dictionary: 标识符中的identifiersDictionary列表

  • hexadecimal: 标识符名称,如_0xabc123

  • mangled: 短标识符名称,如 a, b, c

  • mangled-shuffled: 同等与 mangled 但是使用混乱的字母

identifiersDictionary

Type: string[] Default: []

identifierNamesGenerator:dictionary选项设置标识符字典。字典中的每个标识符都将在几个变体中使用,每个字符的大小写不同。因此,字典中标识符的数量应该取决于原始源代码中的标识符数量。

identifiersPrefix

Type: string Default: ''

为所有全局标识符设置前缀。

当您想要混淆多个文件时,请使用此选项。此选项有助于避免这些文件的全局标识符之间的冲突。每个文件的前缀应该不同。

ignoreImports

Type: boolean Default: false

防止混淆require。在某些情况下,当运行时环境出于某种原因只需要使用静态字符串进行这些导入时,可能会有所帮助。

inputFileName

Type: string Default: ''

允许使用源代码设置输入文件的名称。此名称将在内部用于生成源映射。

使用NodeJS API时需要,并且sourceMapSourcesMode选项具有sources值`。

log

Type: boolean Default: false

启用将信息记录到控制台

numbersToExpressions

Type: boolean Default: false

启用数字转换为表达式

Example:

1
2
3
4
5
// input
const foo = 1234;

// output
const foo = -0xd93 + -0x10b4 + 0x41 * 0x67 + 0x84e * 0x3 + -0xff8;

optionsPreset

Type: string Default: default

允许设置预设选项(options preset)。

可用值:

  • default;

  • low-obfuscation;

  • medium-obfuscation;

  • high-obfuscation.

所有添加选项将与预设的选定选项合并。

renameGlobals

Type: boolean Default: false

⚠️ 此选项可能会破坏您的代码。只有当你知道它的作用时才启用它!

使用声明启用全局变量和函数名的混淆处理。

renameProperties

Type: boolean Default: false

⚠️ 此选项可能会破坏您的代码。只有当你知道它的作用时才启用它!

允许重命名属性名。所有内置DOM属性和核心JavaScript类中的属性都将被忽略。

要在该选项的安全模式和不安全模式之间切换,请使用renamePropertiesMode选项。

要设置重命名属性名的格式,请使用identifierNamesGenerator选项。

要控制重命名哪些属性,请使用reservedNames选项。

Example:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// 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"]());
})();

renamePropertiesMode

Type: string Default: safe

⚠️ 即使在 safe 模式,renameProperties选项也可能破坏你的代码。

指定renameProperties选项模式:

  • safe - 2.11.0发布后的默认行为。试图以更安全的方式重命名属性以防止运行时错误。在这种模式下,一些属性将被排除在重命名之外。

  • unsafe - 2.11.0发布前的默认行为。以不安全的方式重命名属性,没有任何限制。

如果一个文件使用来自其他文件的属性,则使用identifierNamesCache选项在这些文件之间保持相同的属性名称。

reservedNames

Type: string[] Default: []

禁用标识符的混淆和生成,由传递的RegExp模式匹配。

Example:

1
2
3
{
  reservedNames: ["^someVariable", "functionParameter_d"];
}

reservedStrings

Type: string[] Default: []

禁用由传递的RegExp模式匹配的字符串字面量的转换。

Example:

1
2
3
{
  reservedStrings: ["react-native", "./src/test", "some-string_d"];
}

seed

Type: string|number Default: 0

此选项为随机生成器设置seed。这对于创建可重复的结果很有用。

如果seed是0 -随机发生器将工作没有seed。

selfDefending

Type: boolean Default: false

⚠️ 在使用此选项后,不要以任何方式更改被混淆的代码,因为任何像丑陋代码这样的更改都会触发自我防御,代码将不再工作!
⚠️ 此选项强制将compact值设置为true

此选项使输出代码在格式化和变量重命名时具有弹性。如果试图在混淆的代码上使用JavaScript美化器,代码将不再工作,使其更难理解和修改。

simplify

Type: boolean Default: true

通过简化实现额外的代码混淆。

⚠️ 在以后的版本中,boolean字面值的混淆(true => !![])将被移到这个选项下。

Example:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// 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

Type: boolean Default: false

为混淆的代码启用源映射生成。

源映射可以帮助您调试混淆的JavaScript源代码。如果希望或需要在生产环境中进行调试,可以将单独的源映射文件上传到一个秘密位置,然后将浏览器指向该位置。

sourceMapBaseUrl

Type: string Default: ``

sourceMapMode: 'separate'时,将基本url设置为源映射导入url。

CLI example:

1
javascript-obfuscator input.js --output out.js --source-map true --source-map-base-url 'http://localhost:9000'

Result:

1
//# sourceMappingURL=http://localhost:9000/out.js.map

sourceMapFileName

Type: string Default: ``

sourceMapMode: 'separate'时,设置输出源映射的文件名。

CLI example:

1
javascript-obfuscator input.js --output out.js --source-map true --source-map-base-url 'http://localhost:9000' --source-map-file-name example

Result:

1
//# sourceMappingURL=http://localhost:9000/example.js.map

sourceMapMode

Type: string Default: separate

指定源映射生成模式:

  • inline - 在每个.js文件的末尾添加源映射;

  • separate - 生成相应的`.map ‘文件与源映射。如果你通过CLI运行混淆器-添加链接到源映射文件的文件末尾与混淆的代码//# sourceMappingUrl=file.js.map

sourceMapSourcesMode

Type: string Default: sources-content

允许控制sourcessourcesContent映射源的字段:

  • sources-content - 添加虚拟sources字段,添加原始源代码的sourcesContent字段;

  • sources - 使用有效的源描述添加sources字段,不添加sourcesContent字段。当使用NodeJS API时,需要定义inputFileName选项,该选项将用作source字段值。

splitStrings

Type: boolean Default: false

将字面值字符串分割为长度为splitStringsChunkLength选项值的块。

Example:

1
2
3
4
5
6
7
8
9
// input
(function () {
  var test = "abcdefg";
})();

// output
(function () {
  var _0x5a21 = "ab" + "cd" + "ef" + "g";
})();

splitStringsChunkLength

Type: number Default: 10

设置splitStrings选项的块长度。

stringArray

Type: boolean Default: true

删除字符串字面量并将其放置在特殊数组中。例如,字符串"Hello World"var m = "Hello World";将被替换为类似var m = _0x12c456[0x1];

stringArrayCallsTransform

Type: boolean Default: false

⚠️ 必须启用stringArray选项

启用对stringArray的调用转换。这些调用的所有参数都可以根据stringArrayCallsTransformThreshold的值提取到不同的对象。

这使得自动查找字符串数组的调用变得更加困难。

Example:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
function foo() {
    var k = {
        c: 0x2f2,
        d: '0x396',
        e: '0x397',
        f: '0x39a',
        g: '0x39d',
        h: 0x398,
        l: 0x394,
        m: '0x39b',
        n: '0x39f',
        o: 0x395,
        p: 0x395,
        q: 0x399,
        r: '0x399'
    };
    var c = i(k.d, k.e);
    var d = i(k.f, k.g);
    var e = i(k.h, k.l);
    var f = i(k.m, k.n);
    function i(c, d) {
        return b(c - k.c, d);
    }
    var g = i(k.o, k.p);
    var h = i(k.q, k.r);
}
function j(c, d) {
    var l = { c: 0x14b };
    return b(c - -l.c, d);
}
console[j(-'0xa6', -'0xa6')](foo());
function b(c, d) {
    var e = a();
    b = function (f, g) {
        f = f - 0xa3;
        var h = e[f];
        return h;
    };
    return b(c, d);
}
function a() {
    var m = [
        'string5',
        'string1',
        'log',
        'string3',
        'string6',
        'string2',
        'string4'
    ];
    a = function () {
        return m;
    };
    return a();
}

stringArrayCallsTransformThreshold

Type: number Default: 0.5

⚠️ 必须启用stringArraystringArrayCallsTransformThreshold选项

您可以使用此设置调整对字符串数组的调用将被转换的概率(从0到1)。

stringArrayEncoding

Type: string[] Default: []

⚠️ 必须启用stringArray选项

这个选项会降低脚本的速度。

使用base64rc4编码stringArray的所有字符串字面量,并插入用于在运行时解码的特殊代码。

每个stringArray值都将使用从传递列表中随机选择的编码进行编码。这使得使用多种编码成为可能。

可用的值:

  • 'none' (boolean): 不编码stringArray的值

  • 'base64' (string): 使用base64编码stringArray

  • 'rc4' (string): 使用rc4编码stringArray值。大约比base64慢30-50%,但更难获得初始值。建议在使用rc4编码时禁用unicodeEscapeSequence选项,以防止非常大尺寸的混淆代码。

例如,对于以下选项值,一些stringArray值将不会被编码,而一些值将使用base64rc4编码:

1
stringArrayEncoding: ["none", "base64", "rc4"];

stringArrayIndexesType

Type: string[] Default: ['hexadecimal-number']

⚠️ 必须启用stringArray选项

允许控制字符串数组调用索引的类型。

每个stringArray调用索引将由从传递的列表中随机选择的类型进行转换。这使得使用多种类型成为可能。

可用的值:

  • 'hexadecimal-number' (default): 将字符串数组调用索引转换为十六进制数

  • 'hexadecimal-numeric-string': 将字符串数组调用索引转换为十六进制数字字符串

2.9.0发布之前,javascript-obfuscator将所有字符串数组调用索引转换为hexadecimal-numeric-string类型。这使得一些手动去混淆稍微困难一些,但它允许自动去混淆器轻松检测这些调用。

新的hexadecimal-number类型方法使代码中更难自动检测字符串数组调用模式。

未来将添加更多类型。

stringArrayIndexShift

Type: boolean Default: true

⚠️ stringArray option must be enabled

Enables additional index shift for all string array calls

stringArrayRotate

Type: boolean Default: true

⚠️ 必须启用stringArray选项

stringArray数组移动到固定和随机的位置(在代码混淆时生成)。这使得将删除的字符串的顺序匹配到原始位置变得更加困难。

stringArrayShuffle

Type: boolean Default: true

⚠️ 必须启用stringArray选项

随机打乱stringArray数组项。

stringArrayWrappersCount

Type: number Default: 1

⚠️ 必须启用stringArray选项

为每个根或函数作用域内的string array设置包装器的计数。

每个作用域中包装器的实际数量受限于该作用域中文字节点的数量。

Example:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
// Input
const foo = "foo";
const bar = "bar";

function test() {
  const baz = "baz";
  const bark = "bark";
  const hawk = "hawk";
}

const eagle = "eagle";

// Output, stringArrayWrappersCount: 5
const _0x3f6c = ["bark", "bar", "foo", "eagle", "hawk", "baz"];
const _0x48f96e = _0x2e13;
const _0x4dfed8 = _0x2e13;
const _0x55e970 = _0x2e13;
function _0x2e13(_0x33c4f5, _0x3f6c62) {
  _0x2e13 = function (_0x2e1388, _0x60b1e) {
    _0x2e1388 = _0x2e1388 - 0xe2;
    let _0x53d475 = _0x3f6c[_0x2e1388];
    return _0x53d475;
  };
  return _0x2e13(_0x33c4f5, _0x3f6c62);
}
const foo = _0x48f96e(0xe4);
const bar = _0x4dfed8(0xe3);
function test() {
  const _0x1c262f = _0x2e13;
  const _0x54d7a4 = _0x2e13;
  const _0x5142fe = _0x2e13;
  const _0x1392b0 = _0x1c262f(0xe7);
  const _0x201a58 = _0x1c262f(0xe2);
  const _0xd3a7fb = _0x1c262f(0xe6);
}
const eagle = _0x48f96e(0xe5);

stringArrayWrappersChainedCalls

Type: boolean Default: true

⚠️ 必须启用stringArraystringArrayWrappersCount选项

启用string array包装器之间的链式调用。

Example:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
// Input
const foo = "foo";
const bar = "bar";

function test() {
  const baz = "baz";
  const bark = "bark";

  function test1() {
    const hawk = "hawk";
    const eagle = "eagle";
  }
}

// Output, stringArrayWrappersCount: 5, stringArrayWrappersChainedCalls: true
const _0x40c2 = ["bar", "bark", "hawk", "eagle", "foo", "baz"];
const _0x31c087 = _0x3280;
const _0x31759a = _0x3280;
function _0x3280(_0x1f52ee, _0x40c2a2) {
  _0x3280 = function (_0x3280a4, _0xf07b02) {
    _0x3280a4 = _0x3280a4 - 0x1c4;
    let _0x57a182 = _0x40c2[_0x3280a4];
    return _0x57a182;
  };
  return _0x3280(_0x1f52ee, _0x40c2a2);
}
const foo = _0x31c087(0x1c8);
const bar = _0x31c087(0x1c4);
function test() {
  const _0x848719 = _0x31759a;
  const _0x2693bf = _0x31c087;
  const _0x2c08e8 = _0x848719(0x1c9);
  const _0x359365 = _0x2693bf(0x1c5);
  function _0x175e90() {
    const _0x310023 = _0x848719;
    const _0x2302ef = _0x2693bf;
    const _0x237437 = _0x310023(0x1c6);
    const _0x56145c = _0x310023(0x1c7);
  }
}

stringArrayWrappersParametersMaxCount

Type: number Default: 2

⚠️ 必须启用stringArray选项
⚠️ 目前该选项仅影响由stringArrayWrappersType``function 选项值添加的包装器

允许控制字符串数组包装器参数的最大数量。

默认值和最小值为2。建议值为2 ~ 5。

stringArrayWrappersType

Type: string Default: variable

⚠️ 必须启用stringArraystringArrayWrappersCount选项

允许选择由stringArrayWrappersCount选项附加的包装器类型。

可用的值:

  • 'variable': 在每个作用域的顶部追加变量包装器。快速的性能。

  • 'function': 在每个作用域内的随机位置追加函数包装器。性能比变量更慢,但提供了更严格的混淆。

当性能损失对被混淆的应用程序影响不大时,强烈建议使用function包装器来实现更严重的混淆。

‘function’选项值的示例:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
// input
const foo = "foo";

function test() {
  const bar = "bar";
  console.log(foo, bar);
}

test();

// output
const a = ["log", "bar", "foo"];
const foo = d(0x567, 0x568);
function b(c, d) {
  b = function (e, f) {
    e = e - 0x185;
    let g = a[e];
    return g;
  };
  return b(c, d);
}
function test() {
  const c = e(0x51c, 0x51b);
  function e(c, g) {
    return b(c - 0x396, g);
  }
  console[f(0x51b, 0x51d)](foo, c);
  function f(c, g) {
    return b(c - 0x396, g);
  }
}
function d(c, g) {
  return b(g - 0x3e1, c);
}
test();

stringArrayThreshold

Type: number Default: 0.8 Min: 0 Max: 1

⚠️ 必须启用stringArray选项

您可以使用此设置来调整将字符串字面值插入到stringArray的概率(从0到1)。

此设置对于大代码特别有用,因为它会重复调用字符串数组,并降低代码速度。

stringArrayThreshold: 0 等于 stringArray: false.

target

Type: string Default: browser

允许为混淆的代码设置目标环境。

可用的值:

  • browser;

  • browser-no-eval;

  • node.

目前browsernode目标的输出代码是相同的,但某些浏览器特定的选项不允许与节点目标一起使用。

browser-no-eval目标的输出代码没有使用eval

transformObjectKeys

Type: boolean Default: false

启用对象键的转换。

Example:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
// input
(function () {
  var object = {
    foo: "test1",
    bar: {
      baz: "test2",
    },
  };
})();

// output
var _0x4735 = ["foo", "baz", "bar", "test1", "test2"];
function _0x390c(_0x33d6b6, _0x4735f4) {
  _0x390c = function (_0x390c37, _0x1eed85) {
    _0x390c37 = _0x390c37 - 0x198;
    var _0x2275f8 = _0x4735[_0x390c37];
    return _0x2275f8;
  };
  return _0x390c(_0x33d6b6, _0x4735f4);
}
(function () {
  var _0x17d1b7 = _0x390c;
  var _0xc9b6bb = {};
  _0xc9b6bb[_0x17d1b7(0x199)] = _0x17d1b7(0x19c);
  var _0x3d959a = {};
  _0x3d959a[_0x17d1b7(0x198)] = _0x17d1b7(0x19b);
  _0x3d959a[_0x17d1b7(0x19a)] = _0xc9b6bb;
  var _0x41fd86 = _0x3d959a;
})();

unicodeEscapeSequence

Type: boolean Default: false

允许启用/禁用字符串转换到unicode转义序列。

Unicode转义序列极大地增加了代码大小,并且字符串可以很容易地恢复到原始视图。建议仅对小源代码启用此选项。

预设选项

配置optionsPreset的选项

高混淆,低性能(high-obfuscation)

性能将比没有混淆时慢得多

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
{
    compact: true,
    controlFlowFlattening: true,
    controlFlowFlatteningThreshold: 1,
    deadCodeInjection: true,
    deadCodeInjectionThreshold: 1,
    debugProtection: true,
    debugProtectionInterval: 4000,
    disableConsoleOutput: true,
    identifierNamesGenerator: 'hexadecimal',
    log: false,
    numbersToExpressions: true,
    renameGlobals: false,
    selfDefending: true,
    simplify: true,
    splitStrings: true,
    splitStringsChunkLength: 5,
    stringArray: true,
    stringArrayCallsTransform: true,
    stringArrayEncoding: ['rc4'],
    stringArrayIndexShift: true,
    stringArrayRotate: true,
    stringArrayShuffle: true,
    stringArrayWrappersCount: 5,
    stringArrayWrappersChainedCalls: true,
    stringArrayWrappersParametersMaxCount: 5,
    stringArrayWrappersType: 'function',
    stringArrayThreshold: 1,
    transformObjectKeys: true,
    unicodeEscapeSequence: false
}

中等混淆,性能最佳(medium-obfuscation)

性能会比没有混淆时慢

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
{
    compact: true,
    controlFlowFlattening: true,
    controlFlowFlatteningThreshold: 0.75,
    deadCodeInjection: true,
    deadCodeInjectionThreshold: 0.4,
    debugProtection: false,
    debugProtectionInterval: 0,
    disableConsoleOutput: true,
    identifierNamesGenerator: 'hexadecimal',
    log: false,
    numbersToExpressions: true,
    renameGlobals: false,
    selfDefending: true,
    simplify: true,
    splitStrings: true,
    splitStringsChunkLength: 10,
    stringArray: true,
    stringArrayCallsTransform: true,
    stringArrayCallsTransformThreshold: 0.75,
    stringArrayEncoding: ['base64'],
    stringArrayIndexShift: true,
    stringArrayRotate: true,
    stringArrayShuffle: true,
    stringArrayWrappersCount: 2,
    stringArrayWrappersChainedCalls: true,
    stringArrayWrappersParametersMaxCount: 4,
    stringArrayWrappersType: 'function',
    stringArrayThreshold: 0.75,
    transformObjectKeys: true,
    unicodeEscapeSequence: false
}

低混淆,高性能(low-obfuscation)

性能将处于一个相对正常的水平

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
{
    compact: true,
    controlFlowFlattening: false,
    deadCodeInjection: false,
    debugProtection: false,
    debugProtectionInterval: 0,
    disableConsoleOutput: true,
    identifierNamesGenerator: 'hexadecimal',
    log: false,
    numbersToExpressions: false,
    renameGlobals: false,
    selfDefending: true,
    simplify: true,
    splitStrings: false,
    stringArray: true,
    stringArrayCallsTransform: false,
    stringArrayEncoding: [],
    stringArrayIndexShift: true,
    stringArrayRotate: true,
    stringArrayShuffle: true,
    stringArrayWrappersCount: 1,
    stringArrayWrappersChainedCalls: true,
    stringArrayWrappersParametersMaxCount: 2,
    stringArrayWrappersType: 'variable',
    stringArrayThreshold: 0.75,
    unicodeEscapeSequence: false
}

默认设置,高性能(default)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
{
    compact: true,
    controlFlowFlattening: false,
    deadCodeInjection: false,
    debugProtection: false,
    debugProtectionInterval: 0,
    disableConsoleOutput: false,
    identifierNamesGenerator: 'hexadecimal',
    log: false,
    numbersToExpressions: false,
    renameGlobals: false,
    selfDefending: false,
    simplify: true,
    splitStrings: false,
    stringArray: true,
    stringArrayCallsTransform: false,
    stringArrayCallsTransformThreshold: 0.5,
    stringArrayEncoding: [],
    stringArrayIndexShift: true,
    stringArrayRotate: true,
    stringArrayShuffle: true,
    stringArrayWrappersCount: 1,
    stringArrayWrappersChainedCalls: true,
    stringArrayWrappersParametersMaxCount: 2,
    stringArrayWrappersType: 'variable',
    stringArrayThreshold: 0.75,
    unicodeEscapeSequence: false
}