js-confuser 1.5.9 → 1.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/node.js.yml +2 -2
- package/CHANGELOG.md +55 -0
- package/README.md +346 -165
- package/dist/constants.js +6 -2
- package/dist/index.js +9 -21
- package/dist/obfuscator.js +19 -31
- package/dist/options.js +5 -5
- package/dist/order.js +1 -3
- package/dist/presets.js +6 -7
- package/dist/probability.js +2 -4
- package/dist/templates/bufferToString.js +13 -0
- package/dist/templates/crash.js +3 -3
- package/dist/templates/es5.js +18 -0
- package/dist/templates/functionLength.js +16 -0
- package/dist/transforms/calculator.js +77 -21
- package/dist/transforms/controlFlowFlattening/controlFlowFlattening.js +980 -367
- package/dist/transforms/controlFlowFlattening/expressionObfuscation.js +4 -1
- package/dist/transforms/controlFlowFlattening/switchCaseObfuscation.js +25 -26
- package/dist/transforms/deadCode.js +33 -25
- package/dist/transforms/dispatcher.js +8 -4
- package/dist/transforms/es5/antiDestructuring.js +2 -0
- package/dist/transforms/es5/es5.js +31 -34
- package/dist/transforms/extraction/duplicateLiteralsRemoval.js +92 -58
- package/dist/transforms/finalizer.js +82 -0
- package/dist/transforms/flatten.js +229 -148
- package/dist/transforms/identifier/globalAnalysis.js +88 -0
- package/dist/transforms/identifier/globalConcealing.js +10 -83
- package/dist/transforms/identifier/movedDeclarations.js +35 -88
- package/dist/transforms/identifier/renameVariables.js +124 -59
- package/dist/transforms/identifier/variableAnalysis.js +58 -62
- package/dist/transforms/lock/lock.js +0 -37
- package/dist/transforms/minify.js +60 -57
- package/dist/transforms/opaquePredicates.js +1 -1
- package/dist/transforms/preparation/preparation.js +2 -2
- package/dist/transforms/preparation.js +231 -0
- package/dist/transforms/renameLabels.js +1 -1
- package/dist/transforms/rgf.js +139 -247
- package/dist/transforms/stack.js +128 -26
- package/dist/transforms/string/encoding.js +150 -179
- package/dist/transforms/string/stringCompression.js +14 -15
- package/dist/transforms/string/stringConcealing.js +25 -8
- package/dist/transforms/string/stringEncoding.js +13 -24
- package/dist/transforms/transform.js +12 -19
- package/dist/traverse.js +24 -10
- package/dist/util/gen.js +17 -1
- package/dist/util/identifiers.js +37 -3
- package/dist/util/insert.js +35 -4
- package/dist/util/random.js +15 -0
- package/docs/ControlFlowFlattening.md +595 -0
- package/{Countermeasures.md → docs/Countermeasures.md} +1 -15
- package/{Integrity.md → docs/Integrity.md} +2 -2
- package/docs/RGF.md +419 -0
- package/package.json +5 -5
- package/src/constants.ts +3 -0
- package/src/index.ts +2 -2
- package/src/obfuscator.ts +19 -31
- package/src/options.ts +14 -103
- package/src/order.ts +1 -5
- package/src/presets.ts +6 -7
- package/src/probability.ts +2 -3
- package/src/templates/bufferToString.ts +68 -0
- package/src/templates/crash.ts +15 -19
- package/src/templates/es5.ts +131 -0
- package/src/templates/functionLength.ts +14 -0
- package/src/transforms/calculator.ts +122 -59
- package/src/transforms/controlFlowFlattening/controlFlowFlattening.ts +1583 -571
- package/src/transforms/controlFlowFlattening/expressionObfuscation.ts +4 -1
- package/src/transforms/deadCode.ts +383 -26
- package/src/transforms/dispatcher.ts +9 -4
- package/src/transforms/es5/antiDestructuring.ts +2 -0
- package/src/transforms/es5/es5.ts +32 -77
- package/src/transforms/extraction/duplicateLiteralsRemoval.ts +133 -129
- package/src/transforms/{hexadecimalNumbers.ts → finalizer.ts} +29 -13
- package/src/transforms/flatten.ts +357 -300
- package/src/transforms/identifier/globalAnalysis.ts +85 -0
- package/src/transforms/identifier/globalConcealing.ts +14 -103
- package/src/transforms/identifier/movedDeclarations.ts +49 -102
- package/src/transforms/identifier/renameVariables.ts +149 -78
- package/src/transforms/identifier/variableAnalysis.ts +66 -73
- package/src/transforms/lock/lock.ts +1 -42
- package/src/transforms/minify.ts +91 -75
- package/src/transforms/opaquePredicates.ts +2 -2
- package/src/transforms/preparation.ts +238 -0
- package/src/transforms/renameLabels.ts +2 -2
- package/src/transforms/rgf.ts +213 -405
- package/src/transforms/stack.ts +156 -36
- package/src/transforms/string/encoding.ts +115 -212
- package/src/transforms/string/stringCompression.ts +27 -18
- package/src/transforms/string/stringConcealing.ts +39 -9
- package/src/transforms/string/stringEncoding.ts +18 -18
- package/src/transforms/transform.ts +21 -23
- package/src/traverse.ts +23 -4
- package/src/types.ts +2 -1
- package/src/util/gen.ts +28 -3
- package/src/util/identifiers.ts +43 -2
- package/src/util/insert.ts +38 -3
- package/src/util/random.ts +13 -0
- package/test/code/Cash.test.ts +1 -1
- package/test/code/Dynamic.test.ts +12 -10
- package/test/code/ES6.src.js +146 -0
- package/test/code/ES6.test.ts +28 -2
- package/test/index.test.ts +2 -1
- package/test/probability.test.ts +44 -0
- package/test/templates/template.test.ts +1 -1
- package/test/transforms/antiTooling.test.ts +22 -0
- package/test/transforms/calculator.test.ts +40 -0
- package/test/transforms/controlFlowFlattening/controlFlowFlattening.test.ts +702 -160
- package/test/transforms/controlFlowFlattening/expressionObfuscation.test.ts +173 -0
- package/test/transforms/deadCode.test.ts +66 -15
- package/test/transforms/dispatcher.test.ts +20 -1
- package/test/transforms/es5/antiDestructuring.test.ts +16 -0
- package/test/transforms/flatten.test.ts +399 -86
- package/test/transforms/identifier/movedDeclarations.test.ts +63 -8
- package/test/transforms/identifier/renameVariables.test.ts +119 -0
- package/test/transforms/lock/antiDebug.test.ts +2 -2
- package/test/transforms/lock/lock.test.ts +1 -48
- package/test/transforms/minify.test.ts +104 -0
- package/test/transforms/preparation.test.ts +157 -0
- package/test/transforms/rgf.test.ts +261 -381
- package/test/transforms/stack.test.ts +143 -21
- package/test/transforms/string/stringCompression.test.ts +39 -0
- package/test/transforms/string/stringConcealing.test.ts +82 -0
- package/test/transforms/string/stringEncoding.test.ts +53 -2
- package/test/transforms/transform.test.ts +66 -0
- package/test/traverse.test.ts +139 -0
- package/test/util/identifiers.test.ts +113 -1
- package/test/util/insert.test.ts +57 -3
- package/src/transforms/controlFlowFlattening/choiceFlowObfuscation.ts +0 -87
- package/src/transforms/controlFlowFlattening/controlFlowObfuscation.ts +0 -203
- package/src/transforms/controlFlowFlattening/switchCaseObfuscation.ts +0 -130
- package/src/transforms/eval.ts +0 -89
- package/src/transforms/hideInitializingCode.ts +0 -432
- package/src/transforms/identifier/nameRecycling.ts +0 -280
- package/src/transforms/label.ts +0 -64
- package/src/transforms/preparation/nameConflicts.ts +0 -102
- package/src/transforms/preparation/preparation.ts +0 -176
- package/test/transforms/controlFlowFlattening/controlFlowObfuscation.test.ts +0 -101
- package/test/transforms/controlFlowFlattening/switchCaseObfuscation.test.ts +0 -120
- package/test/transforms/eval.test.ts +0 -131
- package/test/transforms/hideInitializingCode.test.ts +0 -336
- package/test/transforms/identifier/nameRecycling.test.ts +0 -205
- package/test/transforms/preparation/nameConflicts.test.ts +0 -52
- package/test/transforms/preparation/preparation.test.ts +0 -62
|
@@ -13,6 +13,9 @@ var _transform = _interopRequireDefault(require("../transform"));
|
|
|
13
13
|
|
|
14
14
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
15
15
|
|
|
16
|
+
/**
|
|
17
|
+
* Expression Obfuscation runs before Control Flow Flattening
|
|
18
|
+
*/
|
|
16
19
|
class ExpressionObfuscation extends _transform.default {
|
|
17
20
|
constructor(o) {
|
|
18
21
|
super(o);
|
|
@@ -27,7 +30,7 @@ class ExpressionObfuscation extends _transform.default {
|
|
|
27
30
|
var exprs = [];
|
|
28
31
|
var deleteExprs = [];
|
|
29
32
|
object.body.forEach((stmt, i) => {
|
|
30
|
-
if (stmt.type == "ExpressionStatement") {
|
|
33
|
+
if (stmt.type == "ExpressionStatement" && !stmt.directive) {
|
|
31
34
|
var expr = stmt.expression;
|
|
32
35
|
|
|
33
36
|
if (expr.type == "UnaryExpression" && !(expr.operator === "typeof" && expr.argument.type === "Identifier") && exprs.length // typeof is special
|
|
@@ -28,22 +28,23 @@ class SwitchCaseObfuscation extends _transform.default {
|
|
|
28
28
|
}
|
|
29
29
|
|
|
30
30
|
match(object, parents) {
|
|
31
|
-
return object.type == "SwitchStatement" && !object.cases.find(x => !(x.test && typeof x.test === "object" && x.test.type == "Literal" && typeof x.test.value === "number" && Math.abs(x.test.value) < 100000));
|
|
31
|
+
return object.type == "SwitchStatement" && (object.$controlFlowFlattening || !object.cases.find(x => !(x.test && typeof x.test === "object" && x.test.type == "Literal" && typeof x.test.value === "number" && Math.abs(x.test.value) < 100000)));
|
|
32
32
|
}
|
|
33
33
|
|
|
34
34
|
transform(object, parents) {
|
|
35
35
|
var types = new Set();
|
|
36
36
|
(0, _traverse.walk)(object.discriminant, [object, ...parents], (o, p) => {
|
|
37
37
|
if (o.type) {
|
|
38
|
-
|
|
39
|
-
types.add(o.type);
|
|
40
|
-
}
|
|
38
|
+
types.add(o.type);
|
|
41
39
|
}
|
|
42
40
|
});
|
|
43
|
-
types.delete("Identifier");
|
|
44
41
|
|
|
45
|
-
if (
|
|
46
|
-
|
|
42
|
+
if (!object.$controlFlowFlattening) {
|
|
43
|
+
types.delete("Identifier");
|
|
44
|
+
|
|
45
|
+
if (types.size) {
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
47
48
|
}
|
|
48
49
|
|
|
49
50
|
var body = parents[0];
|
|
@@ -64,33 +65,25 @@ class SwitchCaseObfuscation extends _transform.default {
|
|
|
64
65
|
return;
|
|
65
66
|
}
|
|
66
67
|
|
|
67
|
-
var factor = (0, _random.getRandomInteger)(
|
|
68
|
-
|
|
69
|
-
if (factor == 0) {
|
|
70
|
-
factor = 2;
|
|
71
|
-
}
|
|
72
|
-
|
|
68
|
+
var factor = (0, _random.getRandomInteger)(2, 100);
|
|
73
69
|
var offset = (0, _random.getRandomInteger)(-250, 250);
|
|
74
70
|
var newVar = this.getPlaceholder();
|
|
75
71
|
var newStates = [];
|
|
76
72
|
var max;
|
|
77
|
-
object.cases.forEach(
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
max
|
|
73
|
+
object.cases.forEach((caseObject, i) => {
|
|
74
|
+
if (caseObject.test && caseObject.test.type === "Literal" && typeof caseObject.test.value === "number") {
|
|
75
|
+
var current = caseObject.test.value;
|
|
76
|
+
var value = current * factor + offset;
|
|
77
|
+
newStates[i] = value;
|
|
78
|
+
|
|
79
|
+
if (!max || Math.abs(value) > max) {
|
|
80
|
+
max = Math.abs(value);
|
|
81
|
+
}
|
|
84
82
|
}
|
|
85
83
|
});
|
|
86
84
|
|
|
87
85
|
if (max > 100000) {
|
|
88
86
|
return;
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
if (new Set(newStates).size !== newStates.length) {
|
|
92
|
-
// not possible because of clashing case test
|
|
93
|
-
return;
|
|
94
87
|
} // State variable declaration
|
|
95
88
|
|
|
96
89
|
|
|
@@ -98,7 +91,13 @@ class SwitchCaseObfuscation extends _transform.default {
|
|
|
98
91
|
object.discriminant = (0, _gen.Identifier)(newVar); // possible so override
|
|
99
92
|
|
|
100
93
|
object.cases.forEach((x, i) => {
|
|
101
|
-
x.test
|
|
94
|
+
if (x.test) {
|
|
95
|
+
if (x.test.type === "Literal" && typeof x.test.value === "number") {
|
|
96
|
+
x.test = (0, _gen.Literal)(newStates[i]);
|
|
97
|
+
} else {
|
|
98
|
+
x.test = (0, _gen.BinaryExpression)("+", (0, _gen.BinaryExpression)("*", x.test, (0, _gen.Literal)(factor)), (0, _gen.Literal)(offset));
|
|
99
|
+
}
|
|
100
|
+
}
|
|
102
101
|
});
|
|
103
102
|
}
|
|
104
103
|
|
|
@@ -25,7 +25,7 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de
|
|
|
25
25
|
|
|
26
26
|
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
|
|
27
27
|
|
|
28
|
-
const templates = [(0, _template.default)("\n function curCSS( elem, name, computed ) {\n var ret;\n \n computed = computed || getStyles( elem );\n \n if ( computed ) {\n ret = computed.getPropertyValue( name ) || computed[ name ];\n \n if ( ret === \"\" && !isAttached( elem ) ) {\n ret = redacted.style( elem, name );\n }\n }\n \n return ret !== undefined ?\n \n // Support: IE <=9 - 11+\n // IE returns zIndex value as an integer.\n ret + \"\" :\n ret;\n }"), (0, _template.default)("\n function Example() {\n var state = redacted.useState(false);\n return x(\n ErrorBoundary,\n null,\n x(\n DisplayName,\n null,\n )\n );\n }"), (0, _template.default)("\n const path = require('path');\nconst { version } = require('../../package');\nconst { version: dashboardPluginVersion } = require('@redacted/enterprise-plugin/package');\nconst { version: componentsVersion } = require('@redacted/components/package');\nconst { sdkVersion } = require('@redacted/enterprise-plugin');\nconst isStandaloneExecutable = require('../utils/isStandaloneExecutable');\nconst resolveLocalRedactedPath = require('./resolve-local-redacted-path');\n\nconst redactedPath = path.resolve(__dirname, '../redacted.js');"), (0, _template.default)("\nmodule.exports = async (resolveLocalRedactedPath = ()=>{throw new Error(\"No redacted path provided\")}) => {\n const cliParams = new Set(process.argv.slice(2));\n if (!cliParams.has('--version')) {\n if (cliParams.size !== 1) return false;\n if (!cliParams.has('-v')) return false;\n }\n\n const installationModePostfix = await (async (isStandaloneExecutable, redactedPath) => {\n if (isStandaloneExecutable) return ' (standalone)';\n if (redactedPath === (await resolveLocalRedactedPath())) return ' (local)';\n return '';\n })();\n\n return true;\n};"), (0, _template.default)("\nfunction setCookie(cname, cvalue, exdays) {\n var d = new Date();\n d.setTime(d.getTime() + (exdays*24*60*60*1000));\n var expires = \"expires=\"+ d.toUTCString();\n document.cookie = cname + \"=\" + cvalue + \";\" + expires + \";path=/\";\n}"), (0, _template.default)("function getCookie(cname) {\n var name = cname + \"=\";\n var decodedCookie = decodeURIComponent(document.cookie);\n var ca = decodedCookie.split(';');\n for(var i = 0; i <ca.length; i++) {\n var c = ca[i];\n while (c.charAt(0) == ' ') {\n c = c.substring(1);\n }\n if (c.indexOf(name) == 0) {\n return c.substring(name.length, c.length);\n }\n }\n return \"\";\n}"), (0, _template.default)("function getLocalStorageValue(key, cb){\n if ( typeof key !== \"string\" ) {\n throw new Error(\"Invalid data key provided (not type string)\")\n }\n if ( !key ) {\n throw new Error(\"Invalid data key provided (empty string)\")\n }\n var value = window.localStorage.getItem(key)\n try {\n value = JSON.parse(value)\n } catch ( e ) {\n cb(new Error(\"Serialization error for data '\" + key + \"': \" + e.message))\n }\n\n cb(null, value)\n }"), (0, _template.default)("\n \n var __ = \"(c=ak(<~F$VU'9f)~><&85dBPL-module/from\";\n var s = \"q:function(){var ad=ad=>b(ad-29);if(!T.r[(typeof ab==ad(123)?\";\n var g = \"return U[c[c[d(-199)]-b(205)]]||V[ae(b(166))];case T.o[c[c[c[d(-199)]+d(-174)]-(c[b(119)]-(c[d(-199)]-163))]+ae(b(146))](0)==b(167)?d(-130):-d(-144)\";\n\n __.match(s + g);\n "), (0, _template.default)("\n function vec_pack(vec) {\n return vec[1] * 67108864 + (vec[0] < 0 ? 33554432 | vec[0] : vec[0]);\n }\n \n function vec_unpack(number) {\n switch (((number & 33554432) !== 0) * 1 + (number < 0) * 2) {\n case 0:\n return [number % 33554432, Math.trunc(number / 67108864)];\n case 1:\n return [\n (number % 33554432) - 33554432,\n Math.trunc(number / 67108864) + 1,\n ];\n case 2:\n return [\n (((number + 33554432) % 33554432) + 33554432) % 33554432,\n Math.round(number / 67108864),\n ];\n case 3:\n return [number % 33554432, Math.trunc(number / 67108864)];\n }\n }\n \n let a = vec_pack([2, 4]);\n let b = vec_pack([1, 2]);\n \n let c = a + b; // Vector addition\n let d = c - b; // Vector subtraction\n let e = d * 2; // Scalar multiplication\n let f = e / 2; // Scalar division\n \n console.log(vec_unpack(c)); // [3, 6]\n console.log(vec_unpack(d)); // [2, 4]\n console.log(vec_unpack(e)); // [4, 8]\n console.log(vec_unpack(f)); // [2, 4]\n "), (0, _template.default)("\n function buildCharacterMap(str) {\n const characterMap = {};\n \n for (let char of str.replace(/[^w]/g, \"\").toLowerCase())\n characterMap[char] = characterMap[char] + 1 || 1;\n \n return characterMap;\n }\n \n function isAnagrams(stringA, stringB) {\n const stringAMap = buildCharMap(stringA);\n const stringBMap = buildCharMap(stringB);\n \n for (let char in stringAMap) {\n if (stringAMap[char] !== stringBMap[char]) {\n return false;\n }\n }\n \n if (Object.keys(stringAMap).length !== Object.keys(stringBMap).length) {\n return false;\n }\n \n return true;\n }\n \n /**\n * @param {TreeNode} root\n * @return {boolean}\n */\n function isBalanced(root) {\n const height = getHeightBalanced(root);\n return height !== Infinity;\n }\n \n function getHeightBalanced(node) {\n if (!node) {\n return -1;\n }\n \n const leftTreeHeight = getHeightBalanced(node.left);\n const rightTreeHeight = getHeightBalanced(node.right);\n \n const heightDiff = Math.abs(leftTreeHeight - rightTreeHeight);\n \n if (\n leftTreeHeight === Infinity ||\n rightTreeHeight === Infinity ||\n heightDiff > 1\n ) {\n return Infinity;\n }\n \n const currentHeight = Math.max(leftTreeHeight, rightTreeHeight) + 1;\n return currentHeight;\n }\n \n window[\"__GLOBAL__HELPERS__\"] = {\n buildCharacterMap,\n isAnagrams,\n isBalanced,\n getHeightBalanced,\n };\n ")];
|
|
28
|
+
const templates = [(0, _template.default)("\n function curCSS( elem, name, computed ) {\n var ret;\n \n computed = computed || getStyles( elem );\n \n if ( computed ) {\n ret = computed.getPropertyValue( name ) || computed[ name ];\n \n if ( ret === \"\" && !isAttached( elem ) ) {\n ret = redacted.style( elem, name );\n }\n }\n \n return ret !== undefined ?\n \n // Support: IE <=9 - 11+\n // IE returns zIndex value as an integer.\n ret + \"\" :\n ret;\n }"), (0, _template.default)("\n function Example() {\n var state = redacted.useState(false);\n return x(\n ErrorBoundary,\n null,\n x(\n DisplayName,\n null,\n )\n );\n }"), (0, _template.default)("\n const path = require('path');\nconst { version } = require('../../package');\nconst { version: dashboardPluginVersion } = require('@redacted/enterprise-plugin/package');\nconst { version: componentsVersion } = require('@redacted/components/package');\nconst { sdkVersion } = require('@redacted/enterprise-plugin');\nconst isStandaloneExecutable = require('../utils/isStandaloneExecutable');\nconst resolveLocalRedactedPath = require('./resolve-local-redacted-path');\n\nconst redactedPath = path.resolve(__dirname, '../redacted.js');"), (0, _template.default)("\nmodule.exports = async (resolveLocalRedactedPath = ()=>{throw new Error(\"No redacted path provided\")}) => {\n const cliParams = new Set(process.argv.slice(2));\n if (!cliParams.has('--version')) {\n if (cliParams.size !== 1) return false;\n if (!cliParams.has('-v')) return false;\n }\n\n const installationModePostfix = await (async (isStandaloneExecutable, redactedPath) => {\n if (isStandaloneExecutable) return ' (standalone)';\n if (redactedPath === (await resolveLocalRedactedPath())) return ' (local)';\n return '';\n })();\n\n return true;\n};"), (0, _template.default)("\nfunction setCookie(cname, cvalue, exdays) {\n var d = new Date();\n d.setTime(d.getTime() + (exdays*24*60*60*1000));\n var expires = \"expires=\"+ d.toUTCString();\n document.cookie = cname + \"=\" + cvalue + \";\" + expires + \";path=/\";\n}"), (0, _template.default)("function getCookie(cname) {\n var name = cname + \"=\";\n var decodedCookie = decodeURIComponent(document.cookie);\n var ca = decodedCookie.split(';');\n for(var i = 0; i <ca.length; i++) {\n var c = ca[i];\n while (c.charAt(0) == ' ') {\n c = c.substring(1);\n }\n if (c.indexOf(name) == 0) {\n return c.substring(name.length, c.length);\n }\n }\n return \"\";\n}"), (0, _template.default)("function getLocalStorageValue(key, cb){\n if ( typeof key !== \"string\" ) {\n throw new Error(\"Invalid data key provided (not type string)\")\n }\n if ( !key ) {\n throw new Error(\"Invalid data key provided (empty string)\")\n }\n var value = window.localStorage.getItem(key)\n try {\n value = JSON.parse(value)\n } catch ( e ) {\n cb(new Error(\"Serialization error for data '\" + key + \"': \" + e.message))\n }\n\n cb(null, value)\n }"), (0, _template.default)("\n \n var __ = \"(c=ak(<~F$VU'9f)~><&85dBPL-module/from\";\n var s = \"q:function(){var ad=ad=>b(ad-29);if(!T.r[(typeof ab==ad(123)?\";\n var g = \"return U[c[c[d(-199)]-b(205)]]||V[ae(b(166))];case T.o[c[c[c[d(-199)]+d(-174)]-(c[b(119)]-(c[d(-199)]-163))]+ae(b(146))](0)==b(167)?d(-130):-d(-144)\";\n\n __.match(s + g);\n "), (0, _template.default)("\n function vec_pack(vec) {\n return vec[1] * 67108864 + (vec[0] < 0 ? 33554432 | vec[0] : vec[0]);\n }\n \n function vec_unpack(number) {\n switch (((number & 33554432) !== 0) * 1 + (number < 0) * 2) {\n case 0:\n return [number % 33554432, Math.trunc(number / 67108864)];\n case 1:\n return [\n (number % 33554432) - 33554432,\n Math.trunc(number / 67108864) + 1,\n ];\n case 2:\n return [\n (((number + 33554432) % 33554432) + 33554432) % 33554432,\n Math.round(number / 67108864),\n ];\n case 3:\n return [number % 33554432, Math.trunc(number / 67108864)];\n }\n }\n \n let a = vec_pack([2, 4]);\n let b = vec_pack([1, 2]);\n \n let c = a + b; // Vector addition\n let d = c - b; // Vector subtraction\n let e = d * 2; // Scalar multiplication\n let f = e / 2; // Scalar division\n \n console.log(vec_unpack(c)); // [3, 6]\n console.log(vec_unpack(d)); // [2, 4]\n console.log(vec_unpack(e)); // [4, 8]\n console.log(vec_unpack(f)); // [2, 4]\n "), (0, _template.default)("\n function buildCharacterMap(str) {\n const characterMap = {};\n \n for (let char of str.replace(/[^w]/g, \"\").toLowerCase())\n characterMap[char] = characterMap[char] + 1 || 1;\n \n return characterMap;\n }\n \n function isAnagrams(stringA, stringB) {\n const stringAMap = buildCharMap(stringA);\n const stringBMap = buildCharMap(stringB);\n \n for (let char in stringAMap) {\n if (stringAMap[char] !== stringBMap[char]) {\n return false;\n }\n }\n \n if (Object.keys(stringAMap).length !== Object.keys(stringBMap).length) {\n return false;\n }\n \n return true;\n }\n \n /**\n * @param {TreeNode} root\n * @return {boolean}\n */\n function isBalanced(root) {\n const height = getHeightBalanced(root);\n return height !== Infinity;\n }\n \n function getHeightBalanced(node) {\n if (!node) {\n return -1;\n }\n \n const leftTreeHeight = getHeightBalanced(node.left);\n const rightTreeHeight = getHeightBalanced(node.right);\n \n const heightDiff = Math.abs(leftTreeHeight - rightTreeHeight);\n \n if (\n leftTreeHeight === Infinity ||\n rightTreeHeight === Infinity ||\n heightDiff > 1\n ) {\n return Infinity;\n }\n \n const currentHeight = Math.max(leftTreeHeight, rightTreeHeight) + 1;\n return currentHeight;\n }\n \n window[\"__GLOBAL__HELPERS__\"] = {\n buildCharacterMap,\n isAnagrams,\n isBalanced,\n getHeightBalanced,\n };\n "), (0, _template.default)("\n function ListNode(){}\n var addTwoNumbers = function(l1, l2) {\n var carry = 0;\n var sum = 0;\n var head = new ListNode(0);\n var now = head;\n var a = l1;\n var b = l2;\n while (a !== null || b !== null) {\n sum = (a ? a.val : 0) + (b ? b.val : 0) + carry;\n carry = Math.floor(sum / 10);\n now.next = new ListNode(sum % 10);\n now = now.next;\n a = a ? a.next : null;\n b = b ? b.next : null;\n }\n if (carry) now.next = new ListNode(carry);\n return head.next;\n };\n\n console.log(addTwoNumbers)\n "), (0, _template.default)("\n var threeSum = function(nums) {\n var len = nums.length;\n var res = [];\n var l = 0;\n var r = 0;\n nums.sort((a, b) => (a - b));\n for (var i = 0; i < len; i++) {\n if (i > 0 && nums[i] === nums[i - 1]) continue;\n l = i + 1;\n r = len - 1;\n while (l < r) {\n if (nums[i] + nums[l] + nums[r] < 0) {\n l++;\n } else if (nums[i] + nums[l] + nums[r] > 0) {\n r--;\n } else {\n res.push([nums[i], nums[l], nums[r]]);\n while (l < r && nums[l] === nums[l + 1]) l++;\n while (l < r && nums[r] === nums[r - 1]) r--;\n l++;\n r--;\n }\n }\n }\n return res;\n };\n console.log(threeSum)\n "), (0, _template.default)("\n var combinationSum2 = function(candidates, target) {\n var res = [];\n var len = candidates.length;\n candidates.sort((a, b) => (a - b));\n dfs(res, [], 0, len, candidates, target);\n return res;\n };\n\n var dfs = function (res, stack, index, len, candidates, target) {\n var tmp = null;\n if (target < 0) return;\n if (target === 0) return res.push(stack);\n for (var i = index; i < len; i++) {\n if (candidates[i] > target) break;\n if (i > index && candidates[i] === candidates[i - 1]) continue;\n tmp = Array.from(stack);\n tmp.push(candidates[i]);\n dfs(res, tmp, i + 1, len, candidates, target - candidates[i]);\n }\n };\n\n console.log(combinationSum2);\n "), (0, _template.default)("\n var isScramble = function(s1, s2) {\n return helper({}, s1, s2);\n };\n \n var helper = function (dp, s1, s2) {\n var map = {};\n \n if (dp[s1 + s2] !== undefined) return dp[s1 + s2];\n if (s1 === s2) return true;\n \n for (var j = 0; j < s1.length; j++) {\n if (map[s1[j]] === undefined) map[s1[j]] = 0;\n if (map[s2[j]] === undefined) map[s2[j]] = 0;\n map[s1[j]]++;\n map[s2[j]]--;\n }\n \n for (var key in map) {\n if (map[key] !== 0) {\n dp[s1 + s2] = false;\n return false;\n }\n }\n \n for (var i = 1; i < s1.length; i++) {\n if ((helper(dp, s1.substr(0, i), s2.substr(0, i))\n && helper(dp, s1.substr(i), s2.substr(i))) ||\n (helper(dp, s1.substr(0, i), s2.substr(s2.length - i))\n && helper(dp, s1.substr(i), s2.substr(0, s2.length - i)))) {\n dp[s1 + s2] = true;\n return true;\n }\n }\n \n dp[s1 + s2] = false;\n return false;\n };\n\n console.log(isScramble);\n "), (0, _template.default)("\n var candy = function(ratings) {\n var len = ratings.length;\n var res = [];\n var sum = 0;\n for (var i = 0; i < len; i++) {\n res.push((i !== 0 && ratings[i] > ratings[i - 1]) ? (res[i - 1] + 1) : 1);\n }\n for (var j = len - 1; j >= 0; j--) {\n if (j !== len - 1 && ratings[j] > ratings[j + 1]) res[j] = Math.max(res[j], res[j + 1] + 1);\n sum += res[j];\n }\n return sum;\n };\n \n console.log(candy)\n "), (0, _template.default)("\n var maxPoints = function(points) {\n var max = 0;\n var map = {};\n var localMax = 0;\n var samePoint = 0;\n var k = 0;\n var len = points.length;\n for (var i = 0; i < len; i++) {\n map = {};\n localMax = 0;\n samePoint = 1;\n for (var j = i + 1; j < len; j++) {\n if (points[i].x === points[j].x && points[i].y === points[j].y) {\n samePoint++;\n continue;\n }\n if (points[i].y === points[j].y) k = Number.MAX_SAFE_INTEGER;\n else k = (points[i].x - points[j].x) / (points[i].y - points[j].y);\n if (!map[k]) map[k] = 0;\n map[k]++;\n localMax = Math.max(localMax, map[k]);\n }\n localMax += samePoint;\n max = Math.max(max, localMax);\n }\n return max;\n };\n \n console.log(maxPoints)\n "), (0, _template.default)("\n var maximumGap = function(nums) {\n var len = nums.length;\n if (len < 2) return 0;\n \n var max = Math.max(...nums);\n var min = Math.min(...nums);\n if (max === min) return 0;\n \n var minBuckets = Array(len - 1).fill(Number.MAX_SAFE_INTEGER);\n var maxBuckets = Array(len - 1).fill(Number.MIN_SAFE_INTEGER);\n var gap = Math.ceil((max - min) / (len - 1));\n var index = 0;\n for (var i = 0; i < len; i++) {\n if (nums[i] === min || nums[i] === max) continue;\n index = Math.floor((nums[i] - min) / gap);\n minBuckets[index] = Math.min(minBuckets[index], nums[i]);\n maxBuckets[index] = Math.max(maxBuckets[index], nums[i]);\n }\n \n var maxGap = Number.MIN_SAFE_INTEGER;\n var preVal = min;\n for (var j = 0; j < len - 1; j++) {\n if (minBuckets[j] === Number.MAX_SAFE_INTEGER && maxBuckets[j] === Number.MIN_SAFE_INTEGER) continue;\n maxGap = Math.max(maxGap, minBuckets[j] - preVal);\n preVal = maxBuckets[j];\n }\n maxGap = Math.max(maxGap, max - preVal);\n \n return maxGap;\n };\n\n console.log(maximumGap);\n "), (0, _template.default)("\n /**\n * @param {number} capacity\n */\n var LRUCache = function(capacity) {\n this.capacity = capacity;\n this.length = 0;\n this.map = {};\n this.head = null;\n this.tail = null;\n };\n \n /** \n * @param {number} key\n * @return {number}\n */\n LRUCache.prototype.get = function(key) {\n var node = this.map[key];\n if (node) {\n this.remove(node);\n this.insert(node.key, node.val);\n return node.val;\n } else {\n return -1;\n }\n };\n \n /** \n * @param {number} key \n * @param {number} value\n * @return {void}\n */\n LRUCache.prototype.put = function(key, value) {\n if (this.map[key]) {\n this.remove(this.map[key]);\n this.insert(key, value);\n } else {\n if (this.length === this.capacity) {\n this.remove(this.head);\n this.insert(key, value);\n } else {\n this.insert(key, value);\n this.length++;\n }\n }\n };\n \n /** \n * Your LRUCache object will be instantiated and called as such:\n * var obj = Object.create(LRUCache).createNew(capacity)\n * var param_1 = obj.get(key)\n * obj.put(key,value)\n */\n \n LRUCache.prototype.remove = function (node) {\n var prev = node.prev;\n var next = node.next;\n if (next) next.prev = prev;\n if (prev) prev.next = next;\n if (this.head === node) this.head = next;\n if (this.tail === node) this.tail = prev;\n delete this.map[node.key];\n };\n \n LRUCache.prototype.insert = function (key, val) {\n var node = new List(key, val);\n if (!this.tail) {\n this.tail = node;\n this.head = node;\n } else {\n this.tail.next = node;\n node.prev = this.tail;\n this.tail = node;\n }\n this.map[key] = node;\n };\n\n console.log(LRUCache);\n "), (0, _template.default)("\n var isInterleave = function(s1, s2, s3) {\n var dp = {};\n if (s3.length !== s1.length + s2.length) return false;\n return helper(s1, s2, s3, 0, 0, 0, dp);\n };\n \n var helper = function (s1, s2, s3, i, j, k, dp) {\n var res = false;\n \n if (k >= s3.length) return true;\n if (dp['' + i + j + k] !== undefined) return dp['' + i + j + k];\n \n if (s3[k] === s1[i] && s3[k] === s2[j]) {\n res = helper(s1, s2, s3, i + 1, j, k + 1, dp) || helper(s1, s2, s3, i, j + 1, k + 1, dp);\n } else if (s3[k] === s1[i]) {\n res = helper(s1, s2, s3, i + 1, j, k + 1, dp);\n } else if (s3[k] === s2[j]) {\n res = helper(s1, s2, s3, i, j + 1, k + 1, dp);\n }\n \n dp['' + i + j + k] = res;\n \n return res;\n };\n\n console.log(isInterleave);\n "), (0, _template.default)("\n var solveNQueens = function(n) {\n var res = [];\n if (n === 1 || n >= 4) dfs(res, [], n, 0);\n return res;\n };\n \n var dfs = function (res, points, n, index) {\n for (var i = index; i < n; i++) {\n if (points.length !== i) return;\n for (var j = 0; j < n; j++) {\n if (isValid(points, [i, j])) {\n points.push([i, j]);\n dfs(res, points, n, i + 1);\n if (points.length === n) res.push(buildRes(points));\n points.pop();\n }\n }\n }\n };\n \n var buildRes = function (points) {\n var res = [];\n var n = points.length;\n for (var i = 0; i < n; i++) {\n res[i] = '';\n for (var j = 0; j < n; j++) {\n res[i] += (points[i][1] === j ? 'Q' : '.');\n }\n }\n return res;\n };\n \n var isValid = function (oldPoints, newPoint) {\n var len = oldPoints.length;\n for (var i = 0; i < len; i++) {\n if (oldPoints[i][0] === newPoint[0] || oldPoints[i][1] === newPoint[1]) return false;\n if (Math.abs((oldPoints[i][0] - newPoint[0]) / (oldPoints[i][1] - newPoint[1])) === 1) return false;\n }\n return true;\n };\n\n console.log(solveNQueens);\n ")];
|
|
29
29
|
/**
|
|
30
30
|
* Adds dead code to blocks.
|
|
31
31
|
*
|
|
@@ -37,8 +37,6 @@ class DeadCode extends _transform.default {
|
|
|
37
37
|
constructor(o) {
|
|
38
38
|
super(o, _order.ObfuscateOrder.DeadCode);
|
|
39
39
|
|
|
40
|
-
_defineProperty(this, "usedNames", void 0);
|
|
41
|
-
|
|
42
40
|
_defineProperty(this, "made", void 0);
|
|
43
41
|
|
|
44
42
|
this.made = 0;
|
|
@@ -49,29 +47,39 @@ class DeadCode extends _transform.default {
|
|
|
49
47
|
}
|
|
50
48
|
|
|
51
49
|
transform(object, parents) {
|
|
52
|
-
if ((0, _probability.ComputeProbabilityMap)(this.options.deadCode)) {
|
|
53
|
-
return
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
var variableDeclaration = (0, _gen.VariableDeclaration)((0, _gen.VariableDeclarator)(name, (0, _gen.Literal)(false)));
|
|
62
|
-
var body = (0, _insert.getBlockBody)(object);
|
|
63
|
-
var index = (0, _random.getRandomInteger)(0, body.length);
|
|
64
|
-
var template;
|
|
65
|
-
|
|
66
|
-
do {
|
|
67
|
-
template = (0, _random.choice)(templates);
|
|
68
|
-
} while (this.options.es5 && template.source.includes("async"));
|
|
69
|
-
|
|
70
|
-
var ifStatement = (0, _gen.IfStatement)((0, _gen.Identifier)(name), template.compile(), null);
|
|
71
|
-
body.splice(index, 0, ifStatement);
|
|
72
|
-
(0, _insert.prepend)(object, variableDeclaration);
|
|
73
|
-
};
|
|
50
|
+
if (!(0, _probability.ComputeProbabilityMap)(this.options.deadCode)) {
|
|
51
|
+
return;
|
|
52
|
+
} // Hard-coded limit of 100 Dead Code insertions
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
this.made++;
|
|
56
|
+
|
|
57
|
+
if (this.made > 100) {
|
|
58
|
+
return;
|
|
74
59
|
}
|
|
60
|
+
|
|
61
|
+
return () => {
|
|
62
|
+
var body = (0, _insert.getBlockBody)(object); // Do not place code before Import statements or 'use strict' directives
|
|
63
|
+
|
|
64
|
+
var safeOffset = 0;
|
|
65
|
+
|
|
66
|
+
for (var node of body) {
|
|
67
|
+
if (node.type === "ImportDeclaration" || node.directive) safeOffset++;else break;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
var index = (0, _random.getRandomInteger)(safeOffset, body.length);
|
|
71
|
+
var name = this.getPlaceholder();
|
|
72
|
+
var variableDeclaration = (0, _gen.VariableDeclaration)((0, _gen.VariableDeclarator)(name, (0, _gen.Literal)(false)));
|
|
73
|
+
var template;
|
|
74
|
+
|
|
75
|
+
do {
|
|
76
|
+
template = (0, _random.choice)(templates);
|
|
77
|
+
} while (this.options.es5 && template.source.includes("async"));
|
|
78
|
+
|
|
79
|
+
var ifStatement = (0, _gen.IfStatement)((0, _gen.Identifier)(name), template.compile(), null);
|
|
80
|
+
body.splice(index, 0, ifStatement);
|
|
81
|
+
(0, _insert.prepend)(object, variableDeclaration);
|
|
82
|
+
};
|
|
75
83
|
}
|
|
76
84
|
|
|
77
85
|
}
|
|
@@ -56,9 +56,12 @@ function _defineProperty(obj, key, value) { if (key in obj) { Object.definePrope
|
|
|
56
56
|
* 3. using `this`
|
|
57
57
|
*/
|
|
58
58
|
class Dispatcher extends _transform.default {
|
|
59
|
+
// Debug mode preserves function names
|
|
59
60
|
constructor(o) {
|
|
60
61
|
super(o, _order.ObfuscateOrder.Dispatcher);
|
|
61
62
|
|
|
63
|
+
_defineProperty(this, "isDebug", false);
|
|
64
|
+
|
|
62
65
|
_defineProperty(this, "count", void 0);
|
|
63
66
|
|
|
64
67
|
this.count = 0;
|
|
@@ -102,11 +105,12 @@ class Dispatcher extends _transform.default {
|
|
|
102
105
|
|
|
103
106
|
if (context === c) {
|
|
104
107
|
if (o.type == "FunctionDeclaration" && o.id.name) {
|
|
108
|
+
var name = o.id.name;
|
|
109
|
+
|
|
105
110
|
if (o.$requiresEval || o.async || o.generator || p.find(x => x.$dispatcherSkip || x.type == "MethodDefinition") || o.body.type != "BlockStatement") {
|
|
106
111
|
illegalFnNames.add(name);
|
|
107
|
-
}
|
|
112
|
+
} // If dupe, no routing
|
|
108
113
|
|
|
109
|
-
var name = o.id.name; // If dupe, no routing
|
|
110
114
|
|
|
111
115
|
if (functionDeclarations[name]) {
|
|
112
116
|
illegalFnNames.add(name);
|
|
@@ -157,13 +161,13 @@ class Dispatcher extends _transform.default {
|
|
|
157
161
|
|
|
158
162
|
var gen = this.getGenerator();
|
|
159
163
|
Object.keys(functionDeclarations).forEach(name => {
|
|
160
|
-
newFnNames[name] = gen.generate();
|
|
164
|
+
newFnNames[name] = this.isDebug ? "_dispatcher_" + this.count + "_" + name : gen.generate();
|
|
161
165
|
}); // set containing new name
|
|
162
166
|
|
|
163
167
|
var set = new Set(Object.keys(newFnNames)); // Only make a dispatcher function if it caught any functions
|
|
164
168
|
|
|
165
169
|
if (set.size > 0) {
|
|
166
|
-
var payloadArg = "
|
|
170
|
+
var payloadArg = this.getPlaceholder() + "_dispatcher_" + this.count + "_payload";
|
|
167
171
|
var dispatcherFnName = this.getPlaceholder() + "_dispatcher_" + this.count;
|
|
168
172
|
this.log(dispatcherFnName, set);
|
|
169
173
|
this.count++;
|
|
@@ -158,6 +158,8 @@ class AntiDestructuring extends _transform.default {
|
|
|
158
158
|
if (x.type == "Identifier") {
|
|
159
159
|
exprs.push((0, _gen.AssignmentExpression)(operator, (0, _insert.clone)(x), realm));
|
|
160
160
|
names.add(x.name);
|
|
161
|
+
} else if (x.type == "MemberExpression") {
|
|
162
|
+
exprs.push((0, _gen.AssignmentExpression)(operator, (0, _insert.clone)(x), realm));
|
|
161
163
|
} else if (x.type == "ObjectPattern") {
|
|
162
164
|
x.properties.forEach(property => {
|
|
163
165
|
recursive(property.value, (0, _gen.MemberExpression)(realm, property.key, property.computed));
|
|
@@ -13,8 +13,6 @@ var _insert = require("../../util/insert");
|
|
|
13
13
|
|
|
14
14
|
var _traverse = require("../../traverse");
|
|
15
15
|
|
|
16
|
-
var _template = _interopRequireDefault(require("../../templates/template"));
|
|
17
|
-
|
|
18
16
|
var _order = require("../../order");
|
|
19
17
|
|
|
20
18
|
var _assert = require("assert");
|
|
@@ -31,6 +29,8 @@ var _antiES6Object = _interopRequireDefault(require("./antiES6Object"));
|
|
|
31
29
|
|
|
32
30
|
var _antiSpreadOperator = _interopRequireDefault(require("./antiSpreadOperator"));
|
|
33
31
|
|
|
32
|
+
var _es = require("../../templates/es5");
|
|
33
|
+
|
|
34
34
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
35
35
|
|
|
36
36
|
/**
|
|
@@ -93,24 +93,44 @@ class AntiArrowFunction extends _transform.default {
|
|
|
93
93
|
}
|
|
94
94
|
|
|
95
95
|
}
|
|
96
|
+
/**
|
|
97
|
+
* The ES5 options aims to convert ES6 and up features down to ES5-compatible code.
|
|
98
|
+
*
|
|
99
|
+
* The obfuscator regularly adds ES6 code (variable destructuring, spread element, etc.)
|
|
100
|
+
* This transformations goal is undo only these things.
|
|
101
|
+
*/
|
|
102
|
+
|
|
96
103
|
|
|
97
104
|
exports.AntiArrowFunction = AntiArrowFunction;
|
|
98
105
|
|
|
99
|
-
class
|
|
106
|
+
class ES5 extends _transform.default {
|
|
100
107
|
constructor(o) {
|
|
101
|
-
super(o);
|
|
108
|
+
super(o, _order.ObfuscateOrder.ES5);
|
|
109
|
+
this.before.push(new _antiClass.default(o));
|
|
110
|
+
this.before.push(new _antiTemplate.default(o));
|
|
111
|
+
this.before.push(new _antiSpreadOperator.default(o));
|
|
112
|
+
this.before.push(new _antiES6Object.default(o));
|
|
113
|
+
this.before.push(new AntiArrowFunction(o));
|
|
114
|
+
this.before.push(new _antiDestructuring.default(o));
|
|
115
|
+
this.before.push(new AntiConstLet(o));
|
|
102
116
|
}
|
|
103
117
|
|
|
118
|
+
apply(tree) {
|
|
119
|
+
super.apply(tree);
|
|
120
|
+
|
|
121
|
+
var nodesToAdd = _es.ES5Template.compile();
|
|
122
|
+
|
|
123
|
+
(0, _insert.prepend)(tree, ...nodesToAdd);
|
|
124
|
+
} // FixedExpressions
|
|
125
|
+
|
|
126
|
+
|
|
104
127
|
match(object, parents) {
|
|
105
|
-
return
|
|
128
|
+
return !!object.type;
|
|
106
129
|
}
|
|
107
130
|
|
|
108
131
|
transform(object, parents) {
|
|
109
132
|
return () => {
|
|
110
|
-
|
|
111
|
-
object.init = object.init.expression;
|
|
112
|
-
}
|
|
113
|
-
|
|
133
|
+
// Object.keyword -> Object["keyword"]
|
|
114
134
|
if (object.type == "MemberExpression") {
|
|
115
135
|
if (!object.computed && object.property.type == "Identifier") {
|
|
116
136
|
if (_constants.reservedKeywords.has(object.property.name)) {
|
|
@@ -118,7 +138,8 @@ class FixedExpressions extends _transform.default {
|
|
|
118
138
|
object.computed = true;
|
|
119
139
|
}
|
|
120
140
|
}
|
|
121
|
-
}
|
|
141
|
+
} // { keyword: ... } -> { "keyword": ... }
|
|
142
|
+
|
|
122
143
|
|
|
123
144
|
if (object.type == "Property") {
|
|
124
145
|
if (!object.computed && object.key.type == "Identifier") {
|
|
@@ -132,28 +153,4 @@ class FixedExpressions extends _transform.default {
|
|
|
132
153
|
|
|
133
154
|
}
|
|
134
155
|
|
|
135
|
-
class ES5 extends _transform.default {
|
|
136
|
-
constructor(o) {
|
|
137
|
-
super(o, _order.ObfuscateOrder.ES5);
|
|
138
|
-
this.before.push(new _antiClass.default(o));
|
|
139
|
-
this.before.push(new _antiTemplate.default(o));
|
|
140
|
-
this.before.push(new _antiSpreadOperator.default(o));
|
|
141
|
-
this.before.push(new _antiES6Object.default(o));
|
|
142
|
-
this.before.push(new AntiArrowFunction(o));
|
|
143
|
-
this.before.push(new _antiDestructuring.default(o));
|
|
144
|
-
this.before.push(new AntiConstLet(o));
|
|
145
|
-
this.concurrent.push(new FixedExpressions(o));
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
match(object, parents) {
|
|
149
|
-
return object.type == "Program";
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
transform(object, parents) {
|
|
153
|
-
var block = (0, _traverse.getBlock)(object, parents);
|
|
154
|
-
(0, _insert.getBlockBody)(block).splice(0, 0, ...(0, _template.default)("\n !Array.prototype.forEach ? Array.prototype.forEach = function (callback, thisArg) {\n thisArg = thisArg;\n for (var i = 0; i < this.length; i++) {\n callback.call(thisArg, this[i], i, this);\n }\n } : 0;\n \n !Array.prototype.map ? Array.prototype.map = function (callback, thisArg) {\n thisArg = thisArg;\n var array=[];\n for (var i = 0; i < this.length; i++) {\n array.push( callback.call(thisArg, this[i], i, this) );\n }\n return array;\n } : 0;\n\n !Array.prototype.reduce ? Array.prototype.reduce = function(fn, initial) {\n var values = this;\n if ( typeof initial === \"undefined\" ) {\n initial = 0;\n }\n\n values.forEach(function(item, index){\n initial = fn(initial, item, index, this);\n });\n\n return initial;\n } : 0;\n ").compile());
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
}
|
|
158
|
-
|
|
159
156
|
exports.default = ES5;
|
|
@@ -23,6 +23,8 @@ var _assert = require("assert");
|
|
|
23
23
|
|
|
24
24
|
var _random = require("../../util/random");
|
|
25
25
|
|
|
26
|
+
var _traverse = require("../../traverse");
|
|
27
|
+
|
|
26
28
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
27
29
|
|
|
28
30
|
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
|
|
@@ -46,12 +48,19 @@ function _defineProperty(obj, key, value) { if (key in obj) { Object.definePrope
|
|
|
46
48
|
* ```
|
|
47
49
|
*/
|
|
48
50
|
class DuplicateLiteralsRemoval extends _transform.default {
|
|
51
|
+
// The array holding all the duplicate literals
|
|
52
|
+
// The array expression node to be inserted into the program
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Literals in the array
|
|
56
|
+
*/
|
|
57
|
+
|
|
49
58
|
/**
|
|
50
|
-
*
|
|
59
|
+
* Literals are saved here the first time they are seen.
|
|
51
60
|
*/
|
|
52
61
|
|
|
53
62
|
/**
|
|
54
|
-
*
|
|
63
|
+
* Block -> { functionName, indexShift }
|
|
55
64
|
*/
|
|
56
65
|
constructor(o) {
|
|
57
66
|
super(o, _order.ObfuscateOrder.DuplicateLiteralsRemoval);
|
|
@@ -64,23 +73,45 @@ class DuplicateLiteralsRemoval extends _transform.default {
|
|
|
64
73
|
|
|
65
74
|
_defineProperty(this, "first", void 0);
|
|
66
75
|
|
|
67
|
-
_defineProperty(this, "
|
|
68
|
-
|
|
69
|
-
_defineProperty(this, "fnGetters", void 0);
|
|
76
|
+
_defineProperty(this, "functions", void 0);
|
|
70
77
|
|
|
71
78
|
this.map = new Map();
|
|
72
79
|
this.first = new Map();
|
|
73
|
-
this.
|
|
74
|
-
this.fnGetters = new Map();
|
|
80
|
+
this.functions = new Map();
|
|
75
81
|
}
|
|
76
82
|
|
|
77
83
|
apply(tree) {
|
|
78
84
|
super.apply(tree);
|
|
79
85
|
|
|
80
|
-
if (this.arrayName && this.arrayExpression.elements.length) {
|
|
86
|
+
if (this.arrayName && this.arrayExpression.elements.length > 0) {
|
|
87
|
+
// This function simply returns the array
|
|
81
88
|
var getArrayFn = this.getPlaceholder();
|
|
82
|
-
(0, _insert.append)(tree, (0, _gen.FunctionDeclaration)(getArrayFn, [], [(0, _gen.ReturnStatement)(this.arrayExpression)]));
|
|
83
|
-
|
|
89
|
+
(0, _insert.append)(tree, (0, _gen.FunctionDeclaration)(getArrayFn, [], [(0, _gen.ReturnStatement)(this.arrayExpression)])); // This variable holds the array
|
|
90
|
+
|
|
91
|
+
(0, _insert.prepend)(tree, (0, _gen.VariableDeclaration)((0, _gen.VariableDeclarator)(this.arrayName, (0, _gen.CallExpression)((0, _gen.MemberExpression)((0, _gen.Identifier)(getArrayFn), (0, _gen.Literal)("call"), true), [(0, _gen.ThisExpression)()])))); // Create all the functions needed
|
|
92
|
+
|
|
93
|
+
for (var blockNode of this.functions.keys()) {
|
|
94
|
+
var {
|
|
95
|
+
functionName,
|
|
96
|
+
indexShift
|
|
97
|
+
} = this.functions.get(blockNode);
|
|
98
|
+
var propertyNode = (0, _gen.BinaryExpression)("-", (0, _gen.Identifier)("index_param"), (0, _gen.Literal)(indexShift));
|
|
99
|
+
var indexRangeInclusive = [0 + indexShift - 1, this.map.size + indexShift]; // The function uses mangling to hide the index being accessed
|
|
100
|
+
|
|
101
|
+
var mangleCount = (0, _random.getRandomInteger)(1, 10);
|
|
102
|
+
|
|
103
|
+
for (var i = 0; i < mangleCount; i++) {
|
|
104
|
+
var operator = (0, _random.choice)([">", "<"]);
|
|
105
|
+
var compareValue = (0, _random.choice)(indexRangeInclusive);
|
|
106
|
+
var test = (0, _gen.BinaryExpression)(operator, (0, _gen.Identifier)("index_param"), (0, _gen.Literal)(compareValue));
|
|
107
|
+
var alternate = (0, _gen.BinaryExpression)("-", (0, _gen.Identifier)("index_param"), (0, _gen.Literal)((0, _random.getRandomInteger)(-100, 100)));
|
|
108
|
+
var testValue = operator === ">" && compareValue === indexRangeInclusive[0] || operator === "<" && compareValue === indexRangeInclusive[1];
|
|
109
|
+
propertyNode = (0, _gen.ConditionalExpression)(test, testValue ? propertyNode : alternate, !testValue ? propertyNode : alternate);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
var returnArgument = (0, _gen.MemberExpression)((0, _gen.Identifier)(this.arrayName), propertyNode, true);
|
|
113
|
+
(0, _insert.prepend)(blockNode, (0, _gen.FunctionDeclaration)(functionName, [(0, _gen.Identifier)("index_param")], [(0, _gen.ReturnStatement)(returnArgument)]));
|
|
114
|
+
}
|
|
84
115
|
}
|
|
85
116
|
}
|
|
86
117
|
|
|
@@ -95,43 +126,39 @@ class DuplicateLiteralsRemoval extends _transform.default {
|
|
|
95
126
|
*/
|
|
96
127
|
|
|
97
128
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
var getterNames = [object, ...parents].map(x => this.fnGetters.get(x)).filter(x => x); // use random getter function
|
|
129
|
+
transformLiteral(object, parents, index) {
|
|
130
|
+
var blockNode = (0, _random.choice)(parents.filter(x => this.functions.has(x))); // Create initial function if none exist
|
|
101
131
|
|
|
102
|
-
|
|
132
|
+
if (this.functions.size === 0) {
|
|
133
|
+
var root = parents[parents.length - 1];
|
|
134
|
+
var rootFunctionName = this.getPlaceholder() + "_dLR_0";
|
|
135
|
+
this.functions.set(root, {
|
|
136
|
+
functionName: rootFunctionName,
|
|
137
|
+
indexShift: (0, _random.getRandomInteger)(-100, 100)
|
|
138
|
+
});
|
|
139
|
+
blockNode = root;
|
|
140
|
+
} // If no function here exist, possibly create new chained function
|
|
103
141
|
|
|
104
|
-
var lexContext = (0, _insert.getLexContext)(object, parents);
|
|
105
|
-
var hasGetterHere = this.fnGetters.has(lexContext); // create one if none are available (or by random chance if none are here locally)
|
|
106
142
|
|
|
107
|
-
var
|
|
143
|
+
var block = (0, _traverse.getBlock)(object, parents);
|
|
108
144
|
|
|
109
|
-
if (
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
145
|
+
if (!this.functions.has(block) && (0, _random.chance)(50 - this.functions.size)) {
|
|
146
|
+
var newFunctionName = this.getPlaceholder() + "_dLR_" + this.functions.size;
|
|
147
|
+
this.functions.set(block, {
|
|
148
|
+
functionName: newFunctionName,
|
|
149
|
+
indexShift: (0, _random.getRandomInteger)(-100, 100)
|
|
150
|
+
});
|
|
151
|
+
blockNode = block;
|
|
152
|
+
} // Derive the function to call from the selected blockNode
|
|
115
153
|
|
|
116
|
-
getterName = this.getPlaceholder() + "_dLR_" + this.fnGetters.size;
|
|
117
154
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
this.fnShifts.set(getterName, shift + thisShift);
|
|
123
|
-
} else {
|
|
124
|
-
// from scratch
|
|
125
|
-
body = [(0, _gen.ReturnStatement)((0, _gen.MemberExpression)((0, _gen.Identifier)(this.arrayName), (0, _gen.BinaryExpression)("+", (0, _gen.Identifier)("index"), (0, _gen.Literal)(thisShift)), true))];
|
|
126
|
-
this.fnShifts.set(getterName, thisShift);
|
|
127
|
-
}
|
|
155
|
+
var {
|
|
156
|
+
functionName,
|
|
157
|
+
indexShift
|
|
158
|
+
} = this.functions.get(blockNode); // Call the function given it's indexShift
|
|
128
159
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
var theShift = this.fnShifts.get(getterName);
|
|
134
|
-
this.replaceIdentifierOrLiteral(object, (0, _gen.CallExpression)((0, _gen.Identifier)(getterName), [(0, _gen.Literal)(index - theShift)]), parents);
|
|
160
|
+
var callExpression = (0, _gen.CallExpression)((0, _gen.Identifier)(functionName), [(0, _gen.Literal)(index + indexShift)]);
|
|
161
|
+
this.replaceIdentifierOrLiteral(object, callExpression, parents);
|
|
135
162
|
}
|
|
136
163
|
|
|
137
164
|
transform(object, parents) {
|
|
@@ -144,19 +171,22 @@ class DuplicateLiteralsRemoval extends _transform.default {
|
|
|
144
171
|
|
|
145
172
|
if (!(0, _probability.ComputeProbabilityMap)(this.options.duplicateLiteralsRemoval)) {
|
|
146
173
|
return;
|
|
147
|
-
}
|
|
174
|
+
} // HARD CODED LIMIT of 10,000 (after 1,000 elements)
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
if (this.map.size > 1000 && (0, _random.chance)(this.map.size / 100)) return;
|
|
148
178
|
|
|
149
179
|
if (this.arrayName && parents[0].object && parents[0].object.name == this.arrayName) {
|
|
150
180
|
return;
|
|
151
181
|
}
|
|
152
182
|
|
|
153
|
-
var
|
|
183
|
+
var stringValue;
|
|
154
184
|
|
|
155
185
|
if (object.type == "Literal") {
|
|
156
|
-
|
|
186
|
+
stringValue = typeof object.value + ":" + object.value;
|
|
157
187
|
|
|
158
188
|
if (object.value === null) {
|
|
159
|
-
|
|
189
|
+
stringValue = "null:null";
|
|
160
190
|
} else {
|
|
161
191
|
// Skip empty strings
|
|
162
192
|
if (typeof object.value === "string" && !object.value) {
|
|
@@ -164,38 +194,42 @@ class DuplicateLiteralsRemoval extends _transform.default {
|
|
|
164
194
|
}
|
|
165
195
|
}
|
|
166
196
|
} else if (object.type == "Identifier") {
|
|
167
|
-
|
|
197
|
+
stringValue = "identifier:" + object.name;
|
|
168
198
|
} else {
|
|
169
199
|
throw new Error("Unsupported primitive type: " + object.type);
|
|
170
200
|
}
|
|
171
201
|
|
|
172
|
-
(0, _assert.ok)(
|
|
202
|
+
(0, _assert.ok)(stringValue);
|
|
173
203
|
|
|
174
|
-
if (
|
|
175
|
-
|
|
176
|
-
} else {
|
|
204
|
+
if (this.map.has(stringValue) || this.first.has(stringValue)) {
|
|
205
|
+
// Create the array if not already made
|
|
177
206
|
if (!this.arrayName) {
|
|
178
207
|
this.arrayName = this.getPlaceholder();
|
|
179
208
|
this.arrayExpression = (0, _gen.ArrayExpression)([]);
|
|
180
|
-
}
|
|
209
|
+
} // Delete with first location
|
|
181
210
|
|
|
182
|
-
|
|
211
|
+
|
|
212
|
+
var firstLocation = this.first.get(stringValue);
|
|
183
213
|
|
|
184
214
|
if (firstLocation) {
|
|
185
|
-
this.first.set(value, null);
|
|
186
215
|
var index = this.map.size;
|
|
187
|
-
(0, _assert.ok)(!this.map.has(
|
|
188
|
-
this.map.set(
|
|
216
|
+
(0, _assert.ok)(!this.map.has(stringValue));
|
|
217
|
+
this.map.set(stringValue, index);
|
|
218
|
+
this.first.delete(stringValue);
|
|
189
219
|
var pushing = (0, _insert.clone)(object);
|
|
190
220
|
this.arrayExpression.elements.push(pushing);
|
|
191
221
|
(0, _assert.ok)(this.arrayExpression.elements[index] === pushing);
|
|
192
|
-
this.
|
|
222
|
+
this.transformLiteral(firstLocation[0], firstLocation[1], index);
|
|
193
223
|
}
|
|
194
224
|
|
|
195
|
-
var index = this.map.get(
|
|
225
|
+
var index = this.map.get(stringValue);
|
|
196
226
|
(0, _assert.ok)(typeof index === "number");
|
|
197
|
-
this.
|
|
198
|
-
|
|
227
|
+
this.transformLiteral(object, parents, index);
|
|
228
|
+
return;
|
|
229
|
+
} // Save this, maybe a duplicate will be found.
|
|
230
|
+
|
|
231
|
+
|
|
232
|
+
this.first.set(stringValue, [object, parents]);
|
|
199
233
|
};
|
|
200
234
|
}
|
|
201
235
|
|