@nodesecure/js-x-ray 9.0.0 → 9.2.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 (180) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +9 -209
  3. package/dist/AstAnalyser.d.ts +64 -0
  4. package/dist/AstAnalyser.d.ts.map +1 -0
  5. package/dist/AstAnalyser.js +165 -0
  6. package/dist/AstAnalyser.js.map +1 -0
  7. package/dist/Deobfuscator.d.ts +36 -0
  8. package/dist/Deobfuscator.d.ts.map +1 -0
  9. package/dist/Deobfuscator.js +154 -0
  10. package/dist/Deobfuscator.js.map +1 -0
  11. package/dist/EntryFilesAnalyser.d.ts +20 -0
  12. package/dist/EntryFilesAnalyser.d.ts.map +1 -0
  13. package/dist/EntryFilesAnalyser.js +121 -0
  14. package/dist/EntryFilesAnalyser.js.map +1 -0
  15. package/dist/JsSourceParser.d.ts +18 -0
  16. package/dist/JsSourceParser.d.ts.map +1 -0
  17. package/dist/JsSourceParser.js +38 -0
  18. package/dist/JsSourceParser.js.map +1 -0
  19. package/dist/NodeCounter.d.ts +24 -0
  20. package/dist/NodeCounter.d.ts.map +1 -0
  21. package/dist/NodeCounter.js +62 -0
  22. package/dist/NodeCounter.js.map +1 -0
  23. package/dist/ProbeRunner.d.ts +40 -0
  24. package/dist/ProbeRunner.d.ts.map +1 -0
  25. package/dist/ProbeRunner.js +106 -0
  26. package/dist/ProbeRunner.js.map +1 -0
  27. package/dist/SourceFile.d.ts +43 -0
  28. package/dist/SourceFile.d.ts.map +1 -0
  29. package/dist/SourceFile.js +137 -0
  30. package/dist/SourceFile.js.map +1 -0
  31. package/dist/index.d.ts +6 -0
  32. package/dist/index.d.ts.map +1 -0
  33. package/dist/index.js +6 -0
  34. package/dist/index.js.map +1 -0
  35. package/dist/obfuscators/freejsobfuscator.d.ts +3 -0
  36. package/dist/obfuscators/freejsobfuscator.d.ts.map +1 -0
  37. package/dist/obfuscators/freejsobfuscator.js +10 -0
  38. package/dist/obfuscators/freejsobfuscator.js.map +1 -0
  39. package/dist/obfuscators/jjencode.d.ts +3 -0
  40. package/dist/obfuscators/jjencode.d.ts.map +1 -0
  41. package/dist/obfuscators/jjencode.js +24 -0
  42. package/dist/obfuscators/jjencode.js.map +1 -0
  43. package/dist/obfuscators/jsfuck.d.ts +3 -0
  44. package/dist/obfuscators/jsfuck.d.ts.map +1 -0
  45. package/dist/obfuscators/jsfuck.js +13 -0
  46. package/dist/obfuscators/jsfuck.js.map +1 -0
  47. package/dist/obfuscators/obfuscator-io.d.ts +3 -0
  48. package/dist/obfuscators/obfuscator-io.d.ts.map +1 -0
  49. package/dist/obfuscators/obfuscator-io.js +15 -0
  50. package/dist/obfuscators/obfuscator-io.js.map +1 -0
  51. package/dist/obfuscators/trojan-source.d.ts +2 -0
  52. package/dist/obfuscators/trojan-source.d.ts.map +1 -0
  53. package/dist/obfuscators/trojan-source.js +27 -0
  54. package/dist/obfuscators/trojan-source.js.map +1 -0
  55. package/dist/probes/isArrayExpression.d.ts +21 -0
  56. package/dist/probes/isArrayExpression.d.ts.map +1 -0
  57. package/{src → dist}/probes/isArrayExpression.js +10 -15
  58. package/dist/probes/isArrayExpression.js.map +1 -0
  59. package/dist/probes/isBinaryExpression.d.ts +21 -0
  60. package/dist/probes/isBinaryExpression.d.ts.map +1 -0
  61. package/dist/probes/isBinaryExpression.js +54 -0
  62. package/dist/probes/isBinaryExpression.js.map +1 -0
  63. package/dist/probes/isESMExport.d.ts +24 -0
  64. package/dist/probes/isESMExport.d.ts.map +1 -0
  65. package/dist/probes/isESMExport.js +30 -0
  66. package/dist/probes/isESMExport.js.map +1 -0
  67. package/dist/probes/isFetch.d.ts +14 -0
  68. package/dist/probes/isFetch.d.ts.map +1 -0
  69. package/dist/probes/isFetch.js +18 -0
  70. package/dist/probes/isFetch.js.map +1 -0
  71. package/dist/probes/isImportDeclaration.d.ts +26 -0
  72. package/dist/probes/isImportDeclaration.d.ts.map +1 -0
  73. package/dist/probes/isImportDeclaration.js +38 -0
  74. package/dist/probes/isImportDeclaration.js.map +1 -0
  75. package/dist/probes/isLiteral.d.ts +21 -0
  76. package/dist/probes/isLiteral.d.ts.map +1 -0
  77. package/dist/probes/isLiteral.js +66 -0
  78. package/dist/probes/isLiteral.js.map +1 -0
  79. package/dist/probes/isLiteralRegex.d.ts +20 -0
  80. package/dist/probes/isLiteralRegex.d.ts.map +1 -0
  81. package/dist/probes/isLiteralRegex.js +30 -0
  82. package/dist/probes/isLiteralRegex.js.map +1 -0
  83. package/dist/probes/isRegexObject.d.ts +22 -0
  84. package/dist/probes/isRegexObject.d.ts.map +1 -0
  85. package/dist/probes/isRegexObject.js +50 -0
  86. package/dist/probes/isRegexObject.js.map +1 -0
  87. package/dist/probes/isRequire/RequireCallExpressionWalker.d.ts +15 -0
  88. package/dist/probes/isRequire/RequireCallExpressionWalker.d.ts.map +1 -0
  89. package/dist/probes/isRequire/RequireCallExpressionWalker.js +95 -0
  90. package/dist/probes/isRequire/RequireCallExpressionWalker.js.map +1 -0
  91. package/dist/probes/isRequire/isRequire.d.ts +20 -0
  92. package/dist/probes/isRequire/isRequire.d.ts.map +1 -0
  93. package/dist/probes/isRequire/isRequire.js +138 -0
  94. package/dist/probes/isRequire/isRequire.js.map +1 -0
  95. package/dist/probes/isSerializeEnv.d.ts +24 -0
  96. package/dist/probes/isSerializeEnv.d.ts.map +1 -0
  97. package/dist/probes/isSerializeEnv.js +66 -0
  98. package/dist/probes/isSerializeEnv.js.map +1 -0
  99. package/dist/probes/isSyncIO.d.ts +16 -0
  100. package/dist/probes/isSyncIO.d.ts.map +1 -0
  101. package/dist/probes/isSyncIO.js +74 -0
  102. package/dist/probes/isSyncIO.js.map +1 -0
  103. package/dist/probes/isUnsafeCallee.d.ts +22 -0
  104. package/dist/probes/isUnsafeCallee.d.ts.map +1 -0
  105. package/dist/probes/isUnsafeCallee.js +60 -0
  106. package/dist/probes/isUnsafeCallee.js.map +1 -0
  107. package/dist/probes/isUnsafeCommand.d.ts +24 -0
  108. package/dist/probes/isUnsafeCommand.d.ts.map +1 -0
  109. package/dist/probes/isUnsafeCommand.js +100 -0
  110. package/dist/probes/isUnsafeCommand.js.map +1 -0
  111. package/dist/probes/isWeakCrypto.d.ts +16 -0
  112. package/dist/probes/isWeakCrypto.d.ts.map +1 -0
  113. package/dist/probes/isWeakCrypto.js +46 -0
  114. package/dist/probes/isWeakCrypto.js.map +1 -0
  115. package/dist/types/estree.d.ts +11 -0
  116. package/dist/types/estree.d.ts.map +1 -0
  117. package/dist/types/estree.js +15 -0
  118. package/dist/types/estree.js.map +1 -0
  119. package/dist/utils/extractNode.d.ts +5 -0
  120. package/dist/utils/extractNode.d.ts.map +1 -0
  121. package/dist/utils/extractNode.js +13 -0
  122. package/dist/utils/extractNode.js.map +1 -0
  123. package/dist/utils/index.d.ts +5 -0
  124. package/dist/utils/index.d.ts.map +1 -0
  125. package/dist/utils/index.js +5 -0
  126. package/dist/utils/index.js.map +1 -0
  127. package/dist/utils/isOneLineExpressionExport.d.ts +3 -0
  128. package/dist/utils/isOneLineExpressionExport.d.ts.map +1 -0
  129. package/dist/utils/isOneLineExpressionExport.js +49 -0
  130. package/dist/utils/isOneLineExpressionExport.js.map +1 -0
  131. package/dist/utils/notNullOrUndefined.d.ts +2 -0
  132. package/dist/utils/notNullOrUndefined.d.ts.map +1 -0
  133. package/dist/utils/notNullOrUndefined.js +4 -0
  134. package/dist/utils/notNullOrUndefined.js.map +1 -0
  135. package/dist/utils/toArrayLocation.d.ts +5 -0
  136. package/dist/utils/toArrayLocation.d.ts.map +1 -0
  137. package/dist/utils/toArrayLocation.js +14 -0
  138. package/dist/utils/toArrayLocation.js.map +1 -0
  139. package/dist/warnings.d.ts +88 -0
  140. package/dist/warnings.d.ts.map +1 -0
  141. package/dist/warnings.js +91 -0
  142. package/dist/warnings.js.map +1 -0
  143. package/package.json +59 -77
  144. package/index.d.ts +0 -46
  145. package/index.js +0 -4
  146. package/src/AstAnalyser.js +0 -222
  147. package/src/Deobfuscator.js +0 -195
  148. package/src/EntryFilesAnalyser.js +0 -167
  149. package/src/JsSourceParser.js +0 -57
  150. package/src/NodeCounter.js +0 -76
  151. package/src/ProbeRunner.js +0 -144
  152. package/src/SourceFile.js +0 -147
  153. package/src/obfuscators/freejsobfuscator.js +0 -9
  154. package/src/obfuscators/jjencode.js +0 -27
  155. package/src/obfuscators/jsfuck.js +0 -11
  156. package/src/obfuscators/obfuscator-io.js +0 -13
  157. package/src/obfuscators/trojan-source.js +0 -28
  158. package/src/probes/isBinaryExpression.js +0 -55
  159. package/src/probes/isESMExport.js +0 -31
  160. package/src/probes/isFetch.js +0 -19
  161. package/src/probes/isImportDeclaration.js +0 -33
  162. package/src/probes/isLiteral.js +0 -70
  163. package/src/probes/isLiteralRegex.js +0 -31
  164. package/src/probes/isRegexObject.js +0 -49
  165. package/src/probes/isRequire/RequireCallExpressionWalker.js +0 -93
  166. package/src/probes/isRequire/isRequire.js +0 -148
  167. package/src/probes/isUnsafeCallee.js +0 -35
  168. package/src/probes/isWeakCrypto.js +0 -37
  169. package/src/utils/exportAssignmentHasRequireLeave.js +0 -40
  170. package/src/utils/extractNode.js +0 -14
  171. package/src/utils/index.js +0 -8
  172. package/src/utils/isNode.js +0 -5
  173. package/src/utils/isOneLineExpressionExport.js +0 -24
  174. package/src/utils/isUnsafeCallee.js +0 -28
  175. package/src/utils/notNullOrUndefined.js +0 -3
  176. package/src/utils/rootLocation.js +0 -3
  177. package/src/utils/toArrayLocation.js +0 -11
  178. package/src/warnings.js +0 -77
  179. package/types/api.d.ts +0 -177
  180. package/types/warnings.d.ts +0 -36
@@ -1,144 +0,0 @@
1
- // Import Native Dependencies
2
- import assert from "node:assert";
3
-
4
- // Import all the probes
5
- import isUnsafeCallee from "./probes/isUnsafeCallee.js";
6
- import isLiteral from "./probes/isLiteral.js";
7
- import isLiteralRegex from "./probes/isLiteralRegex.js";
8
- import isRegexObject from "./probes/isRegexObject.js";
9
- import isRequire from "./probes/isRequire/isRequire.js";
10
- import isImportDeclaration from "./probes/isImportDeclaration.js";
11
- import isWeakCrypto from "./probes/isWeakCrypto.js";
12
- import isBinaryExpression from "./probes/isBinaryExpression.js";
13
- import isArrayExpression from "./probes/isArrayExpression.js";
14
- import isESMExport from "./probes/isESMExport.js";
15
- import isFetch from "./probes/isFetch.js";
16
-
17
- // Import Internal Dependencies
18
- import { SourceFile } from "./SourceFile.js";
19
-
20
- /**
21
- * @typedef {Object} Probe
22
- * @property {string} name
23
- * @property {any} validateNode
24
- * @property {(node: any, options: any) => any} main
25
- * @property {(options: any) => void} teardown
26
- * @property {boolean} [breakOnMatch=false]
27
- * @property {string} [breakGroup]
28
- */
29
-
30
- export const ProbeSignals = Object.freeze({
31
- Break: Symbol.for("breakWalk"),
32
- Skip: Symbol.for("skipWalk")
33
- });
34
-
35
- export class ProbeRunner {
36
- /**
37
- * Note:
38
- * The order of the table has an importance/impact on the correct execution of the probes
39
- *
40
- * @type {Probe[]}
41
- */
42
- static Defaults = [
43
- isFetch,
44
- isRequire,
45
- isESMExport,
46
- isUnsafeCallee,
47
- isLiteral,
48
- isLiteralRegex,
49
- isRegexObject,
50
- isImportDeclaration,
51
- isWeakCrypto,
52
- isBinaryExpression,
53
- isArrayExpression
54
- ];
55
-
56
- /**
57
- *
58
- * @param {!SourceFile} sourceFile
59
- * @param {Probe[]} [probes=ProbeRunner.Defaults]
60
- */
61
- constructor(
62
- sourceFile,
63
- probes = ProbeRunner.Defaults
64
- ) {
65
- this.sourceFile = sourceFile;
66
-
67
- for (const probe of probes) {
68
- assert(
69
- typeof probe.validateNode === "function" || Array.isArray(probe.validateNode),
70
- `Invalid probe ${probe.name}: validateNode must be a function or an array of functions`
71
- );
72
- assert(
73
- typeof probe.main === "function",
74
- `Invalid probe ${probe.name}: main must be a function`
75
- );
76
- }
77
-
78
- this.probes = probes;
79
- }
80
-
81
- /**
82
- * @param {!Probe} probe
83
- * @param {!any} node
84
- * @returns {null|void|Symbol}
85
- */
86
- #runProbe(probe, node) {
87
- const validationFns = Array.isArray(probe.validateNode) ?
88
- probe.validateNode : [probe.validateNode];
89
- for (const validateNode of validationFns) {
90
- const [isMatching, data = null] = validateNode(
91
- node,
92
- this.sourceFile
93
- );
94
-
95
- if (isMatching) {
96
- return probe.main(node, {
97
- sourceFile: this.sourceFile,
98
- data
99
- });
100
- }
101
- }
102
-
103
- return null;
104
- }
105
-
106
- walk(node) {
107
- /** @type {Set<string>} */
108
- const breakGroups = new Set();
109
-
110
- for (const probe of this.probes) {
111
- if (breakGroups.has(probe.breakGroup)) {
112
- continue;
113
- }
114
-
115
- try {
116
- const result = this.#runProbe(probe, node);
117
- if (result === null) {
118
- continue;
119
- }
120
-
121
- if (result === ProbeSignals.Skip) {
122
- return "skip";
123
- }
124
- if (result === ProbeSignals.Break || probe.breakOnMatch) {
125
- const breakGroup = probe.breakGroup || null;
126
-
127
- if (breakGroup === null) {
128
- break;
129
- }
130
- else {
131
- breakGroups.add(breakGroup);
132
- }
133
- }
134
- }
135
- finally {
136
- if (probe.teardown) {
137
- probe.teardown({ sourceFile: this.sourceFile });
138
- }
139
- }
140
- }
141
-
142
- return null;
143
- }
144
- }
package/src/SourceFile.js DELETED
@@ -1,147 +0,0 @@
1
- // Import Third-party Dependencies
2
- import { Utils, Literal } from "@nodesecure/sec-literal";
3
- import { VariableTracer } from "@nodesecure/estree-ast-utils";
4
-
5
- // Import Internal Dependencies
6
- import { rootLocation, toArrayLocation } from "./utils/index.js";
7
- import { generateWarning } from "./warnings.js";
8
- import { ProbeRunner } from "./ProbeRunner.js";
9
- import { Deobfuscator } from "./Deobfuscator.js";
10
- import * as trojan from "./obfuscators/trojan-source.js";
11
-
12
- // CONSTANTS
13
- const kMaximumEncodedLiterals = 10;
14
-
15
- export class SourceFile {
16
- inTryStatement = false;
17
- dependencyAutoWarning = false;
18
- deobfuscator = new Deobfuscator();
19
- dependencies = new Map();
20
- encodedLiterals = new Map();
21
- warnings = [];
22
- /** @type {Set<string>} */
23
- flags = new Set();
24
-
25
- constructor(sourceCodeString, probesOptions = {}) {
26
- this.tracer = new VariableTracer()
27
- .enableDefaultTracing()
28
- .trace("crypto.createHash", {
29
- followConsecutiveAssignment: true, moduleName: "crypto"
30
- });
31
-
32
- let probes = ProbeRunner.Defaults;
33
- if (Array.isArray(probesOptions.customProbes) && probesOptions.customProbes.length > 0) {
34
- probes = probesOptions.skipDefaultProbes === true ? probesOptions.customProbes : [...probes, ...probesOptions.customProbes];
35
- }
36
- this.probesRunner = new ProbeRunner(this, probes);
37
-
38
- if (trojan.verify(sourceCodeString)) {
39
- this.addWarning("obfuscated-code", "trojan-source");
40
- }
41
- }
42
-
43
- addDependency(name, location = null, unsafe = this.dependencyAutoWarning) {
44
- if (typeof name !== "string" || name.trim() === "") {
45
- return;
46
- }
47
-
48
- const dependencyName = name.charAt(name.length - 1) === "/" ?
49
- name.slice(0, -1) : name;
50
- this.dependencies.set(dependencyName, {
51
- unsafe,
52
- inTry: this.inTryStatement,
53
- ...(location === null ? {} : { location })
54
- });
55
-
56
- if (this.dependencyAutoWarning) {
57
- this.addWarning("unsafe-import", dependencyName, location);
58
- }
59
- }
60
-
61
- addWarning(name, value, location = rootLocation()) {
62
- const isEncodedLiteral = name === "encoded-literal";
63
- if (isEncodedLiteral) {
64
- if (this.encodedLiterals.size > kMaximumEncodedLiterals) {
65
- return;
66
- }
67
-
68
- if (this.encodedLiterals.has(value)) {
69
- const index = this.encodedLiterals.get(value);
70
- this.warnings[index].location.push(toArrayLocation(location));
71
-
72
- return;
73
- }
74
- }
75
-
76
- this.warnings.push(generateWarning(name, { value, location }));
77
- if (isEncodedLiteral) {
78
- this.encodedLiterals.set(value, this.warnings.length - 1);
79
- }
80
- }
81
-
82
- analyzeLiteral(node, inArrayExpr = false) {
83
- if (typeof node.value !== "string" || Utils.isSvg(node)) {
84
- return;
85
- }
86
- this.deobfuscator.analyzeString(node.value);
87
-
88
- const { hasHexadecimalSequence, hasUnicodeSequence, isBase64 } = Literal.defaultAnalysis(node);
89
- if ((hasHexadecimalSequence || hasUnicodeSequence) && isBase64) {
90
- if (inArrayExpr) {
91
- this.deobfuscator.encodedArrayValue++;
92
- }
93
- else {
94
- this.addWarning("encoded-literal", node.value, node.loc);
95
- }
96
- }
97
- }
98
-
99
- getResult(isMinified) {
100
- const obfuscatorName = this.deobfuscator.assertObfuscation(this);
101
- if (obfuscatorName !== null) {
102
- this.addWarning("obfuscated-code", obfuscatorName);
103
- }
104
-
105
- const identifiersLengthArr = this.deobfuscator.identifiers
106
- .filter((value) => value.type !== "Property" && typeof value.name === "string")
107
- .map((value) => value.name.length);
108
-
109
- const [idsLengthAvg, stringScore] = [
110
- sum(identifiersLengthArr),
111
- sum(this.deobfuscator.literalScores)
112
- ];
113
- if (!isMinified && identifiersLengthArr.length > 5 && idsLengthAvg <= 1.5) {
114
- this.addWarning("short-identifiers", idsLengthAvg);
115
- }
116
- if (stringScore >= 3) {
117
- this.addWarning("suspicious-literal", stringScore);
118
- }
119
-
120
- if (this.encodedLiterals.size > kMaximumEncodedLiterals) {
121
- this.addWarning("suspicious-file", null);
122
- this.warnings = this.warnings
123
- .filter((warning) => warning.kind !== "encoded-literal");
124
- }
125
-
126
- return { idsLengthAvg, stringScore, warnings: this.warnings };
127
- }
128
-
129
- walk(node) {
130
- this.tracer.walk(node);
131
- this.deobfuscator.walk(node);
132
-
133
- // Detect TryStatement and CatchClause to known which dependency is required in a Try {} clause
134
- if (node.type === "TryStatement" && node.handler) {
135
- this.inTryStatement = true;
136
- }
137
- else if (node.type === "CatchClause") {
138
- this.inTryStatement = false;
139
- }
140
-
141
- return this.probesRunner.walk(node);
142
- }
143
- }
144
-
145
- function sum(arr = []) {
146
- return arr.length === 0 ? 0 : (arr.reduce((prev, curr) => prev + curr, 0) / arr.length);
147
- }
@@ -1,9 +0,0 @@
1
- // Import Third-party Dependencies
2
- import { Utils } from "@nodesecure/sec-literal";
3
-
4
- export function verify(identifiers, prefix) {
5
- const pValue = Object.keys(prefix).pop();
6
- const regexStr = `^${Utils.escapeRegExp(pValue)}[a-zA-Z]{1,2}[0-9]{0,2}$`;
7
-
8
- return identifiers.every(({ name }) => new RegExp(regexStr).test(name));
9
- }
@@ -1,27 +0,0 @@
1
- // Import Internal Dependencies
2
- import { notNullOrUndefined } from "../utils/index.js";
3
-
4
- // CONSTANTS
5
- const kJJRegularSymbols = new Set(["$", "_"]);
6
-
7
- export function verify(identifiers, counters) {
8
- if (counters.VariableDeclarator > 0 || counters.FunctionDeclaration > 0) {
9
- return false;
10
- }
11
- if (counters.AssignmentExpression > counters.Property) {
12
- return false;
13
- }
14
-
15
- const matchCount = identifiers.filter(({ name }) => {
16
- if (!notNullOrUndefined(name)) {
17
- return false;
18
- }
19
- const charsCode = [...new Set([...name])];
20
-
21
- return charsCode.every((char) => kJJRegularSymbols.has(char));
22
- }).length;
23
- const pourcent = ((matchCount / identifiers.length) * 100);
24
-
25
- return pourcent > 80;
26
- }
27
-
@@ -1,11 +0,0 @@
1
- // CONSTANTS
2
- const kJSFuckMinimumDoubleUnaryExpr = 5;
3
-
4
- export function verify(counters) {
5
- const hasZeroAssign = counters.AssignmentExpression === 0
6
- && counters.FunctionDeclaration === 0
7
- && counters.Property === 0
8
- && counters.VariableDeclarator === 0;
9
-
10
- return hasZeroAssign && counters.DoubleUnaryExpression >= kJSFuckMinimumDoubleUnaryExpr;
11
- }
@@ -1,13 +0,0 @@
1
- export function verify(deobfuscator, counters) {
2
- if ((counters.MemberExpression?.false ?? 0) > 0) {
3
- return false;
4
- }
5
-
6
- const hasSomePatterns = counters.DoubleUnaryExpression > 0
7
- || deobfuscator.deepBinaryExpression > 0
8
- || deobfuscator.encodedArrayValue > 0
9
- || deobfuscator.hasDictionaryString;
10
-
11
- // TODO: hasPrefixedIdentifiers only work for hexadecimal id names generator
12
- return deobfuscator.hasPrefixedIdentifiers && hasSomePatterns;
13
- }
@@ -1,28 +0,0 @@
1
- /**
2
- * Dangerous Unicode control characters that can be used by hackers
3
- * to perform trojan source.
4
- */
5
- const kUnsafeUnicodeControlCharacters = [
6
- "\u202A",
7
- "\u202B",
8
- "\u202D",
9
- "\u202E",
10
- "\u202C",
11
- "\u2066",
12
- "\u2067",
13
- "\u2068",
14
- "\u2069",
15
- "\u200E",
16
- "\u200F",
17
- "\u061C"
18
- ];
19
-
20
- export function verify(sourceString) {
21
- for (const unsafeCharacter of kUnsafeUnicodeControlCharacters) {
22
- if (sourceString.includes(unsafeCharacter)) {
23
- return true;
24
- }
25
- }
26
-
27
- return false;
28
- }
@@ -1,55 +0,0 @@
1
- /**
2
- * @description Search for BinaryExpression AST Node.
3
- *
4
- * @see https://github.com/estree/estree/blob/master/es5.md#binaryexpression
5
- * @example
6
- * 5 + 5 + 10
7
- */
8
- function validateNode(node) {
9
- return [
10
- node.type === "BinaryExpression"
11
- ];
12
- }
13
-
14
- function main(node, options) {
15
- const { sourceFile } = options;
16
-
17
- const [binaryExprDeepness, hasUnaryExpression] = walkBinaryExpression(node);
18
- if (binaryExprDeepness >= 3 && hasUnaryExpression) {
19
- sourceFile.deobfuscator.deepBinaryExpression++;
20
- }
21
- }
22
-
23
- /**
24
- * @description Look for suspicious BinaryExpression (read the Obfuscator.io section of the linked G.Doc)
25
- * @see https://docs.google.com/document/d/11ZrfW0bDQ-kd7Gr_Ixqyk8p3TGvxckmhFH3Z8dFoPhY/edit?usp=sharing
26
- * @see https://github.com/estree/estree/blob/master/es5.md#unaryexpression
27
- * @example
28
- * 0x1*-0x12df+-0x1fb9*-0x1+0x2*-0x66d
29
- */
30
- function walkBinaryExpression(expr, level = 1) {
31
- const [lt, rt] = [expr.left.type, expr.right.type];
32
- let hasUnaryExpression = lt === "UnaryExpression" || rt === "UnaryExpression";
33
- let currentLevel = lt === "BinaryExpression" || rt === "BinaryExpression" ? level + 1 : level;
34
-
35
- for (const currExpr of [expr.left, expr.right]) {
36
- if (currExpr.type === "BinaryExpression") {
37
- const [deepLevel, deepHasUnaryExpression] = walkBinaryExpression(currExpr, currentLevel);
38
- if (deepLevel > currentLevel) {
39
- currentLevel = deepLevel;
40
- }
41
- if (!hasUnaryExpression && deepHasUnaryExpression) {
42
- hasUnaryExpression = true;
43
- }
44
- }
45
- }
46
-
47
- return [currentLevel, hasUnaryExpression];
48
- }
49
-
50
- export default {
51
- name: "isBinaryExpression",
52
- validateNode,
53
- main,
54
- breakOnMatch: false
55
- };
@@ -1,31 +0,0 @@
1
- /**
2
- * @description Search for ESM Export
3
- *
4
- * @example
5
- * export { bar } from "./foo.js";
6
- * export * from "./bar.js";
7
- */
8
- function validateNode(node) {
9
- return [
10
- /**
11
- * We must be sure that the source property is a Literal to not fall in a trap
12
- * export const foo = "bar";
13
- */
14
- (node.type === "ExportNamedDeclaration" && node.source?.type === "Literal") ||
15
- node.type === "ExportAllDeclaration"
16
- ];
17
- }
18
-
19
- function main(node, { sourceFile }) {
20
- sourceFile.addDependency(
21
- node.source.value,
22
- node.loc
23
- );
24
- }
25
-
26
- export default {
27
- name: "isESMExport",
28
- validateNode,
29
- main,
30
- breakOnMatch: true
31
- };
@@ -1,19 +0,0 @@
1
- // Import Third-party Dependencies
2
- import { getCallExpressionIdentifier } from "@nodesecure/estree-ast-utils";
3
-
4
- function validateNode(node) {
5
- const id = getCallExpressionIdentifier(node);
6
-
7
- return [id === "fetch"];
8
- }
9
-
10
- function main(_node, { sourceFile }) {
11
- sourceFile.flags.add("fetch");
12
- }
13
-
14
- export default {
15
- name: "isFetch",
16
- validateNode,
17
- main,
18
- breakOnMatch: false
19
- };
@@ -1,33 +0,0 @@
1
- /**
2
- * @description Search for ESM ImportDeclaration
3
- * @see https://github.com/estree/estree/blob/master/es2015.md#importdeclaration
4
- * @example
5
- * import * as foo from "bar";
6
- * import fs from "fs";
7
- * import "make-promises-safe";
8
- */
9
- function validateNode(node) {
10
- return [
11
- // Note: the source property is the right-side Literal part of the Import
12
- ["ImportDeclaration", "ImportExpression"].includes(node.type) && node.source.type === "Literal"
13
- ];
14
- }
15
-
16
- function main(node, options) {
17
- const { sourceFile } = options;
18
-
19
- // Searching for dangerous import "data:text/javascript;..." statement.
20
- // see: https://2ality.com/2019/10/eval-via-import.html
21
- if (node.source.value.startsWith("data:text/javascript")) {
22
- sourceFile.addWarning("unsafe-import", node.source.value, node.loc);
23
- }
24
- sourceFile.addDependency(node.source.value, node.loc);
25
- }
26
-
27
- export default {
28
- name: "isImportDeclaration",
29
- validateNode,
30
- main,
31
- breakOnMatch: true,
32
- breakGroup: "import"
33
- };
@@ -1,70 +0,0 @@
1
- // Import Node.js Dependencies
2
- import { builtinModules } from "module";
3
-
4
- // Import Third-party Dependencies
5
- import { Hex } from "@nodesecure/sec-literal";
6
-
7
- const kMapRegexIps = Object.freeze({
8
- // eslint-disable-next-line @stylistic/max-len
9
- regexIPv4: /^(https?:\/\/)(?!127\.)(?!.*:(?:0{1,3}|25[6-9])\.)(?!.*:(?:25[6-9])\.(?:0{1,3}|25[6-9])\.)(?!.*:(?:25[6-9])\.(?:25[6-9])\.(?:0{1,3}|25[6-9])\.)(?!.*:(?:25[6-9])\.(?:25[6-9])\.(?:25[6-9])\.(?:0{1,3}|25[6-9]))((?:\d{1,2}|1\d{2}|2[0-4]\d|25[0-5])\.){3}(?:\d{1,2}|1\d{2}|2[0-4]\d|25[0-5])(?::\d{1,5})?(\/[^\s]*)?$/,
10
- regexIPv6: /^(https?:\/\/)(\[[0-9A-Fa-f:]+\])(?::\d{1,5})?(\/[^\s]*)?$/
11
- });
12
-
13
- // CONSTANTS
14
- const kNodeDeps = new Set(builtinModules);
15
- const kShadyLinkRegExps = [
16
- kMapRegexIps.regexIPv4,
17
- kMapRegexIps.regexIPv6,
18
- /(http[s]?:\/\/(bit\.ly|ipinfo\.io|httpbin\.org).*)$/,
19
- /(http[s]?:\/\/.*\.(link|xyz|tk|ml|ga|cf|gq|pw|top|club|mw|bd|ke|am|sbs|date|quest|cd|bid|cd|ws|icu|cam|uno|email|stream))$/
20
- ];
21
- /**
22
- * @description Search for Literal AST Node
23
- * @see https://github.com/estree/estree/blob/master/es5.md#literal
24
- * @example
25
- * "foobar"
26
- */
27
- function validateNode(node) {
28
- return [
29
- node.type === "Literal" && typeof node.value === "string"
30
- ];
31
- }
32
-
33
- function main(node, options) {
34
- const { sourceFile } = options;
35
-
36
- // We are searching for value obfuscated as hex of a minimum length of 4.
37
- if (/^[0-9A-Fa-f]{4,}$/g.test(node.value)) {
38
- const value = Buffer.from(node.value, "hex").toString();
39
- sourceFile.deobfuscator.analyzeString(value);
40
-
41
- // If the value we are retrieving is the name of a Node.js dependency,
42
- // then we add it to the dependencies list and we throw an unsafe-import at the current location.
43
- if (kNodeDeps.has(value)) {
44
- sourceFile.addDependency(value, node.loc);
45
- sourceFile.addWarning("unsafe-import", null, node.loc);
46
- }
47
- else if (value === "require" || !Hex.isSafe(node.value)) {
48
- sourceFile.addWarning("encoded-literal", node.value, node.loc);
49
- }
50
- }
51
- // Else we are checking all other string with our suspect method
52
- else {
53
- for (const regex of kShadyLinkRegExps) {
54
- if (regex.test(node.value)) {
55
- sourceFile.addWarning("shady-link", node.value, node.loc);
56
-
57
- return;
58
- }
59
- }
60
-
61
- sourceFile.analyzeLiteral(node);
62
- }
63
- }
64
-
65
- export default {
66
- name: "isLiteral",
67
- validateNode,
68
- main,
69
- breakOnMatch: false
70
- };
@@ -1,31 +0,0 @@
1
- // Require Third-party Dependencies
2
- import { isLiteralRegex } from "@nodesecure/estree-ast-utils";
3
- import safeRegex from "safe-regex";
4
-
5
- /**
6
- * @description Search for RegExpLiteral AST Node
7
- * @see https://github.com/estree/estree/blob/master/es5.md#regexpliteral
8
- * @example
9
- * /hello/
10
- */
11
- function validateNode(node) {
12
- return [
13
- isLiteralRegex(node)
14
- ];
15
- }
16
-
17
- function main(node, options) {
18
- const { sourceFile } = options;
19
-
20
- // We use the safe-regex package to detect whether or not regex is safe!
21
- if (!safeRegex(node.regex.pattern)) {
22
- sourceFile.addWarning("unsafe-regex", node.regex.pattern, node.loc);
23
- }
24
- }
25
-
26
- export default {
27
- name: "isLiteralRegex",
28
- validateNode,
29
- main,
30
- breakOnMatch: false
31
- };
@@ -1,49 +0,0 @@
1
- // Import Third-party Dependencies
2
- import { isLiteralRegex } from "@nodesecure/estree-ast-utils";
3
- import safeRegex from "safe-regex";
4
-
5
- /**
6
- * @description Search for Regex Object constructor.
7
- * @see https://github.com/estree/estree/blob/master/es5.md#newexpression
8
- * @example
9
- * new RegExp("...");
10
- */
11
- function validateNode(node) {
12
- return [
13
- isRegexConstructor(node) && node.arguments.length > 0
14
- ];
15
- }
16
-
17
- function main(node, options) {
18
- const { sourceFile } = options;
19
-
20
- const arg = node.arguments[0];
21
- /**
22
- * Note: RegExp Object can contain a RegExpLiteral
23
- * @see https://github.com/estree/estree/blob/master/es5.md#regexpliteral
24
- *
25
- * @example
26
- * new RegExp(/^foo/)
27
- */
28
- const pattern = isLiteralRegex(arg) ? arg.regex.pattern : arg.value;
29
-
30
- // We use the safe-regex package to detect whether or not regex is safe!
31
- if (!safeRegex(pattern)) {
32
- sourceFile.addWarning("unsafe-regex", pattern, node.loc);
33
- }
34
- }
35
-
36
- function isRegexConstructor(node) {
37
- if (node.type !== "NewExpression" || node.callee.type !== "Identifier") {
38
- return false;
39
- }
40
-
41
- return node.callee.name === "RegExp";
42
- }
43
-
44
- export default {
45
- name: "isRegexObject",
46
- validateNode,
47
- main,
48
- breakOnMatch: false
49
- };