@dacely/toildefender 0.1.3 → 0.1.5
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/README.md +86 -57
- package/docs/all-modes-output.demo.js +1016 -670
- package/esutils.js +11 -1
- package/obfuscator.js +194 -23
- package/package.json +3 -26
- package/processors/deadCode.js +5 -1
- package/processors/flattener.js +56 -32
- package/processors/identifiers.js +9 -15
- package/processors/methods.js +109 -7
- package/processors/normalizer.js +946 -22
- package/processors/numericVm.js +179 -77
- package/processors/scopes.js +25 -0
- package/processors/variables.js +86 -2
- package/traverser.js +8 -2
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<div align="center">
|
|
2
2
|
|
|
3
|
-
<img src="./images/
|
|
3
|
+
<img src="./images/toildefender6.svg" alt="ToilDefender" width="600" />
|
|
4
4
|
|
|
5
5
|
|
|
6
6
|
### JavaScript code protection for the Toil stack.
|
|
@@ -99,6 +99,12 @@ the bytecode into encrypted BigInt streams, and executes it through a generated
|
|
|
99
99
|
runtime VM. Instead of exposing readable JavaScript logic, your code becomes
|
|
100
100
|
numeric program data consumed by a randomized virtual machine.
|
|
101
101
|
|
|
102
|
+
The compiler also fuses selected hot stack patterns into semantic
|
|
103
|
+
superinstructions, so common operation boundaries such as constant-key property
|
|
104
|
+
reads are not always emitted as separate primitive VM opcodes.
|
|
105
|
+
Constants are wrapped in access-bound cells, so encoded strings and references
|
|
106
|
+
are decoded lazily when bytecode reads them instead of during VM call setup.
|
|
107
|
+
|
|
102
108
|
Original logic disappears from the output bundle. Attackers no longer reverse
|
|
103
109
|
plain JavaScript; they must recover the VM, decode the bytecode format,
|
|
104
110
|
reconstruct the instruction set, and emulate the protected program.
|
|
@@ -155,7 +161,8 @@ function licenseGate(input) {
|
|
|
155
161
|
globalThis.__result = licenseGate("Veilmark");
|
|
156
162
|
```
|
|
157
163
|
|
|
158
|
-
The demo artifact is generated with every major protection enabled
|
|
164
|
+
The demo artifact is generated with every major protection enabled and
|
|
165
|
+
compression disabled so the runtime stays readable:
|
|
159
166
|
|
|
160
167
|
```js
|
|
161
168
|
features: {
|
|
@@ -167,7 +174,7 @@ features: {
|
|
|
167
174
|
object_packing: true,
|
|
168
175
|
literals: true,
|
|
169
176
|
mangle: true,
|
|
170
|
-
compress:
|
|
177
|
+
compress: false
|
|
171
178
|
},
|
|
172
179
|
protections: {
|
|
173
180
|
virtualMachine: {
|
|
@@ -194,19 +201,20 @@ protections: {
|
|
|
194
201
|
|
|
195
202
|
The complete beautified generated output is committed at
|
|
196
203
|
[docs/all-modes-output.demo.js](./docs/all-modes-output.demo.js). It is a real
|
|
197
|
-
|
|
204
|
+
1019-line artifact from the current generator and executes to:
|
|
198
205
|
|
|
199
206
|
Output excerpt:
|
|
200
207
|
|
|
201
208
|
```js
|
|
202
209
|
(function () {
|
|
203
|
-
function a(f,
|
|
204
|
-
var b = new Array(
|
|
210
|
+
function a(f, k) {
|
|
211
|
+
var b = new Array(109);
|
|
205
212
|
;
|
|
206
213
|
var c = arguments;
|
|
214
|
+
var i;
|
|
207
215
|
while (true) try {
|
|
208
216
|
switch (f) {
|
|
209
|
-
case
|
|
217
|
+
case 24210:
|
|
210
218
|
b[11] = c[11];
|
|
211
219
|
b[12] = c[10];
|
|
212
220
|
b[13] = c[9];
|
|
@@ -217,69 +225,76 @@ Output excerpt:
|
|
|
217
225
|
b[18] = c[4];
|
|
218
226
|
b[19] = c[3];
|
|
219
227
|
b[20] = c[2];
|
|
220
|
-
b[21] = e(a,
|
|
221
|
-
b[22] = e(a,
|
|
222
|
-
b[23] = e(a,
|
|
223
|
-
b[24] = e(a,
|
|
224
|
-
b[25] = e(a,
|
|
225
|
-
b[26] = e(a,
|
|
228
|
+
b[21] = e(a, 16503, b, c[1]);
|
|
229
|
+
b[22] = e(a, 16827, b, c[1]);
|
|
230
|
+
b[23] = e(a, 28881, b, c[1]);
|
|
231
|
+
b[24] = e(a, 27718, b, c[1]);
|
|
232
|
+
b[25] = e(a, 26046, b, c[1]);
|
|
233
|
+
b[26] = e(a, 11984, b, c[1]);
|
|
234
|
+
b[27] = e(a, 10989, b, c[1]);
|
|
235
|
+
b[28] = e(a, 10700, b, c[1]);
|
|
236
|
+
b[29] = e(a, 18606, b, c[1]);
|
|
237
|
+
b[30] = e(a, 22347, b, c[1]);
|
|
238
|
+
b[31] = e(a, 28683, b, c[1]);
|
|
239
|
+
b[32] = e(a, 11069, b, c[1]);
|
|
240
|
+
b[33] = e(a, 8443, b, c[1]);
|
|
241
|
+
b[34] = e(a, 27840, b, c[1]);
|
|
242
|
+
b[35] = e(a, 21656, b, c[1]);
|
|
243
|
+
b[36] = BigInt(b[19]);
|
|
244
|
+
b[37] = [1n];
|
|
245
|
+
b[38] = c[1][10][1];
|
|
246
|
+
b[39] = c[1][10][1];
|
|
226
247
|
if (b[11]) {
|
|
227
|
-
b[
|
|
248
|
+
b[38] = c[1][4](b[11], b[19], b[18], b[17], b[16], b[12]);
|
|
249
|
+
b[39] = b[11][c[1][10][24]] >>> c[1][10][1];
|
|
228
250
|
}
|
|
229
|
-
b[
|
|
230
|
-
b[
|
|
231
|
-
b[
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
b[32] = Number(b[20] % b[30]);
|
|
236
|
-
b[20] = b[20] / b[30];
|
|
237
|
-
b[33] = c[1][9][5] + (b[28] >>> c[1][9][24]) % (b[19] - c[1][9][5]);
|
|
238
|
-
b[34] = b[28] % b[19];
|
|
239
|
-
b[35] = (b[32] - b[34] + b[19]) % b[19] * b[26](b[33], b[19]) % b[19];
|
|
240
|
-
b[27][c[1][9][29]](b[35]);
|
|
241
|
-
b[29] = b[25](b[29], b[32], b[31]);
|
|
242
|
-
b[28] = b[25](b[28], b[32], b[31]);
|
|
243
|
-
b[31] += c[1][9][5];
|
|
251
|
+
b[40] = c[1][10][1];
|
|
252
|
+
b[41] = b[17] >>> c[1][10][1];
|
|
253
|
+
while (b[40] < b[18]) {
|
|
254
|
+
b[42] = b[33](b[40]);
|
|
255
|
+
b[41] = b[34](b[41], b[42], b[40]);
|
|
256
|
+
b[40] += c[1][10][5];
|
|
244
257
|
}
|
|
245
|
-
if (b[
|
|
246
|
-
b[
|
|
247
|
-
b[
|
|
248
|
-
b[
|
|
249
|
-
b[
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
258
|
+
if (b[41] >>> c[1][10][1] !== b[16] >>> c[1][10][1]) throw new Error(c[1][10][29]);
|
|
259
|
+
b[43] = c[1][10][1];
|
|
260
|
+
b[44] = b[17] >>> c[1][10][1];
|
|
261
|
+
b[45] = b[17] & c[1][10][5];
|
|
262
|
+
b[46] = b[45] ? c[1][10][30] : [];
|
|
263
|
+
b[47] = b[45] ? c[1][10][30] : [];
|
|
264
|
+
b[48] = b[45] ? g([
|
|
265
|
+
/* encoded layout keys */
|
|
266
|
+
], [
|
|
267
|
+
[],
|
|
268
|
+
Object[c[1][10][36]](c[1][10][30])
|
|
269
|
+
]) : c[1][10][30];
|
|
270
|
+
|
|
271
|
+
/* 900+ more generated lines:
|
|
272
|
+
dispatcher cases, encoded literals, streaming VM token reads,
|
|
273
|
+
lazy constant cells, seed-selected stack/local storage, BigInt program blobs,
|
|
274
|
+
semantic superinstructions, randomized opcode tables,
|
|
275
|
+
and Hash-Mesh unwrap */
|
|
276
|
+
|
|
277
|
+
case 27718:
|
|
278
|
+
if (c[1][50] < c[2][10][1] || c[1][50] >= c[1][18]) throw new Error(c[2][10][46]);
|
|
279
|
+
b[1] = c[1][31](c[1][50]);
|
|
280
|
+
c[1][50] += c[2][10][5];
|
|
281
|
+
return b[1];
|
|
282
|
+
case 30063:
|
|
267
283
|
b[1] = '';
|
|
268
|
-
b[1] += d(86, 101);
|
|
269
|
-
b[1] += d(
|
|
270
|
-
b[1] += d(114);
|
|
271
|
-
b[1] += d(107);
|
|
284
|
+
b[1] += d(86, 101, 105);
|
|
285
|
+
b[1] += d(108, 109);
|
|
286
|
+
b[1] += d(97, 114, 107);
|
|
272
287
|
return b[1];
|
|
273
288
|
}
|
|
274
289
|
} catch (a) {
|
|
275
|
-
|
|
290
|
+
i = null;
|
|
276
291
|
switch (f) {
|
|
277
292
|
default:
|
|
278
293
|
throw a;
|
|
279
294
|
}
|
|
280
295
|
}
|
|
281
296
|
}
|
|
282
|
-
a(
|
|
297
|
+
a(20498, {});
|
|
283
298
|
})();
|
|
284
299
|
```
|
|
285
300
|
|
|
@@ -392,12 +407,26 @@ Main options:
|
|
|
392
407
|
| `code` | Entry source code. |
|
|
393
408
|
| `modulesCode` | Map of dependency filename to source code. |
|
|
394
409
|
| `features` | Feature switches for the classic pipeline. |
|
|
410
|
+
| `babel` | Defaults to `false`; set to `true` only when you want the optional Babel downlevel transform before protection. |
|
|
411
|
+
| `babelPreserveAsync` | Defaults to `true`; when `babel: true`, keeps async/generator syntax native so async-aware flattening can avoid Babel regenerator helper bloat. Set to `false` for legacy async lowering. |
|
|
395
412
|
| `protections.virtualMachine` | User-facing VM bytecode backend configuration. |
|
|
396
413
|
| `protections.hashMesh` | User-facing hash-mesh unlock configuration. |
|
|
397
414
|
| `numericVm` | Lower-level numeric VM configuration retained for internal callers. |
|
|
398
415
|
| `preprocessorVariables` | Compile-time preprocessor constants. |
|
|
399
416
|
| `logLevel` | `error`, `warn`, `info`, `debug`, or `log`. |
|
|
400
417
|
|
|
418
|
+
The default path parses modern syntax directly and normalizes the constructs
|
|
419
|
+
that older obfuscation passes cannot consume yet. The native AST path supports
|
|
420
|
+
plain classes as native islands, class fields, private fields, arrows, for-of
|
|
421
|
+
loops, async/generator functions, optional chaining, nullish coalescing, object
|
|
422
|
+
rest/spread, and spread calls.
|
|
423
|
+
|
|
424
|
+
When `babel: true` and `babelPreserveAsync` is enabled, optional Babel packages
|
|
425
|
+
installed by the caller can still downlevel syntax for legacy browser targets
|
|
426
|
+
while leaving async and generator functions for ToilDefender's async/generator
|
|
427
|
+
dispatchers. This avoids the large regenerator helper path for modern browser
|
|
428
|
+
and Node bundles.
|
|
429
|
+
|
|
401
430
|
## Toil Integration
|
|
402
431
|
|
|
403
432
|
ToilDefender is intended to sit behind Toil build tooling. Framework packages
|