@dacely/toildefender 0.1.0 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +661 -661
- package/NOTICE.md +16 -16
- package/README.md +467 -380
- package/cli.js +168 -168
- package/defendjs.js +6 -6
- package/docs/all-modes-output.demo.js +673 -673
- package/estest.js +49 -49
- package/esutils.js +107 -107
- package/logger.js +28 -28
- package/obfuscator.js +534 -534
- package/package.json +108 -108
- package/processors/deadCode.js +62 -62
- package/processors/flattener.js +808 -808
- package/processors/health.js +55 -55
- package/processors/identifiers.js +256 -256
- package/processors/literalObfuscator.js +40 -40
- package/processors/literals.js +233 -233
- package/processors/methods.js +332 -332
- package/processors/modules.js +231 -231
- package/processors/normalizer.js +490 -490
- package/processors/numericVm.js +950 -950
- package/processors/postprocessing.js +69 -69
- package/processors/preprocessing.js +248 -248
- package/processors/scopes.js +177 -177
- package/processors/uglifier.js +25 -25
- package/processors/variables.js +185 -185
- package/toildefender.js +7 -7
- package/traverser.js +115 -115
- package/utils.js +135 -135
package/processors/modules.js
CHANGED
|
@@ -1,231 +1,231 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
var assert = require("assert");
|
|
4
|
-
var path = require("path");
|
|
5
|
-
|
|
6
|
-
var _ = require("lodash");
|
|
7
|
-
var escope = require("escope");
|
|
8
|
-
|
|
9
|
-
var estest = require("../estest");
|
|
10
|
-
var traverser = require("../traverser");
|
|
11
|
-
var ESUtils = require("../esutils");
|
|
12
|
-
var utils = require("../utils");
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* Transform calls to require().
|
|
16
|
-
* @param {Node} node Root node
|
|
17
|
-
* @param {Function} processor Transformer
|
|
18
|
-
* @returns {Node} Root node
|
|
19
|
-
*/
|
|
20
|
-
function findRequires(node, processor) {
|
|
21
|
-
assert.ok(estest.isNode(node));
|
|
22
|
-
assert.equal(typeof processor, "function");
|
|
23
|
-
|
|
24
|
-
return traverser.traverse(node, [], (node, stack) => {
|
|
25
|
-
if (node.type == "CallExpression" && node.callee.type == "Identifier" && node.callee.name == "require") {
|
|
26
|
-
return processor(node, stack);
|
|
27
|
-
} else {
|
|
28
|
-
return node;
|
|
29
|
-
}
|
|
30
|
-
});
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
/**
|
|
34
|
-
* Split path into parts.
|
|
35
|
-
* @param {string} path
|
|
36
|
-
* @returns {string[]}
|
|
37
|
-
*/
|
|
38
|
-
function splitPath(path) {
|
|
39
|
-
return path.split(/[\/\\]/g).filter(x => x != null && x.length > 0);
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
/**
|
|
43
|
-
* Normalize path.
|
|
44
|
-
* @param {string[]} path
|
|
45
|
-
* @returns {string}
|
|
46
|
-
*/
|
|
47
|
-
function normalizePath(path) {
|
|
48
|
-
var parts = splitPath(path);
|
|
49
|
-
|
|
50
|
-
for (var i = parts.length - 1; i >= 0; --i) {
|
|
51
|
-
if (parts[i] == "" || parts[i] == ".") {
|
|
52
|
-
parts.splice(i, 1);
|
|
53
|
-
} else if (parts[i] == "..") {
|
|
54
|
-
parts.splice(i - 1, 2);
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
return parts.join("/");
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
/**
|
|
62
|
-
* Get directory from path.
|
|
63
|
-
* @param {string} path
|
|
64
|
-
* @returns {string}
|
|
65
|
-
*/
|
|
66
|
-
function getPathDir(path) {
|
|
67
|
-
return splitPath(path).slice(0, -1).join("/");
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
/**
|
|
71
|
-
* Resolve path.
|
|
72
|
-
* TODO: This doesnt work as expected when path starts with a slash. Fix this.
|
|
73
|
-
* @param {string} curr Executing script
|
|
74
|
-
* @param {string} path Path
|
|
75
|
-
* @returns {string}
|
|
76
|
-
*/
|
|
77
|
-
function resolvePath(curr, path) {
|
|
78
|
-
return normalizePath(getPathDir(curr) + "/" + path);
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
module.exports = class Modules {
|
|
82
|
-
|
|
83
|
-
constructor (logger) {
|
|
84
|
-
this.logger = logger;
|
|
85
|
-
this.esutils = new ESUtils(logger);
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
/**
|
|
89
|
-
* Replace references to exports and module.exports.
|
|
90
|
-
* @param {Node} ast Root node
|
|
91
|
-
* @param {Node} replacement Replacement
|
|
92
|
-
* @returns {Node} Root node
|
|
93
|
-
*/
|
|
94
|
-
replaceExportsReferences (ast, replacement) {
|
|
95
|
-
this.esutils.setParentsRecursive(ast);
|
|
96
|
-
|
|
97
|
-
var scopeManager = escope.analyze(ast, { optimistic: true });
|
|
98
|
-
|
|
99
|
-
scopeManager.scopes.forEach(scope => {
|
|
100
|
-
scope.references
|
|
101
|
-
.filter(reference => !utils.isResolvedReference(reference))
|
|
102
|
-
.forEach(reference => {
|
|
103
|
-
var parent = reference.identifier.veilmark$parent;
|
|
104
|
-
|
|
105
|
-
if (reference.identifier.name == "exports") {
|
|
106
|
-
this.esutils.replaceNode(ast, reference.identifier, utils.cloneISwearIKnowWhatImDoing(replacement));
|
|
107
|
-
} else if (
|
|
108
|
-
parent.type == "MemberExpression"
|
|
109
|
-
&& (parent.object.type == "Identifier" && parent.object.name == "module")
|
|
110
|
-
&& ((parent.property.type == "Identifier" && parent.property.name == "exports") || (parent.property.type == "Literal" && parent.property.value == "exports"))
|
|
111
|
-
) {
|
|
112
|
-
this.esutils.replaceNode(ast, parent, utils.cloneISwearIKnowWhatImDoing(replacement));
|
|
113
|
-
}
|
|
114
|
-
});
|
|
115
|
-
});
|
|
116
|
-
|
|
117
|
-
return ast;
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
/**
|
|
121
|
-
* Merges multiple modules into a single main module.
|
|
122
|
-
* @param {Object.<string, Node>} modules Module dictionary
|
|
123
|
-
* @param {string} mainKey Main module key
|
|
124
|
-
* @param {ScopeManager} scopeManager Scope manager
|
|
125
|
-
* @returns {Node} Transformed root node
|
|
126
|
-
*/
|
|
127
|
-
merge (modules, mainKey, scopeManager) {
|
|
128
|
-
assert.ok(Object.keys(modules).length > 0);
|
|
129
|
-
assert.equal(typeof mainKey, "string");
|
|
130
|
-
|
|
131
|
-
modules = _.mapKeys(modules, (value, key) => normalizePath(key));
|
|
132
|
-
mainKey = normalizePath(mainKey);
|
|
133
|
-
|
|
134
|
-
var declaration = {
|
|
135
|
-
type: "VariableDeclaration",
|
|
136
|
-
kind: "var",
|
|
137
|
-
declarations: []
|
|
138
|
-
};
|
|
139
|
-
var embeds = [];
|
|
140
|
-
|
|
141
|
-
var rng = new utils.UniqueRandomAlpha(3);
|
|
142
|
-
|
|
143
|
-
var processedModules = {};
|
|
144
|
-
|
|
145
|
-
var requiresOrder = [];
|
|
146
|
-
|
|
147
|
-
function walkDeps(key, stack) {
|
|
148
|
-
stack = stack || [];
|
|
149
|
-
|
|
150
|
-
findRequires(modules[key], node => {
|
|
151
|
-
var path = node.arguments.length > 0 && node.arguments[0].value;
|
|
152
|
-
|
|
153
|
-
if (!path) {
|
|
154
|
-
return node;
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
if (![ "/", "./", "../" ].some(x => path.indexOf(x) == 0)) {
|
|
158
|
-
return node;
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
path = resolvePath(key, path);
|
|
162
|
-
|
|
163
|
-
if (path.slice(-3) == ".js") {
|
|
164
|
-
path = path.slice(0, -3);
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
if (!modules[path]) {
|
|
168
|
-
path = path + ".js";
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
requiresOrder.push(path);
|
|
172
|
-
|
|
173
|
-
var _module = modules[path];
|
|
174
|
-
if (!_module) {
|
|
175
|
-
this.logger.warn(`Local module not found: ${path}`);
|
|
176
|
-
return node;
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
if (stack.indexOf(path) == -1) {
|
|
180
|
-
walkDeps.call(this, path, stack.concat(path));
|
|
181
|
-
} else {
|
|
182
|
-
this.logger.warn("Skipping cyclic depedency: " + path);
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
if (!processedModules[path]) {
|
|
186
|
-
var id = processedModules[path] = "$$module$" + rng.get();
|
|
187
|
-
|
|
188
|
-
declaration.declarations.push({
|
|
189
|
-
type: "VariableDeclarator",
|
|
190
|
-
id: { type: "Identifier", name: id },
|
|
191
|
-
init: { type: "ObjectExpression", properties: [] }
|
|
192
|
-
});
|
|
193
|
-
|
|
194
|
-
_module = this.replaceExportsReferences(_module, { type: "Identifier", name: id });
|
|
195
|
-
|
|
196
|
-
embeds.push({
|
|
197
|
-
type: "ExpressionStatement",
|
|
198
|
-
expression: {
|
|
199
|
-
type: "CallExpression",
|
|
200
|
-
callee: {
|
|
201
|
-
type: "FunctionExpression",
|
|
202
|
-
params: [
|
|
203
|
-
],
|
|
204
|
-
body: {
|
|
205
|
-
type: "BlockStatement",
|
|
206
|
-
body: _module.body
|
|
207
|
-
}
|
|
208
|
-
},
|
|
209
|
-
arguments: [
|
|
210
|
-
|
|
211
|
-
]
|
|
212
|
-
},
|
|
213
|
-
veilmark$module: path
|
|
214
|
-
});
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
return { type: "Identifier", name: processedModules[path] };
|
|
218
|
-
});
|
|
219
|
-
}
|
|
220
|
-
// Method has to be called via .call because otherwise this is not being passed correctly for some reason
|
|
221
|
-
walkDeps.call(this, mainKey);
|
|
222
|
-
|
|
223
|
-
// Check whether the VariableDeclaration contains VariableDeclarators, because an empty VariableDeclaration causes errors
|
|
224
|
-
if (declaration.declarations.length > 0) {
|
|
225
|
-
modules[mainKey].body = [ declaration ].concat(embeds).concat(modules[mainKey].body);
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
return modules[mainKey];
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
};
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var assert = require("assert");
|
|
4
|
+
var path = require("path");
|
|
5
|
+
|
|
6
|
+
var _ = require("lodash");
|
|
7
|
+
var escope = require("escope");
|
|
8
|
+
|
|
9
|
+
var estest = require("../estest");
|
|
10
|
+
var traverser = require("../traverser");
|
|
11
|
+
var ESUtils = require("../esutils");
|
|
12
|
+
var utils = require("../utils");
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Transform calls to require().
|
|
16
|
+
* @param {Node} node Root node
|
|
17
|
+
* @param {Function} processor Transformer
|
|
18
|
+
* @returns {Node} Root node
|
|
19
|
+
*/
|
|
20
|
+
function findRequires(node, processor) {
|
|
21
|
+
assert.ok(estest.isNode(node));
|
|
22
|
+
assert.equal(typeof processor, "function");
|
|
23
|
+
|
|
24
|
+
return traverser.traverse(node, [], (node, stack) => {
|
|
25
|
+
if (node.type == "CallExpression" && node.callee.type == "Identifier" && node.callee.name == "require") {
|
|
26
|
+
return processor(node, stack);
|
|
27
|
+
} else {
|
|
28
|
+
return node;
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Split path into parts.
|
|
35
|
+
* @param {string} path
|
|
36
|
+
* @returns {string[]}
|
|
37
|
+
*/
|
|
38
|
+
function splitPath(path) {
|
|
39
|
+
return path.split(/[\/\\]/g).filter(x => x != null && x.length > 0);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Normalize path.
|
|
44
|
+
* @param {string[]} path
|
|
45
|
+
* @returns {string}
|
|
46
|
+
*/
|
|
47
|
+
function normalizePath(path) {
|
|
48
|
+
var parts = splitPath(path);
|
|
49
|
+
|
|
50
|
+
for (var i = parts.length - 1; i >= 0; --i) {
|
|
51
|
+
if (parts[i] == "" || parts[i] == ".") {
|
|
52
|
+
parts.splice(i, 1);
|
|
53
|
+
} else if (parts[i] == "..") {
|
|
54
|
+
parts.splice(i - 1, 2);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
return parts.join("/");
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Get directory from path.
|
|
63
|
+
* @param {string} path
|
|
64
|
+
* @returns {string}
|
|
65
|
+
*/
|
|
66
|
+
function getPathDir(path) {
|
|
67
|
+
return splitPath(path).slice(0, -1).join("/");
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Resolve path.
|
|
72
|
+
* TODO: This doesnt work as expected when path starts with a slash. Fix this.
|
|
73
|
+
* @param {string} curr Executing script
|
|
74
|
+
* @param {string} path Path
|
|
75
|
+
* @returns {string}
|
|
76
|
+
*/
|
|
77
|
+
function resolvePath(curr, path) {
|
|
78
|
+
return normalizePath(getPathDir(curr) + "/" + path);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
module.exports = class Modules {
|
|
82
|
+
|
|
83
|
+
constructor (logger) {
|
|
84
|
+
this.logger = logger;
|
|
85
|
+
this.esutils = new ESUtils(logger);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Replace references to exports and module.exports.
|
|
90
|
+
* @param {Node} ast Root node
|
|
91
|
+
* @param {Node} replacement Replacement
|
|
92
|
+
* @returns {Node} Root node
|
|
93
|
+
*/
|
|
94
|
+
replaceExportsReferences (ast, replacement) {
|
|
95
|
+
this.esutils.setParentsRecursive(ast);
|
|
96
|
+
|
|
97
|
+
var scopeManager = escope.analyze(ast, { optimistic: true });
|
|
98
|
+
|
|
99
|
+
scopeManager.scopes.forEach(scope => {
|
|
100
|
+
scope.references
|
|
101
|
+
.filter(reference => !utils.isResolvedReference(reference))
|
|
102
|
+
.forEach(reference => {
|
|
103
|
+
var parent = reference.identifier.veilmark$parent;
|
|
104
|
+
|
|
105
|
+
if (reference.identifier.name == "exports") {
|
|
106
|
+
this.esutils.replaceNode(ast, reference.identifier, utils.cloneISwearIKnowWhatImDoing(replacement));
|
|
107
|
+
} else if (
|
|
108
|
+
parent.type == "MemberExpression"
|
|
109
|
+
&& (parent.object.type == "Identifier" && parent.object.name == "module")
|
|
110
|
+
&& ((parent.property.type == "Identifier" && parent.property.name == "exports") || (parent.property.type == "Literal" && parent.property.value == "exports"))
|
|
111
|
+
) {
|
|
112
|
+
this.esutils.replaceNode(ast, parent, utils.cloneISwearIKnowWhatImDoing(replacement));
|
|
113
|
+
}
|
|
114
|
+
});
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
return ast;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Merges multiple modules into a single main module.
|
|
122
|
+
* @param {Object.<string, Node>} modules Module dictionary
|
|
123
|
+
* @param {string} mainKey Main module key
|
|
124
|
+
* @param {ScopeManager} scopeManager Scope manager
|
|
125
|
+
* @returns {Node} Transformed root node
|
|
126
|
+
*/
|
|
127
|
+
merge (modules, mainKey, scopeManager) {
|
|
128
|
+
assert.ok(Object.keys(modules).length > 0);
|
|
129
|
+
assert.equal(typeof mainKey, "string");
|
|
130
|
+
|
|
131
|
+
modules = _.mapKeys(modules, (value, key) => normalizePath(key));
|
|
132
|
+
mainKey = normalizePath(mainKey);
|
|
133
|
+
|
|
134
|
+
var declaration = {
|
|
135
|
+
type: "VariableDeclaration",
|
|
136
|
+
kind: "var",
|
|
137
|
+
declarations: []
|
|
138
|
+
};
|
|
139
|
+
var embeds = [];
|
|
140
|
+
|
|
141
|
+
var rng = new utils.UniqueRandomAlpha(3);
|
|
142
|
+
|
|
143
|
+
var processedModules = {};
|
|
144
|
+
|
|
145
|
+
var requiresOrder = [];
|
|
146
|
+
|
|
147
|
+
function walkDeps(key, stack) {
|
|
148
|
+
stack = stack || [];
|
|
149
|
+
|
|
150
|
+
findRequires(modules[key], node => {
|
|
151
|
+
var path = node.arguments.length > 0 && node.arguments[0].value;
|
|
152
|
+
|
|
153
|
+
if (!path) {
|
|
154
|
+
return node;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
if (![ "/", "./", "../" ].some(x => path.indexOf(x) == 0)) {
|
|
158
|
+
return node;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
path = resolvePath(key, path);
|
|
162
|
+
|
|
163
|
+
if (path.slice(-3) == ".js") {
|
|
164
|
+
path = path.slice(0, -3);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
if (!modules[path]) {
|
|
168
|
+
path = path + ".js";
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
requiresOrder.push(path);
|
|
172
|
+
|
|
173
|
+
var _module = modules[path];
|
|
174
|
+
if (!_module) {
|
|
175
|
+
this.logger.warn(`Local module not found: ${path}`);
|
|
176
|
+
return node;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
if (stack.indexOf(path) == -1) {
|
|
180
|
+
walkDeps.call(this, path, stack.concat(path));
|
|
181
|
+
} else {
|
|
182
|
+
this.logger.warn("Skipping cyclic depedency: " + path);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
if (!processedModules[path]) {
|
|
186
|
+
var id = processedModules[path] = "$$module$" + rng.get();
|
|
187
|
+
|
|
188
|
+
declaration.declarations.push({
|
|
189
|
+
type: "VariableDeclarator",
|
|
190
|
+
id: { type: "Identifier", name: id },
|
|
191
|
+
init: { type: "ObjectExpression", properties: [] }
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
_module = this.replaceExportsReferences(_module, { type: "Identifier", name: id });
|
|
195
|
+
|
|
196
|
+
embeds.push({
|
|
197
|
+
type: "ExpressionStatement",
|
|
198
|
+
expression: {
|
|
199
|
+
type: "CallExpression",
|
|
200
|
+
callee: {
|
|
201
|
+
type: "FunctionExpression",
|
|
202
|
+
params: [
|
|
203
|
+
],
|
|
204
|
+
body: {
|
|
205
|
+
type: "BlockStatement",
|
|
206
|
+
body: _module.body
|
|
207
|
+
}
|
|
208
|
+
},
|
|
209
|
+
arguments: [
|
|
210
|
+
|
|
211
|
+
]
|
|
212
|
+
},
|
|
213
|
+
veilmark$module: path
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
return { type: "Identifier", name: processedModules[path] };
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
// Method has to be called via .call because otherwise this is not being passed correctly for some reason
|
|
221
|
+
walkDeps.call(this, mainKey);
|
|
222
|
+
|
|
223
|
+
// Check whether the VariableDeclaration contains VariableDeclarators, because an empty VariableDeclaration causes errors
|
|
224
|
+
if (declaration.declarations.length > 0) {
|
|
225
|
+
modules[mainKey].body = [ declaration ].concat(embeds).concat(modules[mainKey].body);
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
return modules[mainKey];
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
};
|