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.
Files changed (143) hide show
  1. package/.github/workflows/node.js.yml +2 -2
  2. package/CHANGELOG.md +55 -0
  3. package/README.md +346 -165
  4. package/dist/constants.js +6 -2
  5. package/dist/index.js +9 -21
  6. package/dist/obfuscator.js +19 -31
  7. package/dist/options.js +5 -5
  8. package/dist/order.js +1 -3
  9. package/dist/presets.js +6 -7
  10. package/dist/probability.js +2 -4
  11. package/dist/templates/bufferToString.js +13 -0
  12. package/dist/templates/crash.js +3 -3
  13. package/dist/templates/es5.js +18 -0
  14. package/dist/templates/functionLength.js +16 -0
  15. package/dist/transforms/calculator.js +77 -21
  16. package/dist/transforms/controlFlowFlattening/controlFlowFlattening.js +980 -367
  17. package/dist/transforms/controlFlowFlattening/expressionObfuscation.js +4 -1
  18. package/dist/transforms/controlFlowFlattening/switchCaseObfuscation.js +25 -26
  19. package/dist/transforms/deadCode.js +33 -25
  20. package/dist/transforms/dispatcher.js +8 -4
  21. package/dist/transforms/es5/antiDestructuring.js +2 -0
  22. package/dist/transforms/es5/es5.js +31 -34
  23. package/dist/transforms/extraction/duplicateLiteralsRemoval.js +92 -58
  24. package/dist/transforms/finalizer.js +82 -0
  25. package/dist/transforms/flatten.js +229 -148
  26. package/dist/transforms/identifier/globalAnalysis.js +88 -0
  27. package/dist/transforms/identifier/globalConcealing.js +10 -83
  28. package/dist/transforms/identifier/movedDeclarations.js +35 -88
  29. package/dist/transforms/identifier/renameVariables.js +124 -59
  30. package/dist/transforms/identifier/variableAnalysis.js +58 -62
  31. package/dist/transforms/lock/lock.js +0 -37
  32. package/dist/transforms/minify.js +60 -57
  33. package/dist/transforms/opaquePredicates.js +1 -1
  34. package/dist/transforms/preparation/preparation.js +2 -2
  35. package/dist/transforms/preparation.js +231 -0
  36. package/dist/transforms/renameLabels.js +1 -1
  37. package/dist/transforms/rgf.js +139 -247
  38. package/dist/transforms/stack.js +128 -26
  39. package/dist/transforms/string/encoding.js +150 -179
  40. package/dist/transforms/string/stringCompression.js +14 -15
  41. package/dist/transforms/string/stringConcealing.js +25 -8
  42. package/dist/transforms/string/stringEncoding.js +13 -24
  43. package/dist/transforms/transform.js +12 -19
  44. package/dist/traverse.js +24 -10
  45. package/dist/util/gen.js +17 -1
  46. package/dist/util/identifiers.js +37 -3
  47. package/dist/util/insert.js +35 -4
  48. package/dist/util/random.js +15 -0
  49. package/docs/ControlFlowFlattening.md +595 -0
  50. package/{Countermeasures.md → docs/Countermeasures.md} +1 -15
  51. package/{Integrity.md → docs/Integrity.md} +2 -2
  52. package/docs/RGF.md +419 -0
  53. package/package.json +5 -5
  54. package/src/constants.ts +3 -0
  55. package/src/index.ts +2 -2
  56. package/src/obfuscator.ts +19 -31
  57. package/src/options.ts +14 -103
  58. package/src/order.ts +1 -5
  59. package/src/presets.ts +6 -7
  60. package/src/probability.ts +2 -3
  61. package/src/templates/bufferToString.ts +68 -0
  62. package/src/templates/crash.ts +15 -19
  63. package/src/templates/es5.ts +131 -0
  64. package/src/templates/functionLength.ts +14 -0
  65. package/src/transforms/calculator.ts +122 -59
  66. package/src/transforms/controlFlowFlattening/controlFlowFlattening.ts +1583 -571
  67. package/src/transforms/controlFlowFlattening/expressionObfuscation.ts +4 -1
  68. package/src/transforms/deadCode.ts +383 -26
  69. package/src/transforms/dispatcher.ts +9 -4
  70. package/src/transforms/es5/antiDestructuring.ts +2 -0
  71. package/src/transforms/es5/es5.ts +32 -77
  72. package/src/transforms/extraction/duplicateLiteralsRemoval.ts +133 -129
  73. package/src/transforms/{hexadecimalNumbers.ts → finalizer.ts} +29 -13
  74. package/src/transforms/flatten.ts +357 -300
  75. package/src/transforms/identifier/globalAnalysis.ts +85 -0
  76. package/src/transforms/identifier/globalConcealing.ts +14 -103
  77. package/src/transforms/identifier/movedDeclarations.ts +49 -102
  78. package/src/transforms/identifier/renameVariables.ts +149 -78
  79. package/src/transforms/identifier/variableAnalysis.ts +66 -73
  80. package/src/transforms/lock/lock.ts +1 -42
  81. package/src/transforms/minify.ts +91 -75
  82. package/src/transforms/opaquePredicates.ts +2 -2
  83. package/src/transforms/preparation.ts +238 -0
  84. package/src/transforms/renameLabels.ts +2 -2
  85. package/src/transforms/rgf.ts +213 -405
  86. package/src/transforms/stack.ts +156 -36
  87. package/src/transforms/string/encoding.ts +115 -212
  88. package/src/transforms/string/stringCompression.ts +27 -18
  89. package/src/transforms/string/stringConcealing.ts +39 -9
  90. package/src/transforms/string/stringEncoding.ts +18 -18
  91. package/src/transforms/transform.ts +21 -23
  92. package/src/traverse.ts +23 -4
  93. package/src/types.ts +2 -1
  94. package/src/util/gen.ts +28 -3
  95. package/src/util/identifiers.ts +43 -2
  96. package/src/util/insert.ts +38 -3
  97. package/src/util/random.ts +13 -0
  98. package/test/code/Cash.test.ts +1 -1
  99. package/test/code/Dynamic.test.ts +12 -10
  100. package/test/code/ES6.src.js +146 -0
  101. package/test/code/ES6.test.ts +28 -2
  102. package/test/index.test.ts +2 -1
  103. package/test/probability.test.ts +44 -0
  104. package/test/templates/template.test.ts +1 -1
  105. package/test/transforms/antiTooling.test.ts +22 -0
  106. package/test/transforms/calculator.test.ts +40 -0
  107. package/test/transforms/controlFlowFlattening/controlFlowFlattening.test.ts +702 -160
  108. package/test/transforms/controlFlowFlattening/expressionObfuscation.test.ts +173 -0
  109. package/test/transforms/deadCode.test.ts +66 -15
  110. package/test/transforms/dispatcher.test.ts +20 -1
  111. package/test/transforms/es5/antiDestructuring.test.ts +16 -0
  112. package/test/transforms/flatten.test.ts +399 -86
  113. package/test/transforms/identifier/movedDeclarations.test.ts +63 -8
  114. package/test/transforms/identifier/renameVariables.test.ts +119 -0
  115. package/test/transforms/lock/antiDebug.test.ts +2 -2
  116. package/test/transforms/lock/lock.test.ts +1 -48
  117. package/test/transforms/minify.test.ts +104 -0
  118. package/test/transforms/preparation.test.ts +157 -0
  119. package/test/transforms/rgf.test.ts +261 -381
  120. package/test/transforms/stack.test.ts +143 -21
  121. package/test/transforms/string/stringCompression.test.ts +39 -0
  122. package/test/transforms/string/stringConcealing.test.ts +82 -0
  123. package/test/transforms/string/stringEncoding.test.ts +53 -2
  124. package/test/transforms/transform.test.ts +66 -0
  125. package/test/traverse.test.ts +139 -0
  126. package/test/util/identifiers.test.ts +113 -1
  127. package/test/util/insert.test.ts +57 -3
  128. package/src/transforms/controlFlowFlattening/choiceFlowObfuscation.ts +0 -87
  129. package/src/transforms/controlFlowFlattening/controlFlowObfuscation.ts +0 -203
  130. package/src/transforms/controlFlowFlattening/switchCaseObfuscation.ts +0 -130
  131. package/src/transforms/eval.ts +0 -89
  132. package/src/transforms/hideInitializingCode.ts +0 -432
  133. package/src/transforms/identifier/nameRecycling.ts +0 -280
  134. package/src/transforms/label.ts +0 -64
  135. package/src/transforms/preparation/nameConflicts.ts +0 -102
  136. package/src/transforms/preparation/preparation.ts +0 -176
  137. package/test/transforms/controlFlowFlattening/controlFlowObfuscation.test.ts +0 -101
  138. package/test/transforms/controlFlowFlattening/switchCaseObfuscation.test.ts +0 -120
  139. package/test/transforms/eval.test.ts +0 -131
  140. package/test/transforms/hideInitializingCode.test.ts +0 -336
  141. package/test/transforms/identifier/nameRecycling.test.ts +0 -205
  142. package/test/transforms/preparation/nameConflicts.test.ts +0 -52
  143. package/test/transforms/preparation/preparation.test.ts +0 -62
@@ -1,4 +1,7 @@
1
- import parseJS from "../../src/parser";
1
+ import { ok } from "assert";
2
+ import parseJS, { parseSync } from "../../src/parser";
3
+ import traverse from "../../src/traverse";
4
+ import { Location, Node } from "../../src/util/gen";
2
5
  import {
3
6
  getFunctionParameters,
4
7
  getIdentifierInfo,
@@ -41,6 +44,115 @@ describe("getIdentifierInfo", () => {
41
44
  getIdentifierInfo({ type: "Literal", value: true }, []);
42
45
  }).toThrow();
43
46
  });
47
+
48
+ function findIdentifier(tree: Node, identifierName: string) {
49
+ var searchLocation: Location;
50
+
51
+ traverse(tree, (o, p) => {
52
+ if (o.type === "Identifier" && o.name === identifierName) {
53
+ ok(!searchLocation);
54
+ searchLocation = [o, p];
55
+ }
56
+ });
57
+
58
+ ok(searchLocation);
59
+ return searchLocation;
60
+ }
61
+
62
+ test("Variant #4: Variable declaration assignment pattern", async () => {
63
+ var tree = parseSync(`
64
+ var [ definedIdentifier = nonDefinedIdentifier ] = [];
65
+ `);
66
+
67
+ var definedIdentifier = findIdentifier(tree, "definedIdentifier");
68
+ var definedInfo = getIdentifierInfo(
69
+ definedIdentifier[0],
70
+ definedIdentifier[1]
71
+ );
72
+ expect(definedInfo.spec.isDefined).toStrictEqual(true);
73
+ expect(definedInfo.spec.isReferenced).toStrictEqual(true);
74
+
75
+ var nonDefinedIdentifier = findIdentifier(tree, "nonDefinedIdentifier");
76
+ var nonDefinedInfo = getIdentifierInfo(
77
+ nonDefinedIdentifier[0],
78
+ nonDefinedIdentifier[1]
79
+ );
80
+ expect(nonDefinedInfo.spec.isDefined).toStrictEqual(false);
81
+ expect(nonDefinedInfo.spec.isReferenced).toStrictEqual(true);
82
+ });
83
+
84
+ test("Variant #5: Function parameter assignment pattern", async () => {
85
+ var tree = parseSync(`
86
+ function myFunction(definedIdentifier = nonDefinedIdentifier) {
87
+
88
+ }
89
+ `);
90
+
91
+ var myFunction = findIdentifier(tree, "myFunction");
92
+ var myFunctionInfo = getIdentifierInfo(myFunction[0], myFunction[1]);
93
+
94
+ expect(myFunctionInfo.isFunctionDeclaration).toStrictEqual(true);
95
+ expect(myFunctionInfo.spec.isDefined).toStrictEqual(true);
96
+
97
+ var definedIdentifier = findIdentifier(tree, "definedIdentifier");
98
+ var definedInfo = getIdentifierInfo(
99
+ definedIdentifier[0],
100
+ definedIdentifier[1]
101
+ );
102
+ expect(definedInfo.spec.isDefined).toStrictEqual(true);
103
+ expect(definedInfo.spec.isReferenced).toStrictEqual(true);
104
+
105
+ var nonDefinedIdentifier = findIdentifier(tree, "nonDefinedIdentifier");
106
+ var nonDefinedInfo = getIdentifierInfo(
107
+ nonDefinedIdentifier[0],
108
+ nonDefinedIdentifier[1]
109
+ );
110
+ expect(nonDefinedInfo.spec.isDefined).toStrictEqual(false);
111
+ expect(nonDefinedInfo.spec.isReferenced).toStrictEqual(true);
112
+ });
113
+
114
+ test("Variant #6: Object pattern", async () => {
115
+ var tree = parseSync(`
116
+ var { nonDefinedIdentifier: definedIdentifier } = {};
117
+
118
+ ( { nonModifiedIdentifier: modifiedIdentifier } = {} );
119
+ `);
120
+
121
+ var definedIdentifier = findIdentifier(tree, "definedIdentifier");
122
+ var definedInfo = getIdentifierInfo(
123
+ definedIdentifier[0],
124
+ definedIdentifier[1]
125
+ );
126
+ expect(definedInfo.spec.isDefined).toStrictEqual(true);
127
+ expect(definedInfo.spec.isReferenced).toStrictEqual(true);
128
+
129
+ var nonDefinedIdentifier = findIdentifier(tree, "nonDefinedIdentifier");
130
+ var nonDefinedInfo = getIdentifierInfo(
131
+ nonDefinedIdentifier[0],
132
+ nonDefinedIdentifier[1]
133
+ );
134
+ expect(nonDefinedInfo.spec.isDefined).toStrictEqual(false);
135
+ expect(nonDefinedInfo.spec.isReferenced).toStrictEqual(false);
136
+
137
+ var modifiedIdentifier = findIdentifier(tree, "modifiedIdentifier");
138
+ var modifiedInfo = getIdentifierInfo(
139
+ modifiedIdentifier[0],
140
+ modifiedIdentifier[1]
141
+ );
142
+ expect(modifiedInfo.spec.isDefined).toStrictEqual(false);
143
+ expect(modifiedInfo.spec.isModified).toStrictEqual(true);
144
+ expect(modifiedInfo.spec.isReferenced).toStrictEqual(true);
145
+
146
+ var nonModifiedIdentifier = findIdentifier(tree, "nonModifiedIdentifier");
147
+ var nonModifiedInfo = getIdentifierInfo(
148
+ nonModifiedIdentifier[0],
149
+ nonModifiedIdentifier[1]
150
+ );
151
+
152
+ expect(nonModifiedInfo.spec.isDefined).toStrictEqual(false);
153
+ expect(nonModifiedInfo.spec.isModified).toStrictEqual(false);
154
+ expect(nonModifiedInfo.spec.isReferenced).toStrictEqual(false);
155
+ });
44
156
  });
45
157
 
46
158
  describe("validateChain", () => {
@@ -1,7 +1,8 @@
1
+ import { ok } from "assert";
1
2
  import { compileJsSync } from "../../src/compiler";
2
- import parseJS from "../../src/parser";
3
- import { isBlock } from "../../src/traverse";
4
- import { Identifier } from "../../src/util/gen";
3
+ import parseJS, { parseSync } from "../../src/parser";
4
+ import traverse, { isBlock } from "../../src/traverse";
5
+ import { Identifier, Location } from "../../src/util/gen";
5
6
  import {
6
7
  deleteDeclaration,
7
8
  isVarContext,
@@ -10,6 +11,7 @@ import {
10
11
  getContexts,
11
12
  getLexContext,
12
13
  getVarContext,
14
+ computeFunctionLength,
13
15
  } from "../../src/util/insert";
14
16
 
15
17
  it("isBlock() should be true for block statements and program", async () => {
@@ -86,3 +88,55 @@ it("should throw when missing parameters", () => {
86
88
  expect(() => getLexContext(Identifier("test"), [])).toThrow();
87
89
  expect(() => getVarContext(Identifier("test"), [])).toThrow();
88
90
  });
91
+
92
+ test("computeFunctionLength", () => {
93
+ var tree = parseSync(`
94
+ function zeroParameters(){}; // 0
95
+ function oneParameter(a){}; // 1
96
+ function twoParameter(a,b){}; // 2
97
+ function restParameter1(...a){}; // 0
98
+ function restParameter2(a,b,...c){}; // 2
99
+ function defaultValue(a,b,c=1,d){}; // 2
100
+ function arrayPattern([a],[b = 2],[[c]]){}; // 3
101
+ function objectPattern({a},{b = 2},{c, d}){}; // 3
102
+ function mixed(a,{b},[c = 3],d,e=5,f,...g){}; // 4
103
+ `);
104
+
105
+ function getFunction(searchName: string): Location {
106
+ var searchLocation: Location;
107
+ traverse(tree, (o, p) => {
108
+ if (o.type === "FunctionDeclaration" && o.id.name === searchName) {
109
+ ok(!searchLocation);
110
+ searchLocation = [o, p];
111
+ }
112
+ });
113
+
114
+ ok(searchLocation);
115
+ return searchLocation;
116
+ }
117
+
118
+ expect(
119
+ computeFunctionLength(getFunction("zeroParameters")[0].params)
120
+ ).toStrictEqual(0);
121
+ expect(
122
+ computeFunctionLength(getFunction("oneParameter")[0].params)
123
+ ).toStrictEqual(1);
124
+ expect(
125
+ computeFunctionLength(getFunction("twoParameter")[0].params)
126
+ ).toStrictEqual(2);
127
+ expect(
128
+ computeFunctionLength(getFunction("restParameter1")[0].params)
129
+ ).toStrictEqual(0);
130
+ expect(
131
+ computeFunctionLength(getFunction("restParameter2")[0].params)
132
+ ).toStrictEqual(2);
133
+ expect(
134
+ computeFunctionLength(getFunction("arrayPattern")[0].params)
135
+ ).toStrictEqual(3);
136
+ expect(
137
+ computeFunctionLength(getFunction("objectPattern")[0].params)
138
+ ).toStrictEqual(3);
139
+ expect(computeFunctionLength(getFunction("mixed")[0].params)).toStrictEqual(
140
+ 4
141
+ );
142
+ });
@@ -1,87 +0,0 @@
1
- import {
2
- AssignmentExpression,
3
- BlockStatement,
4
- CatchClause,
5
- ExpressionStatement,
6
- Identifier,
7
- IfStatement,
8
- Literal,
9
- ThrowStatement,
10
- TryStatement,
11
- UnaryExpression,
12
- VariableDeclaration,
13
- VariableDeclarator,
14
- } from "../../util/gen";
15
- import Transform from "../transform";
16
-
17
- export default class ChoiceFlowObfuscation extends Transform {
18
- constructor(o) {
19
- super(o);
20
- }
21
-
22
- match(object, parents) {
23
- return object.type == "IfStatement";
24
- }
25
-
26
- transform(object, parents) {
27
- return () => {
28
- var body = parents[0];
29
- var element = object;
30
- if (parents[0].type == "LabeledStatement") {
31
- body = parents[1];
32
- element = parents[0];
33
- }
34
-
35
- var before = [];
36
-
37
- var isNested =
38
- parents[0].type == "IfStatement" && parents[0].alternate === object;
39
-
40
- if (!isNested && (!Array.isArray(body) || body.indexOf(element) === -1)) {
41
- return;
42
- }
43
-
44
- var result = this.getPlaceholder();
45
- before.push(VariableDeclaration(VariableDeclarator(result)));
46
-
47
- var yesBody = object.consequent
48
- ? object.consequent.type == "BlockStatement"
49
- ? [...object.consequent.body]
50
- : [object.consequent]
51
- : [];
52
-
53
- yesBody.unshift(
54
- ExpressionStatement(
55
- AssignmentExpression("=", Identifier(result), Literal(1))
56
- )
57
- );
58
-
59
- var noBody = object.alternate
60
- ? object.alternate.type == "BlockStatement"
61
- ? [...object.alternate.body]
62
- : [object.alternate]
63
- : [];
64
-
65
- noBody.unshift(
66
- ExpressionStatement(
67
- AssignmentExpression("=", Identifier(result), Literal(1))
68
- )
69
- );
70
-
71
- var elseTest = UnaryExpression("!", Identifier(result));
72
-
73
- var newObject = TryStatement(
74
- [IfStatement({ ...object.test }, [ThrowStatement(Identifier(result))])],
75
- CatchClause(Identifier(this.getPlaceholder()), yesBody),
76
- [IfStatement(elseTest, noBody)]
77
- );
78
-
79
- if (isNested) {
80
- this.replace(object, BlockStatement([...before, { ...newObject }]));
81
- } else {
82
- body.splice(body.indexOf(element), 0, ...before);
83
- this.replace(object, newObject);
84
- }
85
- };
86
- }
87
- }
@@ -1,203 +0,0 @@
1
- import { ok } from "assert";
2
- import { ComputeProbabilityMap } from "../../probability";
3
- import { walk } from "../../traverse";
4
- import {
5
- AssignmentExpression,
6
- BinaryExpression,
7
- BreakStatement,
8
- ExpressionStatement,
9
- Identifier,
10
- IfStatement,
11
- Literal,
12
- Node,
13
- SwitchCase,
14
- SwitchStatement,
15
- VariableDeclaration,
16
- VariableDeclarator,
17
- WhileStatement,
18
- } from "../../util/gen";
19
- import { containsLexicallyBoundVariables } from "../../util/identifiers";
20
- import { clone, getBlockBody } from "../../util/insert";
21
- import { getRandomInteger, shuffle } from "../../util/random";
22
- import Transform from "../transform";
23
-
24
- /**
25
- * Obfuscates For and While statements.
26
- */
27
- export default class ControlFlowObfuscation extends Transform {
28
- constructor(o) {
29
- super(o);
30
- }
31
-
32
- match(object: Node, parents: Node[]) {
33
- return object.type === "ForStatement" || object.type === "WhileStatement";
34
- }
35
-
36
- transform(object: Node, parents: Node[]) {
37
- return () => {
38
- if (object.$controlFlowObfuscation) {
39
- // avoid infinite loop
40
- return;
41
- }
42
-
43
- if (containsLexicallyBoundVariables(object, parents)) {
44
- return;
45
- }
46
-
47
- var illegal = false;
48
- walk(object, parents, (o, p) => {
49
- if (o.type == "FunctionDeclaration" || o.type == "BreakStatement") {
50
- illegal = true;
51
- return "EXIT";
52
- }
53
- });
54
-
55
- if (illegal) {
56
- return;
57
- }
58
-
59
- var body =
60
- parents[0].type == "LabeledStatement" ? parents[1] : parents[0];
61
- var element = parents[0].type == "LabeledStatement" ? parents[0] : object;
62
-
63
- // No place to insert more statements
64
- if (!Array.isArray(body)) {
65
- return;
66
- }
67
-
68
- // No place to insert variable declaration
69
- if (body.indexOf(element) === -1) {
70
- return;
71
- }
72
-
73
- if (
74
- !ComputeProbabilityMap(this.options.controlFlowFlattening, (x) => x)
75
- ) {
76
- return;
77
- }
78
-
79
- var init = [];
80
- var update = [];
81
- var test: Node = null;
82
- var consequent = [];
83
-
84
- if (object.type === "ForStatement") {
85
- if (object.init) {
86
- init.push(object.init);
87
- }
88
- if (object.update) {
89
- update.push(ExpressionStatement(object.update));
90
- }
91
- if (object.test) {
92
- test = object.test || Literal(true);
93
- }
94
- } else if (object.type === "WhileStatement") {
95
- if (object.test) {
96
- test = object.test;
97
- }
98
- } else {
99
- throw new Error("Unknown type: " + object.type);
100
- }
101
-
102
- if (object.body.type == "BlockStatement") {
103
- consequent.push(...getBlockBody(object.body));
104
- } else {
105
- consequent.push(object.body);
106
- }
107
-
108
- if (!test) {
109
- test = Literal(true);
110
- }
111
-
112
- ok(test);
113
-
114
- init.forEach((o) => {
115
- if (
116
- o.type !== "VariableDeclaration" &&
117
- o.type !== "ExpressionStatement"
118
- ) {
119
- this.replace(o, ExpressionStatement(clone(o)));
120
- }
121
- });
122
-
123
- var stateVar = this.getPlaceholder();
124
-
125
- var selection = new Set();
126
-
127
- // init 0 test 1 run 2 update 3 end 4
128
- var states: number[] = [];
129
-
130
- // Create 5 random unique number
131
- while (states.length < 5) {
132
- var newState;
133
- do {
134
- newState = getRandomInteger(0, 1000 + states.length);
135
- } while (selection.has(newState));
136
-
137
- ok(!isNaN(newState));
138
-
139
- states.push(newState);
140
- selection.add(newState);
141
- }
142
- ok(selection.size === states.length);
143
- ok(states.length === 5);
144
-
145
- var startState = states[0];
146
- var testState = states[1];
147
- var bodyState = states[2];
148
- var updateState = states[3];
149
- var endState = states[4];
150
-
151
- body.splice(
152
- body.indexOf(element),
153
- 0,
154
- VariableDeclaration(VariableDeclarator(stateVar, Literal(startState)))
155
- );
156
-
157
- function goto(from: number, to: number) {
158
- var diff = to - from;
159
- ok(!isNaN(diff));
160
- return ExpressionStatement(
161
- AssignmentExpression("+=", Identifier(stateVar), Literal(diff))
162
- );
163
- }
164
-
165
- var cases = [
166
- SwitchCase(Literal(startState), [
167
- ...init,
168
- goto(startState, testState),
169
- BreakStatement(),
170
- ]),
171
- SwitchCase(Literal(testState), [
172
- IfStatement(
173
- test,
174
- [goto(testState, bodyState)],
175
- [goto(testState, endState)]
176
- ),
177
- BreakStatement(),
178
- ]),
179
- SwitchCase(Literal(bodyState), [
180
- ...consequent,
181
- goto(bodyState, updateState),
182
- BreakStatement(),
183
- ]),
184
- SwitchCase(Literal(updateState), [
185
- ...update,
186
- goto(updateState, testState),
187
- BreakStatement(),
188
- ]),
189
- ];
190
-
191
- this.replace(
192
- object,
193
- WhileStatement(
194
- BinaryExpression("!=", Identifier(stateVar), Literal(endState)),
195
- [SwitchStatement(Identifier(stateVar), cases)]
196
- )
197
- );
198
-
199
- // Marked to not be infinite
200
- object.$controlFlowObfuscation = 1;
201
- };
202
- }
203
- }
@@ -1,130 +0,0 @@
1
- import Template from "../../templates/template";
2
- import { walk } from "../../traverse";
3
- import {
4
- BinaryExpression,
5
- Identifier,
6
- Literal,
7
- VariableDeclaration,
8
- VariableDeclarator,
9
- } from "../../util/gen";
10
- import { clone } from "../../util/insert";
11
- import { getRandomInteger } from "../../util/random";
12
- import Transform from "../transform";
13
-
14
- /**
15
- * Does complex math to the state variable, after both CFF and CFO have run.
16
- *
17
- * The switch statements are ones with numbered cases and a simple discriminant.
18
- */
19
- export default class SwitchCaseObfuscation extends Transform {
20
- constructor(o) {
21
- super(o);
22
- }
23
-
24
- match(object, parents) {
25
- return (
26
- object.type == "SwitchStatement" &&
27
- !object.cases.find(
28
- (x) =>
29
- !(
30
- x.test &&
31
- typeof x.test === "object" &&
32
- x.test.type == "Literal" &&
33
- typeof x.test.value === "number" &&
34
- Math.abs(x.test.value) < 100_000
35
- )
36
- )
37
- );
38
- }
39
-
40
- transform(object, parents) {
41
- var types = new Set();
42
- walk(object.discriminant, [object, ...parents], (o, p) => {
43
- if (o.type) {
44
- if (
45
- object.$controlFlowFlattening &&
46
- o.type == "BinaryExpression" &&
47
- o.operator === "+"
48
- ) {
49
- } else {
50
- types.add(o.type);
51
- }
52
- }
53
- });
54
-
55
- types.delete("Identifier");
56
- if (types.size) {
57
- return;
58
- }
59
-
60
- var body = parents[0];
61
- var element = object;
62
-
63
- if (parents[0].type == "LabeledStatement") {
64
- body = parents[1];
65
- element = parents[0];
66
- }
67
-
68
- if (!Array.isArray(body)) {
69
- return;
70
- }
71
-
72
- var index = body.indexOf(element);
73
- if (index === -1) {
74
- return;
75
- }
76
-
77
- var factor = getRandomInteger(-150, 150);
78
- if (factor == 0) {
79
- factor = 2;
80
- }
81
- var offset = getRandomInteger(-250, 250);
82
-
83
- var newVar = this.getPlaceholder();
84
-
85
- var newStates = [];
86
- var max;
87
- object.cases.forEach((x) => {
88
- var current = x.test.value;
89
- var value = current * factor + offset;
90
-
91
- newStates.push(value);
92
- if (!max || Math.abs(value) > max) {
93
- max = Math.abs(value);
94
- }
95
- });
96
-
97
- if (max > 100_000) {
98
- return;
99
- }
100
-
101
- if (new Set(newStates).size !== newStates.length) {
102
- // not possible because of clashing case test
103
- return;
104
- }
105
-
106
- // State variable declaration
107
- body.splice(
108
- index,
109
- 0,
110
- VariableDeclaration(
111
- VariableDeclarator(
112
- newVar,
113
-
114
- BinaryExpression(
115
- "+",
116
- BinaryExpression("*", clone(object.discriminant), Literal(factor)),
117
- Literal(offset)
118
- )
119
- )
120
- )
121
- );
122
-
123
- object.discriminant = Identifier(newVar);
124
-
125
- // possible so override
126
- object.cases.forEach((x, i) => {
127
- x.test = Literal(newStates[i]);
128
- });
129
- }
130
- }
@@ -1,89 +0,0 @@
1
- import { compileJsSync } from "../compiler";
2
- import { ObfuscateOrder } from "../order";
3
- import { ComputeProbabilityMap } from "../probability";
4
- import { isBlock } from "../traverse";
5
- import {
6
- CallExpression,
7
- Identifier,
8
- Literal,
9
- Node,
10
- VariableDeclaration,
11
- VariableDeclarator,
12
- } from "../util/gen";
13
- import { isFunction, prepend } from "../util/insert";
14
- import Transform from "./transform";
15
-
16
- export default class Eval extends Transform {
17
- constructor(o) {
18
- super(o, ObfuscateOrder.Eval);
19
- }
20
-
21
- match(object, parents) {
22
- return (
23
- isFunction(object) &&
24
- object.type != "ArrowFunctionExpression" &&
25
- !object.$eval &&
26
- !object.$dispatcherSkip
27
- );
28
- }
29
-
30
- transform(object, parents) {
31
- // Don't apply to getter/setters or class methods
32
- if (parents[0]) {
33
- if (
34
- parents[0].type === "MethodDefinition" &&
35
- parents[0].value === object
36
- ) {
37
- return;
38
- }
39
-
40
- if (
41
- parents[0].type === "Property" &&
42
- parents[0].value === object &&
43
- (parents[0].kind !== "init" || parents[0].method)
44
- ) {
45
- return;
46
- }
47
- }
48
-
49
- if (
50
- !ComputeProbabilityMap(
51
- this.options.eval,
52
- (x) => x,
53
- object.id && object.id.name
54
- )
55
- ) {
56
- return;
57
- }
58
-
59
- object.$eval = (o, p) => {
60
- var name;
61
- var requiresMove = false;
62
- if (object.type == "FunctionDeclaration") {
63
- name = object.id.name;
64
- object.type = "FunctionExpression";
65
- object.id = null;
66
- requiresMove = Array.isArray(p[0]) && isBlock(p[1]);
67
- }
68
-
69
- var code = compileJsSync(object, this.options);
70
- if (object.type == "FunctionExpression") {
71
- code = "(" + code + ")";
72
- }
73
-
74
- var literal = Literal(code);
75
-
76
- var expr: Node = CallExpression(Identifier("eval"), [literal]);
77
- if (name) {
78
- expr = VariableDeclaration(VariableDeclarator(name, expr));
79
- }
80
-
81
- if (requiresMove) {
82
- prepend(p[1], expr);
83
- p[0].splice(p[0].indexOf(object), 1);
84
- } else {
85
- this.replace(object, expr);
86
- }
87
- };
88
- }
89
- }