js-confuser 1.7.3 → 2.0.0-alpha.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 (269) hide show
  1. package/.github/ISSUE_TEMPLATE/bug_report.md +6 -4
  2. package/CHANGELOG.md +70 -0
  3. package/Migration.md +57 -0
  4. package/README.md +23 -929
  5. package/dist/constants.js +65 -14
  6. package/dist/index.js +108 -160
  7. package/dist/obfuscator.js +316 -118
  8. package/dist/options.js +1 -119
  9. package/dist/order.js +30 -30
  10. package/dist/presets.js +47 -45
  11. package/dist/probability.js +25 -32
  12. package/dist/templates/bufferToStringTemplate.js +9 -0
  13. package/dist/templates/deadCodeTemplates.js +9 -0
  14. package/dist/templates/getGlobalTemplate.js +19 -0
  15. package/dist/templates/integrityTemplate.js +30 -0
  16. package/dist/templates/setFunctionLengthTemplate.js +9 -0
  17. package/dist/templates/stringCompressionTemplate.js +10 -0
  18. package/dist/templates/tamperProtectionTemplates.js +21 -0
  19. package/dist/templates/template.js +199 -184
  20. package/dist/transforms/astScrambler.js +100 -0
  21. package/dist/transforms/calculator.js +70 -127
  22. package/dist/transforms/controlFlowFlattening.js +1182 -0
  23. package/dist/transforms/deadCode.js +62 -587
  24. package/dist/transforms/dispatcher.js +300 -313
  25. package/dist/transforms/extraction/duplicateLiteralsRemoval.js +88 -189
  26. package/dist/transforms/extraction/objectExtraction.js +131 -215
  27. package/dist/transforms/finalizer.js +56 -59
  28. package/dist/transforms/flatten.js +275 -276
  29. package/dist/transforms/functionOutlining.js +230 -0
  30. package/dist/transforms/identifier/globalConcealing.js +214 -135
  31. package/dist/transforms/identifier/movedDeclarations.js +167 -91
  32. package/dist/transforms/identifier/renameVariables.js +239 -193
  33. package/dist/transforms/lock/integrity.js +61 -184
  34. package/dist/transforms/lock/lock.js +261 -387
  35. package/dist/transforms/minify.js +431 -436
  36. package/dist/transforms/opaquePredicates.js +65 -118
  37. package/dist/transforms/pack.js +160 -0
  38. package/dist/transforms/plugin.js +179 -0
  39. package/dist/transforms/preparation.js +261 -173
  40. package/dist/transforms/renameLabels.js +132 -56
  41. package/dist/transforms/rgf.js +140 -267
  42. package/dist/transforms/shuffle.js +52 -145
  43. package/dist/transforms/string/encoding.js +44 -175
  44. package/dist/transforms/string/stringCompression.js +79 -155
  45. package/dist/transforms/string/stringConcealing.js +189 -225
  46. package/dist/transforms/string/stringEncoding.js +32 -40
  47. package/dist/transforms/string/stringSplitting.js +54 -55
  48. package/dist/transforms/variableMasking.js +232 -0
  49. package/dist/utils/ControlObject.js +125 -0
  50. package/dist/utils/IntGen.js +46 -0
  51. package/dist/utils/NameGen.js +106 -0
  52. package/dist/utils/ast-utils.js +560 -0
  53. package/dist/utils/function-utils.js +56 -0
  54. package/dist/utils/gen-utils.js +48 -0
  55. package/dist/utils/node.js +77 -0
  56. package/dist/utils/object-utils.js +21 -0
  57. package/dist/utils/random-utils.js +91 -0
  58. package/dist/utils/static-utils.js +64 -0
  59. package/dist/validateOptions.js +122 -0
  60. package/index.d.ts +1 -17
  61. package/package.json +27 -22
  62. package/src/constants.ts +139 -82
  63. package/src/index.ts +70 -165
  64. package/src/obfuscationResult.ts +43 -0
  65. package/src/obfuscator.ts +328 -135
  66. package/src/options.ts +149 -658
  67. package/src/order.ts +14 -14
  68. package/src/presets.ts +39 -34
  69. package/src/probability.ts +21 -36
  70. package/src/templates/bufferToStringTemplate.ts +57 -0
  71. package/src/templates/deadCodeTemplates.ts +1185 -0
  72. package/src/templates/getGlobalTemplate.ts +72 -0
  73. package/src/templates/integrityTemplate.ts +69 -0
  74. package/src/templates/setFunctionLengthTemplate.ts +11 -0
  75. package/src/templates/stringCompressionTemplate.ts +42 -0
  76. package/src/templates/tamperProtectionTemplates.ts +116 -0
  77. package/src/templates/template.ts +149 -157
  78. package/src/transforms/astScrambler.ts +99 -0
  79. package/src/transforms/calculator.ts +96 -226
  80. package/src/transforms/controlFlowFlattening.ts +1594 -0
  81. package/src/transforms/deadCode.ts +85 -676
  82. package/src/transforms/dispatcher.ts +431 -640
  83. package/src/transforms/extraction/duplicateLiteralsRemoval.ts +147 -295
  84. package/src/transforms/extraction/objectExtraction.ts +160 -333
  85. package/src/transforms/finalizer.ts +63 -64
  86. package/src/transforms/flatten.ts +439 -557
  87. package/src/transforms/functionOutlining.ts +225 -0
  88. package/src/transforms/identifier/globalConcealing.ts +255 -266
  89. package/src/transforms/identifier/movedDeclarations.ts +228 -142
  90. package/src/transforms/identifier/renameVariables.ts +250 -271
  91. package/src/transforms/lock/integrity.ts +85 -263
  92. package/src/transforms/lock/lock.ts +338 -579
  93. package/src/transforms/minify.ts +523 -663
  94. package/src/transforms/opaquePredicates.ts +90 -229
  95. package/src/transforms/pack.ts +195 -0
  96. package/src/transforms/plugin.ts +185 -0
  97. package/src/transforms/preparation.ts +337 -231
  98. package/src/transforms/renameLabels.ts +176 -77
  99. package/src/transforms/rgf.ts +293 -424
  100. package/src/transforms/shuffle.ts +80 -254
  101. package/src/transforms/string/encoding.ts +20 -126
  102. package/src/transforms/string/stringCompression.ts +117 -307
  103. package/src/transforms/string/stringConcealing.ts +254 -342
  104. package/src/transforms/string/stringEncoding.ts +28 -47
  105. package/src/transforms/string/stringSplitting.ts +61 -75
  106. package/src/transforms/variableMasking.ts +257 -0
  107. package/src/utils/ControlObject.ts +141 -0
  108. package/src/utils/IntGen.ts +33 -0
  109. package/src/utils/NameGen.ts +106 -0
  110. package/src/utils/ast-utils.ts +667 -0
  111. package/src/utils/function-utils.ts +50 -0
  112. package/src/utils/gen-utils.ts +48 -0
  113. package/src/utils/node.ts +78 -0
  114. package/src/utils/object-utils.ts +21 -0
  115. package/src/utils/random-utils.ts +79 -0
  116. package/src/utils/static-utils.ts +66 -0
  117. package/src/validateOptions.ts +256 -0
  118. package/tsconfig.json +13 -8
  119. package/babel.config.js +0 -12
  120. package/dev.js +0 -8
  121. package/dist/compiler.js +0 -34
  122. package/dist/parser.js +0 -59
  123. package/dist/precedence.js +0 -66
  124. package/dist/templates/bufferToString.js +0 -129
  125. package/dist/templates/core.js +0 -35
  126. package/dist/templates/crash.js +0 -28
  127. package/dist/templates/es5.js +0 -137
  128. package/dist/templates/functionLength.js +0 -34
  129. package/dist/templates/globals.js +0 -9
  130. package/dist/transforms/antiTooling.js +0 -88
  131. package/dist/transforms/controlFlowFlattening/controlFlowFlattening.js +0 -1287
  132. package/dist/transforms/controlFlowFlattening/expressionObfuscation.js +0 -131
  133. package/dist/transforms/es5/antiClass.js +0 -164
  134. package/dist/transforms/es5/antiDestructuring.js +0 -193
  135. package/dist/transforms/es5/antiES6Object.js +0 -185
  136. package/dist/transforms/es5/antiSpreadOperator.js +0 -35
  137. package/dist/transforms/es5/antiTemplate.js +0 -66
  138. package/dist/transforms/es5/es5.js +0 -123
  139. package/dist/transforms/extraction/classExtraction.js +0 -83
  140. package/dist/transforms/identifier/globalAnalysis.js +0 -83
  141. package/dist/transforms/identifier/variableAnalysis.js +0 -104
  142. package/dist/transforms/lock/antiDebug.js +0 -76
  143. package/dist/transforms/stack.js +0 -349
  144. package/dist/transforms/transform.js +0 -372
  145. package/dist/traverse.js +0 -110
  146. package/dist/util/compare.js +0 -145
  147. package/dist/util/gen.js +0 -564
  148. package/dist/util/guard.js +0 -14
  149. package/dist/util/identifiers.js +0 -355
  150. package/dist/util/insert.js +0 -362
  151. package/dist/util/math.js +0 -19
  152. package/dist/util/object.js +0 -40
  153. package/dist/util/random.js +0 -156
  154. package/dist/util/scope.js +0 -20
  155. package/docs/ControlFlowFlattening.md +0 -595
  156. package/docs/Countermeasures.md +0 -70
  157. package/docs/ES5.md +0 -197
  158. package/docs/Integrity.md +0 -82
  159. package/docs/RGF.md +0 -424
  160. package/docs/RenameVariables.md +0 -116
  161. package/docs/TamperProtection.md +0 -100
  162. package/docs/Template.md +0 -117
  163. package/samples/example.js +0 -15
  164. package/samples/high.js +0 -1
  165. package/samples/input.js +0 -3
  166. package/samples/javascriptobfuscator.com.js +0 -8
  167. package/samples/jscrambler_advanced.js +0 -1894
  168. package/samples/jscrambler_light.js +0 -1134
  169. package/samples/low.js +0 -1
  170. package/samples/medium.js +0 -1
  171. package/samples/obfuscator.io.js +0 -1686
  172. package/samples/preemptive.com.js +0 -16
  173. package/src/compiler.ts +0 -35
  174. package/src/parser.ts +0 -49
  175. package/src/precedence.ts +0 -61
  176. package/src/templates/bufferToString.ts +0 -136
  177. package/src/templates/core.ts +0 -29
  178. package/src/templates/crash.ts +0 -23
  179. package/src/templates/es5.ts +0 -131
  180. package/src/templates/functionLength.ts +0 -32
  181. package/src/templates/globals.ts +0 -3
  182. package/src/transforms/antiTooling.ts +0 -102
  183. package/src/transforms/controlFlowFlattening/controlFlowFlattening.ts +0 -2153
  184. package/src/transforms/controlFlowFlattening/expressionObfuscation.ts +0 -179
  185. package/src/transforms/es5/antiClass.ts +0 -276
  186. package/src/transforms/es5/antiDestructuring.ts +0 -294
  187. package/src/transforms/es5/antiES6Object.ts +0 -267
  188. package/src/transforms/es5/antiSpreadOperator.ts +0 -56
  189. package/src/transforms/es5/antiTemplate.ts +0 -98
  190. package/src/transforms/es5/es5.ts +0 -149
  191. package/src/transforms/extraction/classExtraction.ts +0 -168
  192. package/src/transforms/identifier/globalAnalysis.ts +0 -102
  193. package/src/transforms/identifier/variableAnalysis.ts +0 -118
  194. package/src/transforms/lock/antiDebug.ts +0 -112
  195. package/src/transforms/stack.ts +0 -557
  196. package/src/transforms/transform.ts +0 -441
  197. package/src/traverse.ts +0 -120
  198. package/src/types.ts +0 -133
  199. package/src/util/compare.ts +0 -181
  200. package/src/util/gen.ts +0 -651
  201. package/src/util/guard.ts +0 -17
  202. package/src/util/identifiers.ts +0 -494
  203. package/src/util/insert.ts +0 -419
  204. package/src/util/math.ts +0 -15
  205. package/src/util/object.ts +0 -39
  206. package/src/util/random.ts +0 -221
  207. package/src/util/scope.ts +0 -21
  208. package/test/code/Cash.src.js +0 -1011
  209. package/test/code/Cash.test.ts +0 -132
  210. package/test/code/Dynamic.src.js +0 -118
  211. package/test/code/Dynamic.test.ts +0 -49
  212. package/test/code/ES6.src.js +0 -235
  213. package/test/code/ES6.test.ts +0 -42
  214. package/test/code/NewFeatures.test.ts +0 -19
  215. package/test/code/StrictMode.src.js +0 -65
  216. package/test/code/StrictMode.test.js +0 -37
  217. package/test/compare.test.ts +0 -104
  218. package/test/index.test.ts +0 -249
  219. package/test/options.test.ts +0 -150
  220. package/test/presets.test.ts +0 -22
  221. package/test/probability.test.ts +0 -44
  222. package/test/templates/template.test.ts +0 -224
  223. package/test/transforms/antiTooling.test.ts +0 -52
  224. package/test/transforms/calculator.test.ts +0 -78
  225. package/test/transforms/controlFlowFlattening/controlFlowFlattening.test.ts +0 -1274
  226. package/test/transforms/controlFlowFlattening/expressionObfuscation.test.ts +0 -192
  227. package/test/transforms/deadCode.test.ts +0 -85
  228. package/test/transforms/dispatcher.test.ts +0 -457
  229. package/test/transforms/es5/antiClass.test.ts +0 -427
  230. package/test/transforms/es5/antiDestructuring.test.ts +0 -157
  231. package/test/transforms/es5/antiES6Object.test.ts +0 -245
  232. package/test/transforms/es5/antiTemplate.test.ts +0 -116
  233. package/test/transforms/es5/es5.test.ts +0 -110
  234. package/test/transforms/extraction/classExtraction.test.ts +0 -86
  235. package/test/transforms/extraction/duplicateLiteralsRemoval.test.ts +0 -200
  236. package/test/transforms/extraction/objectExtraction.test.ts +0 -491
  237. package/test/transforms/flatten.test.ts +0 -721
  238. package/test/transforms/hexadecimalNumbers.test.ts +0 -62
  239. package/test/transforms/identifier/globalConcealing.test.ts +0 -142
  240. package/test/transforms/identifier/movedDeclarations.test.ts +0 -275
  241. package/test/transforms/identifier/renameVariables.test.ts +0 -695
  242. package/test/transforms/lock/antiDebug.test.ts +0 -66
  243. package/test/transforms/lock/browserLock.test.ts +0 -129
  244. package/test/transforms/lock/countermeasures.test.ts +0 -100
  245. package/test/transforms/lock/integrity.test.ts +0 -161
  246. package/test/transforms/lock/lock.test.ts +0 -204
  247. package/test/transforms/lock/osLock.test.ts +0 -312
  248. package/test/transforms/lock/selfDefending.test.ts +0 -68
  249. package/test/transforms/lock/tamperProtection.test.ts +0 -336
  250. package/test/transforms/minify.test.ts +0 -575
  251. package/test/transforms/opaquePredicates.test.ts +0 -43
  252. package/test/transforms/preparation.test.ts +0 -157
  253. package/test/transforms/renameLabels.test.ts +0 -95
  254. package/test/transforms/rgf.test.ts +0 -378
  255. package/test/transforms/shuffle.test.ts +0 -135
  256. package/test/transforms/stack.test.ts +0 -573
  257. package/test/transforms/string/stringCompression.test.ts +0 -120
  258. package/test/transforms/string/stringConcealing.test.ts +0 -299
  259. package/test/transforms/string/stringEncoding.test.ts +0 -95
  260. package/test/transforms/string/stringSplitting.test.ts +0 -135
  261. package/test/transforms/transform.test.ts +0 -66
  262. package/test/traverse.test.ts +0 -139
  263. package/test/util/compare.test.ts +0 -34
  264. package/test/util/gen.test.ts +0 -121
  265. package/test/util/identifiers.test.ts +0 -253
  266. package/test/util/insert.test.ts +0 -142
  267. package/test/util/math.test.ts +0 -5
  268. package/test/util/random.test.ts +0 -71
  269. /package/dist/{types.js → obfuscationResult.js} +0 -0
@@ -1,650 +1,409 @@
1
- import Transform from "../transform";
2
- import {
3
- Node,
4
- IfStatement,
5
- ExpressionStatement,
6
- AssignmentExpression,
7
- Identifier,
8
- BinaryExpression,
9
- CallExpression,
10
- MemberExpression,
11
- Literal,
12
- UnaryExpression,
13
- NewExpression,
14
- VariableDeclaration,
15
- ThisExpression,
16
- VariableDeclarator,
17
- Location,
18
- LogicalExpression,
19
- SequenceExpression,
20
- } from "../../util/gen";
21
- import traverse, { getBlock, isBlock } from "../../traverse";
22
- import { choice, getRandomInteger } from "../../util/random";
23
- import { CrashTemplate1, CrashTemplate2 } from "../../templates/crash";
24
- import { getBlockBody, getVarContext, prepend } from "../../util/insert";
1
+ import { NodePath } from "@babel/core";
2
+ import { PluginArg, PluginObject } from "../plugin";
3
+ import { Order } from "../../order";
4
+ import { chance, choice } from "../../utils/random-utils";
25
5
  import Template from "../../templates/template";
26
- import { ObfuscateOrder } from "../../order";
27
- import Integrity from "./integrity";
28
- import AntiDebug from "./antiDebug";
29
- import { getIdentifierInfo } from "../../util/identifiers";
30
- import { isLoop, isValidIdentifier } from "../../util/compare";
31
- import { ok } from "assert";
32
- import { variableFunctionName } from "../../constants";
33
- import { IndexOfTemplate } from "../../templates/core";
34
-
35
- /**
36
- * Applies browser & date locks.
37
- */
38
- export default class Lock extends Transform {
39
- globalVar: string;
40
- counterMeasuresNode: Location;
41
- iosDetectFn: string;
42
-
43
- /**
44
- * This is a boolean variable injected into the source code determining wether the countermeasures function has been called.
45
- * This is used to prevent infinite loops from happening
46
- */
47
- counterMeasuresActivated: string;
48
-
49
- /**
50
- * The name of the native function that is used to check runtime calls for tampering
51
- */
52
- nativeFunctionName: string;
53
-
54
- made: number;
55
-
56
- shouldTransformNativeFunction(nameAndPropertyPath: string[]) {
57
- if (!this.options.lock.tamperProtection) {
58
- return false;
59
- }
60
-
61
- if (typeof this.options.lock.tamperProtection === "function") {
62
- return this.options.lock.tamperProtection(nameAndPropertyPath.join("."));
63
- }
64
-
65
- if (
66
- this.options.target === "browser" &&
67
- nameAndPropertyPath.length === 1 &&
68
- nameAndPropertyPath[0] === "fetch"
69
- ) {
70
- return true;
71
- }
72
-
73
- // TODO: Allow user to customize this behavior
74
- var globalObject = typeof window !== "undefined" ? window : global;
75
- var fn = globalObject;
76
- for (var item of nameAndPropertyPath) {
77
- fn = fn[item];
78
- if (typeof fn === "undefined") return false;
79
- }
80
-
81
- var hasNativeCode =
82
- typeof fn === "function" && ("" + fn).includes("[native code]");
83
-
84
- return hasNativeCode;
85
- }
86
-
87
- constructor(o) {
88
- super(o, ObfuscateOrder.Lock);
89
-
90
- // Removed feature
91
- // if (this.options.lock.startDate && this.options.lock.endDate) {
92
- // this.before.push(new LockStrings(o));
93
- // }
94
-
95
- if (this.options.lock.integrity) {
96
- this.before.push(new Integrity(o, this));
97
- }
98
-
99
- if (this.options.lock.antiDebug) {
100
- this.before.push(new AntiDebug(o, this));
101
- }
102
-
103
- this.made = 0;
6
+ import * as t from "@babel/types";
7
+ import { CustomLock } from "../../options";
8
+ import {
9
+ getFunctionName,
10
+ getParentFunctionOrProgram,
11
+ isDefiningIdentifier,
12
+ isVariableIdentifier,
13
+ prependProgram,
14
+ } from "../../utils/ast-utils";
15
+ import { INTEGRITY, NodeIntegrity } from "./integrity";
16
+ import { HashTemplate } from "../../templates/integrityTemplate";
17
+ import {
18
+ MULTI_TRANSFORM,
19
+ NodeSymbol,
20
+ PREDICTABLE,
21
+ SKIP,
22
+ UNSAFE,
23
+ } from "../../constants";
24
+ import {
25
+ IndexOfTemplate,
26
+ NativeFunctionTemplate,
27
+ StrictModeTemplate,
28
+ } from "../../templates/tamperProtectionTemplates";
29
+ import { computeProbabilityMap } from "../../probability";
30
+
31
+ export default ({ Plugin }: PluginArg): PluginObject => {
32
+ const me = Plugin(Order.Lock, {
33
+ changeData: {
34
+ locksInserted: 0,
35
+ },
36
+ });
37
+
38
+ if (me.options.lock.startDate instanceof Date) {
39
+ me.options.lock.customLocks.push({
40
+ code: [
41
+ `
42
+ if(Date.now()<${me.options.lock.startDate.getTime()}) {
43
+ {countermeasures}
44
+ }
45
+ `,
46
+ `
47
+ if((new Date()).getTime()<${me.options.lock.startDate.getTime()}) {
48
+ {countermeasures}
49
+ }
50
+ `,
51
+ ],
52
+ percentagePerBlock: 0.5,
53
+ });
104
54
  }
105
55
 
106
- apply(tree) {
107
- if (
108
- typeof this.options.lock.countermeasures === "string" &&
109
- isValidIdentifier(this.options.lock.countermeasures)
110
- ) {
111
- traverse(tree, (object, parents) => {
112
- if (
113
- object.type == "Identifier" &&
114
- object.name === this.options.lock.countermeasures
115
- ) {
116
- var info = getIdentifierInfo(object, parents);
117
- if (info.spec.isDefined) {
118
- if (this.counterMeasuresNode) {
119
- throw new Error(
120
- "Countermeasures function was already defined, it must have a unique name from the rest of your code"
121
- );
122
- } else {
123
- var definingContext = getVarContext(parents[0], parents.slice(1));
124
- if (definingContext != tree) {
125
- throw new Error(
126
- "Countermeasures function must be defined at the global level"
127
- );
128
- }
129
- var chain: Location = [object, parents];
130
- if (info.isFunctionDeclaration) {
131
- chain = [parents[0], parents.slice(1)];
132
- } else if (info.isVariableDeclaration) {
133
- chain = [parents[1], parents.slice(2)];
134
- }
135
-
136
- this.counterMeasuresNode = chain;
137
- }
138
- }
139
- }
140
- });
141
-
142
- if (!this.counterMeasuresNode) {
143
- throw new Error(
144
- "Countermeasures function named '" +
145
- this.options.lock.countermeasures +
146
- "' was not found."
147
- );
56
+ if (me.options.lock.endDate instanceof Date) {
57
+ me.options.lock.customLocks.push({
58
+ code: [
59
+ `
60
+ if(Date.now()>${me.options.lock.endDate.getTime()}) {
61
+ {countermeasures}
148
62
  }
149
- }
150
-
151
- super.apply(tree);
152
-
153
- if (this.options.lock.tamperProtection) {
154
- this.nativeFunctionName = this.getPlaceholder() + "_lockNative";
155
-
156
- // Ensure program is not in strict mode
157
- // Tamper Protection forces non-strict mode
63
+ `,
64
+ `
65
+ if((new Date()).getTime()>${me.options.lock.endDate.getTime()}) {
66
+ {countermeasures}
67
+ }
68
+ `,
69
+ ],
70
+ percentagePerBlock: 0.5,
71
+ });
72
+ }
158
73
 
159
- var strictModeCheck = new Template(`
160
- (function(){
161
- function isStrictMode(){
162
- try {
163
- var arr = []
164
- delete arr["length"]
165
- } catch(e) {
166
- return true;
167
- }
168
- return false;
169
- }
74
+ if (me.options.lock.domainLock) {
75
+ var domainArray = Array.isArray(me.options.lock.domainLock)
76
+ ? me.options.lock.domainLock
77
+ : [me.options.lock.domainLock];
170
78
 
171
- if(isStrictMode()) {
79
+ for (const regexString of domainArray) {
80
+ me.options.lock.customLocks.push({
81
+ code: new Template(`
82
+ if(!new RegExp({regexString}).test(window.location.href)) {
172
83
  {countermeasures}
173
- ${this.nativeFunctionName} = undefined;
174
84
  }
175
- })()
176
- `).single({
177
- countermeasures: this.getCounterMeasuresCode(tree, []),
85
+ `).setDefaultVariables({
86
+ regexString: () => t.stringLiteral(regexString.toString()),
87
+ }),
88
+ percentagePerBlock: 0.5,
178
89
  });
90
+ }
91
+ }
179
92
 
180
- // $multiTransformSkip is used to prevent scoping between transformations
181
- strictModeCheck.$multiTransformSkip = true;
182
-
183
- prepend(tree, strictModeCheck);
184
-
185
- var nativeFunctionCheck = new Template(`
186
- function ${this.nativeFunctionName}() {
187
- {IndexOfTemplate}
188
-
189
- function checkFunction(fn){
190
- if (indexOf("" + fn, '{ [native code] }') === -1
191
- ||
192
- typeof Object.getOwnPropertyDescriptor(fn, "toString") !== "undefined"
193
- ) {
93
+ if (me.options.lock.selfDefending) {
94
+ me.options.lock.customLocks.push({
95
+ code: `
96
+ (
97
+ function(){
98
+ // Breaks any code formatter
99
+ var namedFunction = function(){
100
+ const test = function(){
101
+ const regExp=new RegExp('\\n');
102
+ return regExp['test'](namedFunction)
103
+ };
104
+
105
+ if(test()) {
194
106
  {countermeasures}
195
- return undefined
196
107
  }
197
-
198
- return fn;
199
108
  }
200
109
 
201
- var args = arguments
202
- if(args.length === 1) {
203
- return checkFunction(args[0]);
204
- } else if (args.length === 2) {
205
- var object = args[0];
206
- var property = args[1];
110
+ return namedFunction();
111
+ }
112
+ )();
113
+ `,
114
+ percentagePerBlock: 0.5,
115
+ });
116
+ }
117
+
118
+ if (me.options.lock.antiDebug) {
119
+ me.options.lock.customLocks.push({
120
+ code: `
121
+ debugger;
122
+ `,
123
+ percentagePerBlock: 0.5,
124
+ });
125
+ }
207
126
 
208
- var fn = object[property];
209
- fn = checkFunction(fn);
127
+ const timesMap = new WeakMap<CustomLock, number>();
210
128
 
211
- return fn.bind(object);
212
- }
213
- }`).single({
214
- IndexOfTemplate: IndexOfTemplate,
215
- countermeasures: this.getCounterMeasuresCode(tree, []),
216
- });
129
+ let countermeasuresNode: NodePath<t.Identifier>;
130
+ let invokeCountermeasuresFnName;
217
131
 
218
- // $multiTransformSkip is used to prevent scoping between transformations
219
- nativeFunctionCheck.$multiTransformSkip = true;
132
+ if (me.options.lock.countermeasures) {
133
+ invokeCountermeasuresFnName = me.getPlaceholder("invokeCountermeasures");
220
134
 
221
- prepend(tree, nativeFunctionCheck);
222
- }
135
+ me.globalState.internals.invokeCountermeasuresFnName =
136
+ invokeCountermeasuresFnName;
223
137
  }
224
138
 
225
- getCounterMeasuresCode(object: Node, parents: Node[]): Node[] {
226
- var opt = this.options.lock.countermeasures;
227
-
228
- if (opt === false) {
229
- return null;
139
+ var createCountermeasuresCode = () => {
140
+ if (invokeCountermeasuresFnName) {
141
+ return new Template(`${invokeCountermeasuresFnName}()`).compile();
230
142
  }
231
143
 
232
- // Call function
233
- if (typeof opt === "string") {
234
- if (!this.counterMeasuresActivated) {
235
- this.counterMeasuresActivated = this.getPlaceholder();
236
-
237
- prepend(
238
- parents[parents.length - 1] || object,
239
- VariableDeclaration(VariableDeclarator(this.counterMeasuresActivated))
240
- );
241
- }
242
-
243
- // Since Lock occurs before variable renaming, we are using the pre-obfuscated function name
244
- return [
245
- ExpressionStatement(
246
- LogicalExpression(
247
- "||",
248
- Identifier(this.counterMeasuresActivated),
249
- SequenceExpression([
250
- AssignmentExpression(
251
- "=",
252
- Identifier(this.counterMeasuresActivated),
253
- Literal(true)
254
- ),
255
- CallExpression(new Template(opt).single().expression, []),
256
- ])
257
- )
258
- ),
259
- ];
144
+ if (me.options.lock.countermeasures === false) {
145
+ return [];
260
146
  }
261
147
 
262
- // Default fallback to infinite loop
263
- var varName = this.getPlaceholder();
264
- return choice([CrashTemplate1, CrashTemplate2]).compile({
265
- var: varName,
266
- });
267
- }
148
+ return new Template(`while(true){}`).compile();
149
+ };
150
+ me.globalState.lock.createCountermeasuresCode = createCountermeasuresCode;
268
151
 
269
- /**
270
- * Converts Dates to numbers, then applies some randomness
271
- * @param object
272
- */
273
- getTime(object: Date | number | false): number {
274
- if (!object) {
275
- return 0;
276
- }
277
- if (object instanceof Date) {
278
- return this.getTime(object.getTime());
279
- }
152
+ function applyLockToBlock(path: NodePath<t.Block>, customLock: CustomLock) {
153
+ let times = timesMap.get(customLock);
280
154
 
281
- return object + getRandomInteger(-4000, 4000);
282
- }
155
+ if (typeof times === "undefined") {
156
+ times = 0;
157
+ }
283
158
 
284
- match(object: Node, parents: Node[]) {
285
- return isBlock(object);
286
- }
159
+ let maxCount = customLock.maxCount || 100; // 100 is default max count
160
+ let minCount = customLock.minCount || 1; // 1 is default min count
287
161
 
288
- transform(object: Node, parents: Node[]) {
289
- if (parents.find((x) => isLoop(x) && x.type != "SwitchStatement")) {
162
+ if (maxCount >= 0 && times > maxCount) {
163
+ // Limit creation, allowing -1 to disable the limit entirely
290
164
  return;
291
165
  }
292
166
 
293
- // no check in countermeasures code, otherwise it will infinitely call itself
167
+ // The Program always gets a lock
168
+ // Else based on the percentage
169
+ // Try to reach the minimum count
294
170
  if (
295
- this.counterMeasuresNode &&
296
- (object == this.counterMeasuresNode[0] ||
297
- parents.indexOf(this.counterMeasuresNode[0]) !== -1)
171
+ !path.isProgram() &&
172
+ !chance(customLock.percentagePerBlock * 100) &&
173
+ times >= minCount
298
174
  ) {
299
175
  return;
300
176
  }
301
177
 
302
- var block = getBlock(object, parents);
178
+ // Increment the times
179
+ timesMap.set(customLock, times + 1);
303
180
 
304
- var choices = [];
305
- if (this.options.lock.startDate) {
306
- choices.push("startDate");
307
- }
308
- if (this.options.lock.endDate) {
309
- choices.push("endDate");
310
- }
311
- if (this.options.lock.domainLock && this.options.lock.domainLock.length) {
312
- choices.push("domainLock");
313
- }
314
-
315
- if (this.options.lock.context && this.options.lock.context.length) {
316
- choices.push("context");
317
- }
318
- if (this.options.lock.browserLock && this.options.lock.browserLock.length) {
319
- choices.push("browserLock");
320
- }
321
- if (this.options.lock.osLock && this.options.lock.osLock.length) {
322
- choices.push("osLock");
323
- }
324
- if (this.options.lock.selfDefending) {
325
- choices.push("selfDefending");
326
- }
181
+ const lockCode = Array.isArray(customLock.code)
182
+ ? choice(customLock.code)
183
+ : customLock.code;
327
184
 
328
- if (!choices.length) {
329
- return;
330
- }
185
+ const template =
186
+ typeof lockCode === "string" ? new Template(lockCode) : lockCode;
187
+ const lockNodes = template.compile({
188
+ countermeasures: () => createCountermeasuresCode(),
189
+ });
190
+ var p = path.unshiftContainer("body", lockNodes);
191
+ p.forEach((p) => p.skip());
331
192
 
332
- return () => {
333
- this.made++;
334
- if (this.made > 150) {
335
- return;
336
- }
193
+ me.changeData.locksInserted++;
194
+ }
337
195
 
338
- var type = choice(choices);
339
- var nodes = [];
340
-
341
- var dateNow: Node = CallExpression(
342
- MemberExpression(Identifier("Date"), Literal("now"), true),
343
- []
344
- );
345
- if (Math.random() > 0.5) {
346
- dateNow = CallExpression(
347
- MemberExpression(
348
- NewExpression(Identifier("Date"), []),
349
- Literal("getTime")
350
- ),
351
- []
352
- );
353
- }
354
- if (Math.random() > 0.5) {
355
- dateNow = CallExpression(
356
- MemberExpression(
357
- MemberExpression(
358
- MemberExpression(Identifier("Date"), Literal("prototype"), true),
359
- Literal("getTime"),
360
- true
361
- ),
362
- Literal("call"),
363
- true
364
- ),
365
- [NewExpression(Identifier("Date"), [])]
366
- );
367
- }
196
+ return {
197
+ visitor: {
198
+ BindingIdentifier(path) {
199
+ if (path.node.name !== me.options.lock.countermeasures) {
200
+ return;
201
+ }
368
202
 
369
- var test;
370
- var offset = 0;
371
-
372
- switch (type) {
373
- case "selfDefending":
374
- // A very simple mechanism inspired from https://github.com/javascript-obfuscator/javascript-obfuscator/blob/master/src/custom-code-helpers/self-defending/templates/SelfDefendingNoEvalTemplate.ts
375
- // regExp checks for a newline, formatters add these
376
- var callExpression = new Template(
377
- `
378
- (
379
- function(){
380
- // Breaks JSNice.org, beautifier.io
381
- var namedFunction = function(){
382
- const test = function(){
383
- const regExp=new RegExp('\\n');
384
- return regExp['test'](namedFunction)
385
- };
386
- return test()
387
- }
203
+ // Exclude labels
204
+ if (!isVariableIdentifier(path)) return;
388
205
 
389
- return namedFunction();
390
- }
391
- )()
392
- `
393
- ).single().expression;
394
-
395
- nodes.push(
396
- IfStatement(
397
- callExpression,
398
- this.getCounterMeasuresCode(object, parents) || [],
399
- null
400
- )
401
- );
206
+ if (!isDefiningIdentifier(path)) {
207
+ // Reassignments are not allowed
402
208
 
403
- break;
209
+ me.error("Countermeasures function cannot be reassigned");
210
+ }
404
211
 
405
- case "startDate":
406
- test = BinaryExpression(
407
- "<",
408
- dateNow,
409
- Literal(this.getTime(this.options.lock.startDate))
410
- );
212
+ if (countermeasuresNode) {
213
+ // Disallow multiple countermeasures functions
411
214
 
412
- nodes.push(
413
- IfStatement(
414
- test,
415
- this.getCounterMeasuresCode(object, parents) || [],
416
- null
417
- )
215
+ me.error(
216
+ "Countermeasures function was already defined, it must have a unique name from the rest of your code"
418
217
  );
218
+ }
419
219
 
420
- break;
421
-
422
- case "endDate":
423
- test = BinaryExpression(
424
- ">",
425
- dateNow,
426
- Literal(this.getTime(this.options.lock.endDate))
220
+ if (
221
+ path.scope.getBinding(path.node.name).scope !==
222
+ path.scope.getProgramParent()
223
+ ) {
224
+ me.error(
225
+ "Countermeasures function must be defined at the global level"
427
226
  );
227
+ }
428
228
 
429
- nodes.push(
430
- IfStatement(
431
- test,
432
- this.getCounterMeasuresCode(object, parents) || [],
433
- null
434
- )
435
- );
229
+ countermeasuresNode = path;
230
+ },
436
231
 
437
- break;
438
-
439
- case "context":
440
- var prop = choice(this.options.lock.context);
441
-
442
- var code = this.getCounterMeasuresCode(object, parents) || [];
443
-
444
- // Todo: Alternative to `this`
445
- if (!this.globalVar) {
446
- offset = 1;
447
- this.globalVar = this.getPlaceholder();
448
- prepend(
449
- parents[parents.length - 1] || block,
450
- VariableDeclaration(
451
- VariableDeclarator(
452
- this.globalVar,
453
- LogicalExpression(
454
- "||",
455
- Identifier(
456
- this.options.globalVariables.keys().next().value
457
- ),
458
- ThisExpression()
459
- )
460
- )
461
- )
462
- );
232
+ Block: {
233
+ exit(path) {
234
+ var customLock = choice(me.options.lock.customLocks);
235
+ if (customLock) {
236
+ applyLockToBlock(path, customLock);
463
237
  }
464
-
465
- test = UnaryExpression(
466
- "!",
467
- MemberExpression(Identifier(this.globalVar), Literal(prop), true)
468
- );
469
- nodes.push(IfStatement(test, code, null));
470
-
471
- break;
472
-
473
- case "osLock":
474
- var navigatorUserAgent = new Template(
475
- `window.navigator.userAgent.toLowerCase()`
476
- ).single().expression;
477
-
478
- ok(this.options.lock.osLock);
479
-
480
- var code = this.getCounterMeasuresCode(object, parents) || [];
481
-
482
- this.options.lock.osLock.forEach((osName) => {
483
- var agentMatcher = {
484
- windows: "Win",
485
- linux: "Linux",
486
- osx: "Mac",
487
- android: "Android",
488
- ios: "---",
489
- }[osName];
490
- var thisTest: Node = CallExpression(
491
- MemberExpression(navigatorUserAgent, Literal("match"), true),
492
- [Literal(agentMatcher.toLowerCase())]
493
- );
494
- if (osName == "ios" && this.options.target === "browser") {
495
- if (!this.iosDetectFn) {
496
- this.iosDetectFn = this.getPlaceholder();
497
- prepend(
498
- parents[parents.length - 1] || object,
499
- new Template(`function ${this.iosDetectFn}() {
500
- return [
501
- 'iPad Simulator',
502
- 'iPhone Simulator',
503
- 'iPod Simulator',
504
- 'iPad',
505
- 'iPhone',
506
- 'iPod'
507
- ].includes(navigator.platform)
508
- // iPad on iOS 13 detection
509
- || (navigator.userAgent.includes("Mac") && "ontouchend" in document)
510
- }`).single()
238
+ },
239
+ },
240
+
241
+ Program: {
242
+ exit(path) {
243
+ // Insert nativeFunctionCheck
244
+ if (me.options.lock.tamperProtection) {
245
+ // Disallow strict mode
246
+ // Tamper Protection uses non-strict mode features:
247
+ // - eval() with local scope assignments
248
+ const directives = path.get("directives");
249
+ for (var directive of directives) {
250
+ if (directive.node.value.value === "use strict") {
251
+ me.error(
252
+ "Tamper Protection cannot be applied to code in strict mode. Disable strict mode by removing the 'use strict' directive, or disable Tamper Protection."
511
253
  );
512
254
  }
513
-
514
- thisTest = CallExpression(Identifier(this.iosDetectFn), []);
515
255
  }
516
256
 
517
- if (this.options.target === "node") {
518
- var platformName =
519
- { windows: "win32", osx: "darwin", ios: "darwin" }[osName] ||
520
- osName;
521
- thisTest = new Template(
522
- `require('os').platform()==="${platformName}"`
523
- ).single().expression;
524
- }
257
+ var nativeFunctionName =
258
+ me.getPlaceholder() + "_nativeFunctionCheck";
525
259
 
526
- if (!test) {
527
- test = thisTest;
528
- } else {
529
- test = LogicalExpression("||", { ...test }, thisTest);
530
- }
531
- });
260
+ me.obfuscator.globalState.internals.nativeFunctionName =
261
+ nativeFunctionName;
532
262
 
533
- test = UnaryExpression("!", { ...test });
534
- nodes.push(IfStatement(test, code, null));
535
- break;
536
-
537
- case "browserLock":
538
- var navigatorUserAgent = new Template(
539
- `window.navigator.userAgent.toLowerCase()`
540
- ).single().expression;
541
-
542
- ok(this.options.lock.browserLock);
543
-
544
- this.options.lock.browserLock.forEach((browserName) => {
545
- var thisTest: Node = CallExpression(
546
- MemberExpression(navigatorUserAgent, Literal("match"), true),
547
- [
548
- Literal(
549
- browserName == "iexplorer"
550
- ? "msie"
551
- : browserName.toLowerCase()
552
- ),
553
- ]
263
+ // Ensure program is not in strict mode
264
+ // Tamper Protection forces non-strict mode
265
+ prependProgram(
266
+ path,
267
+ StrictModeTemplate.compile({
268
+ nativeFunctionName,
269
+ countermeasures: createCountermeasuresCode(),
270
+ })
554
271
  );
555
272
 
556
- if (browserName === "safari") {
557
- thisTest = new Template(
558
- `/^((?!chrome|android).)*safari/i.test(navigator.userAgent)`
559
- ).single().expression;
560
- }
561
-
562
- if (!test) {
563
- test = thisTest;
564
- } else {
565
- test = LogicalExpression("||", { ...test }, thisTest);
566
- }
567
- });
273
+ const nativeFunctionDeclaration = NativeFunctionTemplate.single({
274
+ nativeFunctionName,
275
+ countermeasures: createCountermeasuresCode(),
276
+ IndexOfTemplate: IndexOfTemplate,
277
+ });
568
278
 
569
- test = UnaryExpression("!", { ...test });
570
- nodes.push(
571
- IfStatement(
572
- test,
573
- this.getCounterMeasuresCode(object, parents) || [],
574
- null
575
- )
576
- );
577
- break;
279
+ // Checks function's toString() value for [native code] signature
280
+ prependProgram(path, nativeFunctionDeclaration);
281
+ }
578
282
 
579
- case "domainLock":
580
- function removeSlashes(path: string) {
581
- var count = path.length - 1;
582
- var index = 0;
283
+ // Insert invokeCountermeasures function
284
+ if (invokeCountermeasuresFnName) {
285
+ if (!countermeasuresNode) {
286
+ me.error(
287
+ "Countermeasures function named '" +
288
+ me.options.lock.countermeasures +
289
+ "' was not found."
290
+ );
291
+ }
583
292
 
584
- while (path.charCodeAt(index) === 47 && ++index);
585
- while (path.charCodeAt(count) === 47 && --count);
293
+ var hasInvoked = me.getPlaceholder("hasInvoked");
294
+ var statements = new Template(`
295
+ var ${hasInvoked} = false;
296
+ function ${invokeCountermeasuresFnName}(){
297
+ if(${hasInvoked}) return;
298
+ ${hasInvoked} = true;
299
+ ${me.options.lock.countermeasures}();
300
+ }
301
+ `)
302
+ .addSymbols(MULTI_TRANSFORM)
303
+ .compile();
586
304
 
587
- return path.slice(index, count + 1);
305
+ prependProgram(path, statements).forEach((p) => p.skip());
588
306
  }
589
307
 
590
- var locationHref = MemberExpression(
591
- Identifier("location"),
592
- Literal("href"),
593
- true
308
+ if (me.options.lock.integrity) {
309
+ const hashFnName = me.getPlaceholder() + "_hash";
310
+ const imulFnName = me.getPlaceholder() + "_imul";
311
+
312
+ const { sensitivityRegex } = me.globalState.lock.integrity;
313
+ me.globalState.internals.integrityHashName = hashFnName;
314
+
315
+ const hashCode = HashTemplate.compile({
316
+ imul: imulFnName,
317
+ name: hashFnName,
318
+ hashingUtilFnName: me.getPlaceholder(),
319
+ sensitivityRegex: () =>
320
+ t.newExpression(t.identifier("RegExp"), [
321
+ t.stringLiteral(sensitivityRegex.source),
322
+ t.stringLiteral(sensitivityRegex.flags),
323
+ ]),
324
+ });
325
+
326
+ prependProgram(path, hashCode);
327
+ }
328
+ },
329
+ },
330
+
331
+ // Integrity first pass
332
+ // Functions are prepared for Integrity by simply extracting the function body
333
+ // The extracted function is hashed in the 'integrity' plugin
334
+ FunctionDeclaration: {
335
+ exit(funcDecPath) {
336
+ if (!me.options.lock.integrity) return;
337
+
338
+ // Mark functions for integrity
339
+ // Don't apply to async or generator functions
340
+ if (funcDecPath.node.async || funcDecPath.node.generator) return;
341
+
342
+ if (funcDecPath.find((p) => !!(p.node as NodeSymbol)[SKIP])) return;
343
+
344
+ var program = getParentFunctionOrProgram(funcDecPath);
345
+ // Only top-level functions
346
+ if (!program.isProgram()) return;
347
+
348
+ // Check user's custom implementation
349
+ const functionName = getFunctionName(funcDecPath);
350
+ // Don't apply to the countermeasures function (Intended)
351
+ if (
352
+ me.options.lock.countermeasures &&
353
+ functionName === me.options.lock.countermeasures
354
+ )
355
+ return;
356
+ // Don't apply to invokeCountermeasures function (Intended)
357
+ if (me.obfuscator.isInternalVariable(functionName)) return;
358
+
359
+ if (!computeProbabilityMap(me.options.lock.integrity, functionName))
360
+ return;
361
+
362
+ var newFnName = me.getPlaceholder();
363
+ var newFunctionDeclaration = t.functionDeclaration(
364
+ t.identifier(newFnName),
365
+ funcDecPath.node.params,
366
+ funcDecPath.node.body
594
367
  );
595
368
 
596
- var random = choice(this.options.lock.domainLock as any);
597
- if (random) {
598
- test = CallExpression(
599
- MemberExpression(locationHref, Literal("match"), true),
600
- [
601
- {
602
- type: "Literal",
603
- regex: {
604
- pattern:
605
- random instanceof RegExp
606
- ? random.source
607
- : removeSlashes(random + ""),
608
- flags: random instanceof RegExp ? "" : "",
609
- },
610
- },
611
- ]
612
- );
369
+ // Clone semantic symbols like (UNSAFE, PREDICTABLE, MULTI_TRANSFORM, etc)
370
+ const source = funcDecPath.node;
371
+ Object.getOwnPropertySymbols(source).forEach((symbol) => {
372
+ newFunctionDeclaration[symbol] = source[symbol];
373
+ });
613
374
 
614
- test = UnaryExpression("!", test);
615
- if (Math.random() > 0.5) {
616
- test = LogicalExpression(
617
- "||",
618
- BinaryExpression(
619
- "==",
620
- UnaryExpression("typeof", Identifier("location")),
621
- Literal("undefined")
622
- ),
623
- test
624
- );
625
- }
626
- nodes.push(
627
- IfStatement(
628
- test,
629
- this.getCounterMeasuresCode(object, parents) || [],
630
- null
631
- )
632
- );
633
- }
375
+ (newFunctionDeclaration as NodeSymbol)[SKIP] = true;
634
376
 
635
- break;
636
- }
377
+ var [newFnPath] = program.unshiftContainer(
378
+ "body",
379
+ newFunctionDeclaration
380
+ );
637
381
 
638
- if (nodes.length) {
639
- var body = getBlockBody(block);
640
- var randomIndex = getRandomInteger(0, body.length) + offset;
382
+ // Function simply calls the new function
383
+ // In the case Integrity cannot transform the function, the original behavior is preserved
384
+ funcDecPath.node.body = t.blockStatement(
385
+ new Template(`
386
+ return ${newFnName}(...arguments);
387
+ `).compile(),
388
+ funcDecPath.node.body.directives
389
+ );
641
390
 
642
- if (randomIndex >= body.length) {
643
- body.push(...nodes);
644
- } else {
645
- body.splice(randomIndex, 0, ...nodes);
646
- }
647
- }
648
- };
649
- }
650
- }
391
+ // Parameters no longer needed, using 'arguments' instead
392
+ funcDecPath.node.params = [];
393
+
394
+ // Mark the function as unsafe - use of 'arguments' is unsafe
395
+ (funcDecPath.node as NodeSymbol)[UNSAFE] = true;
396
+
397
+ // Params changed - function is no longer predictable
398
+ (funcDecPath.node as NodeSymbol)[PREDICTABLE] = false;
399
+
400
+ // Mark the function for integrity
401
+ (funcDecPath.node as NodeIntegrity)[INTEGRITY] = {
402
+ fnPath: newFnPath,
403
+ fnName: newFnName,
404
+ };
405
+ },
406
+ },
407
+ },
408
+ };
409
+ };