js-confuser-vm 0.0.9 → 0.1.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.
- package/.gitmodules +4 -0
- package/CHANGELOG.md +102 -2
- package/README.md +95 -1
- package/dist/compiler.js +225 -152
- package/dist/runtime.js +200 -143
- package/dist/template.js +142 -0
- package/dist/transforms/bytecode/dispatcher.js +362 -0
- package/dist/transforms/bytecode/macroOpcodes.js +1 -1
- package/dist/transforms/bytecode/resolveLabels.js +21 -18
- package/dist/transforms/bytecode/resolveRegisters.js +212 -0
- package/dist/transforms/bytecode/specializedOpcodes.js +4 -2
- package/dist/types.js +41 -0
- package/dist/utils/op-utils.js +1 -0
- package/index.ts +1 -0
- package/jest.config.js +5 -0
- package/package.json +1 -1
- package/src/compiler.ts +291 -180
- package/src/options.ts +1 -0
- package/src/runtime.ts +222 -141
- package/src/template.ts +141 -0
- package/src/transforms/bytecode/aliasedOpcodes.ts +1 -1
- package/src/transforms/bytecode/dispatcher.ts +398 -0
- package/src/transforms/bytecode/macroOpcodes.ts +2 -2
- package/src/transforms/bytecode/resolveLabels.ts +31 -27
- package/src/transforms/bytecode/resolveRegisters.ts +221 -0
- package/src/transforms/bytecode/specializedOpcodes.ts +5 -9
- package/src/types.ts +64 -4
- package/src/utils/op-utils.ts +2 -0
- package/dist/transforms/utils/op-utils.js +0 -25
- package/dist/transforms/utils/random-utils.js +0 -27
- package/dist/utilts.js +0 -3
package/.gitmodules
ADDED
package/CHANGELOG.md
CHANGED
|
@@ -1,4 +1,104 @@
|
|
|
1
|
-
## `0.0
|
|
1
|
+
## `0.1.0` Dispatcher, Virtual Registers, and more
|
|
2
|
+
|
|
3
|
+
- Added new option `dispatcher` which creates a middleman block to process jumps.
|
|
4
|
+
|
|
5
|
+
```js
|
|
6
|
+
// Input Code
|
|
7
|
+
if (true) {
|
|
8
|
+
console.log("Hello world!");
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
// Before
|
|
12
|
+
// fn_0_0:
|
|
13
|
+
// [0, 0, 0, 0], LOAD_CONST reg[0] = true 1:4-1:8
|
|
14
|
+
// [40, 0, 29], JUMP_IF_FALSE [0, if_else_1] 1:0-3:1
|
|
15
|
+
// [2, 0, 1, 0], LOAD_GLOBAL reg[0] = console 2:2-2:9
|
|
16
|
+
// [0, 1, 2, 0], LOAD_CONST reg[1] = "log" 2:2-2:29
|
|
17
|
+
// [8, 2, 0, 1], GET_PROP reg[2] = reg[0][reg[1]] 2:2-2:29
|
|
18
|
+
// [0, 1, 3, 0], LOAD_CONST reg[1] = "Hello world!" 2:14-2:28
|
|
19
|
+
// [43, 3, 0, 2, 1, 1], CALL_METHOD reg[3] = reg[2](recv=reg[0], 1 args) 2:2-2:29
|
|
20
|
+
// if_else_1:
|
|
21
|
+
// [0, 0, 4, 0], LOAD_CONST reg[0] = undefined
|
|
22
|
+
// [45, 0], RETURN reg[0]
|
|
23
|
+
|
|
24
|
+
// What this looks like decompiled:
|
|
25
|
+
// fn_0_0:
|
|
26
|
+
r0 = true
|
|
27
|
+
if (!r0) goto if_else_1
|
|
28
|
+
r0 = console
|
|
29
|
+
r1 = "log"
|
|
30
|
+
r2 = r0[r1] // console.log
|
|
31
|
+
r1 = "Hello world!"
|
|
32
|
+
r3 = r2.call(r0, r1) // console.log("Hello world!")
|
|
33
|
+
// if_else_1:
|
|
34
|
+
r0 = undefined
|
|
35
|
+
return r0
|
|
36
|
+
|
|
37
|
+
// After
|
|
38
|
+
// fn_0_0:
|
|
39
|
+
// [47, 2, 57, 2, 5, 0], MAKE_CLOSURE reg[2] PC=fn_2_3 (params=2 regs=5 upvalues=0)
|
|
40
|
+
// [0, 3, 0, 0], LOAD_CONST reg[3] = true 1:4-1:8
|
|
41
|
+
// [41, 3, 21], JUMP_IF_TRUE [3, if_else_1_skip_5]
|
|
42
|
+
// [1, 0, 43020], LOAD_INT reg[0] = if_else_1
|
|
43
|
+
// [1, 1, 40151], LOAD_INT reg[1] = 40151
|
|
44
|
+
// [39, 49], JUMP dispatcher_4
|
|
45
|
+
// if_else_1_skip_5:
|
|
46
|
+
// [2, 3, 1, 0], LOAD_GLOBAL reg[3] = console 2:2-2:9
|
|
47
|
+
// [0, 4, 2, 0], LOAD_CONST reg[4] = "log" 2:2-2:29
|
|
48
|
+
// [8, 5, 3, 4], GET_PROP reg[5] = reg[3][reg[4]] 2:2-2:29
|
|
49
|
+
// [0, 4, 3, 0], LOAD_CONST reg[4] = "Hello world!" 2:14-2:28
|
|
50
|
+
// [43, 6, 3, 5, 1, 4], CALL_METHOD reg[6] = reg[5](recv=reg[3], 1 args) 2:2-2:29
|
|
51
|
+
// if_else_1:
|
|
52
|
+
// [0, 3, 4, 0], LOAD_CONST reg[3] = undefined
|
|
53
|
+
// [45, 3], RETURN reg[3]
|
|
54
|
+
// dispatcher_4:
|
|
55
|
+
// [42, 0, 2, 2, 0, 1], CALL reg[0] = reg[2](reg[0], reg[1])
|
|
56
|
+
// [58, 0], JUMP_REG PC = reg[0]
|
|
57
|
+
// fn_2_3:
|
|
58
|
+
// [18, 2, 0, 1], BXOR [2, 0, 1]
|
|
59
|
+
// [0, 3, 5, 0], LOAD_CONST reg[3] = 52048
|
|
60
|
+
// [11, 4, 2, 3], ADD [4, 2, 3]
|
|
61
|
+
// [0, 2, 6, 0], LOAD_CONST reg[2] = 65535
|
|
62
|
+
// [16, 3, 4, 2], BAND [3, 4, 2]
|
|
63
|
+
// [45, 3], RETURN reg[3]
|
|
64
|
+
|
|
65
|
+
// What this looks like decompiled:
|
|
66
|
+
// fn_0_0:
|
|
67
|
+
r2 = MakeClosure(fn_2_3, params=2)
|
|
68
|
+
r3 = true
|
|
69
|
+
if (r3) goto if_else_1_skip
|
|
70
|
+
r0 = 43020
|
|
71
|
+
r1 = 40151
|
|
72
|
+
goto dispatcher
|
|
73
|
+
// if_else_1_skip:
|
|
74
|
+
r3 = console
|
|
75
|
+
r4 = "log"
|
|
76
|
+
r5 = r3[r4] // console.log
|
|
77
|
+
r4 = "Hello world!"
|
|
78
|
+
r6 = r5.call(r3, r4) // console.log("Hello world!")
|
|
79
|
+
// if_else_1:
|
|
80
|
+
r3 = undefined
|
|
81
|
+
return r3
|
|
82
|
+
|
|
83
|
+
// dispatcher:
|
|
84
|
+
r0 = r2(r0, r1) // decode(encodedPC, siteKey)
|
|
85
|
+
goto *r0 // indirect jump
|
|
86
|
+
|
|
87
|
+
// fn_2_3:
|
|
88
|
+
function decode(x, k) {
|
|
89
|
+
return ((x ^ k) + 52048) & 65535;
|
|
90
|
+
}
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
- Improved registers:
|
|
94
|
+
- - Now flattened into a single array with base/stack pointer mechanics
|
|
95
|
+
- - Improved compiler to support virtual registers, allowing passes to introduce scope-specific registers, with a final pass responsible for allocation and freeing
|
|
96
|
+
|
|
97
|
+
- Added a template system to insert synthetic JavaScript as native bytecode, similar to [JS-Confuser's template system](https://github.com/MichaelXF/js-confuser/blob/b6ef304f77b7fc27cb9cc8d7d841e50a4200d7bc/docs/Template.md)
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
## `0.0.9` Micro Opcodes
|
|
2
102
|
|
|
3
103
|
- Added new option `microOpcodes` which breaks opcodes into multiple sub-opcodes.
|
|
4
104
|
|
|
@@ -34,7 +134,7 @@ case OP.LOAD_CONST:
|
|
|
34
134
|
// [59, 2, 0], MICRO_LOAD_CONST_1 [2, 0]
|
|
35
135
|
// [43, 5, 1, 3, 1, 4], CALL_METHOD reg[5] = reg[3](recv=reg[1], 1 args) 1:0-1:27
|
|
36
136
|
|
|
37
|
-
// What the opcodes "MICRO_LOAD_CONST_0" (58) and "MICRO_LOAD_CONST_1" (59)
|
|
137
|
+
// What the opcodes "MICRO_LOAD_CONST_0" (58) and "MICRO_LOAD_CONST_1" (59) look like:
|
|
38
138
|
case 58:
|
|
39
139
|
// MICRO_LOAD_CONST_0
|
|
40
140
|
this._internals[0] = this._operand();
|
package/README.md
CHANGED
|
@@ -39,6 +39,7 @@ JsConfuserVM.obfuscate(`
|
|
|
39
39
|
shuffleOpcodes: true, // shuffle order of opcode handlers in the runtime?
|
|
40
40
|
encodeBytecode: true, // encode the bytecode array?
|
|
41
41
|
concealConstants: true, // conceal strings and integers in the constant pool?
|
|
42
|
+
dispatcher: true, // create middleman blocks to process jumps?
|
|
42
43
|
selfModifying: true, // do self-modifying bytecode for function bodies?
|
|
43
44
|
macroOpcodes: true, // create combined opcodes for repeated instruction sequences?
|
|
44
45
|
microOpcodes: true, // break opcodes into sub-opcodes?
|
|
@@ -138,6 +139,7 @@ A(new p(function(a){a=typeof Buffer!=="undefined"?Buffer.from(a,"base64"):Uint8A
|
|
|
138
139
|
- [x] self-modifying bytecode
|
|
139
140
|
- [x] timing checks
|
|
140
141
|
- [ ] low-level bytecode obfuscations
|
|
142
|
+
- [x] dispatcher (Encoded jumps)
|
|
141
143
|
- [ ] stack protection
|
|
142
144
|
- [ ] control flow integrity
|
|
143
145
|
|
|
@@ -179,6 +181,98 @@ var CONSTANTS = [/* 0 */"console", /* 1 */"log", /* 2 */"Hello world!", /* 3 */u
|
|
|
179
181
|
var CONSTANTS = [/* 0 */"DaQApB6kAqQdpB+kEaQ=", /* 1 */"TCFOIUUh", /* 2 */"kKK8orait6Kzov2iqaKwopKijaKGosKi", /* 3 */undefined];
|
|
180
182
|
```
|
|
181
183
|
|
|
184
|
+
#### `dispatcher` (true/false)
|
|
185
|
+
|
|
186
|
+
- Creates a middleman block to process jumps.
|
|
187
|
+
|
|
188
|
+
```js
|
|
189
|
+
// Input Code
|
|
190
|
+
if (true) {
|
|
191
|
+
console.log("Hello world!");
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// Before
|
|
195
|
+
// fn_0_0:
|
|
196
|
+
// [0, 0, 0, 0], LOAD_CONST reg[0] = true 1:4-1:8
|
|
197
|
+
// [40, 0, 29], JUMP_IF_FALSE [0, if_else_1] 1:0-3:1
|
|
198
|
+
// [2, 0, 1, 0], LOAD_GLOBAL reg[0] = console 2:2-2:9
|
|
199
|
+
// [0, 1, 2, 0], LOAD_CONST reg[1] = "log" 2:2-2:29
|
|
200
|
+
// [8, 2, 0, 1], GET_PROP reg[2] = reg[0][reg[1]] 2:2-2:29
|
|
201
|
+
// [0, 1, 3, 0], LOAD_CONST reg[1] = "Hello world!" 2:14-2:28
|
|
202
|
+
// [43, 3, 0, 2, 1, 1], CALL_METHOD reg[3] = reg[2](recv=reg[0], 1 args) 2:2-2:29
|
|
203
|
+
// if_else_1:
|
|
204
|
+
// [0, 0, 4, 0], LOAD_CONST reg[0] = undefined
|
|
205
|
+
// [45, 0], RETURN reg[0]
|
|
206
|
+
|
|
207
|
+
// What this looks like decompiled:
|
|
208
|
+
// fn_0_0:
|
|
209
|
+
r0 = true
|
|
210
|
+
if (!r0) goto if_else_1
|
|
211
|
+
r0 = console
|
|
212
|
+
r1 = "log"
|
|
213
|
+
r2 = r0[r1] // console.log
|
|
214
|
+
r1 = "Hello world!"
|
|
215
|
+
r3 = r2.call(r0, r1) // console.log("Hello world!")
|
|
216
|
+
// if_else_1:
|
|
217
|
+
r0 = undefined
|
|
218
|
+
return r0
|
|
219
|
+
|
|
220
|
+
// After
|
|
221
|
+
// fn_0_0:
|
|
222
|
+
// [47, 2, 57, 2, 5, 0], MAKE_CLOSURE reg[2] PC=fn_2_3 (params=2 regs=5 upvalues=0)
|
|
223
|
+
// [0, 3, 0, 0], LOAD_CONST reg[3] = true 1:4-1:8
|
|
224
|
+
// [41, 3, 21], JUMP_IF_TRUE [3, if_else_1_skip_5]
|
|
225
|
+
// [1, 0, 43020], LOAD_INT reg[0] = if_else_1
|
|
226
|
+
// [1, 1, 40151], LOAD_INT reg[1] = 40151
|
|
227
|
+
// [39, 49], JUMP dispatcher_4
|
|
228
|
+
// if_else_1_skip_5:
|
|
229
|
+
// [2, 3, 1, 0], LOAD_GLOBAL reg[3] = console 2:2-2:9
|
|
230
|
+
// [0, 4, 2, 0], LOAD_CONST reg[4] = "log" 2:2-2:29
|
|
231
|
+
// [8, 5, 3, 4], GET_PROP reg[5] = reg[3][reg[4]] 2:2-2:29
|
|
232
|
+
// [0, 4, 3, 0], LOAD_CONST reg[4] = "Hello world!" 2:14-2:28
|
|
233
|
+
// [43, 6, 3, 5, 1, 4], CALL_METHOD reg[6] = reg[5](recv=reg[3], 1 args) 2:2-2:29
|
|
234
|
+
// if_else_1:
|
|
235
|
+
// [0, 3, 4, 0], LOAD_CONST reg[3] = undefined
|
|
236
|
+
// [45, 3], RETURN reg[3]
|
|
237
|
+
// dispatcher_4:
|
|
238
|
+
// [42, 0, 2, 2, 0, 1], CALL reg[0] = reg[2](reg[0], reg[1])
|
|
239
|
+
// [58, 0], JUMP_REG PC = reg[0]
|
|
240
|
+
// fn_2_3:
|
|
241
|
+
// [18, 2, 0, 1], BXOR [2, 0, 1]
|
|
242
|
+
// [0, 3, 5, 0], LOAD_CONST reg[3] = 52048
|
|
243
|
+
// [11, 4, 2, 3], ADD [4, 2, 3]
|
|
244
|
+
// [0, 2, 6, 0], LOAD_CONST reg[2] = 65535
|
|
245
|
+
// [16, 3, 4, 2], BAND [3, 4, 2]
|
|
246
|
+
// [45, 3], RETURN reg[3]
|
|
247
|
+
|
|
248
|
+
// What this looks like decompiled:
|
|
249
|
+
// fn_0_0:
|
|
250
|
+
r2 = MakeClosure(fn_2_3, params=2)
|
|
251
|
+
r3 = true
|
|
252
|
+
if (r3) goto if_else_1_skip
|
|
253
|
+
r0 = 43020
|
|
254
|
+
r1 = 40151
|
|
255
|
+
goto dispatcher
|
|
256
|
+
// if_else_1_skip:
|
|
257
|
+
r3 = console
|
|
258
|
+
r4 = "log"
|
|
259
|
+
r5 = r3[r4] // console.log
|
|
260
|
+
r4 = "Hello world!"
|
|
261
|
+
r6 = r5.call(r3, r4) // console.log("Hello world!")
|
|
262
|
+
// if_else_1:
|
|
263
|
+
r3 = undefined
|
|
264
|
+
return r3
|
|
265
|
+
|
|
266
|
+
// dispatcher:
|
|
267
|
+
r0 = r2(r0, r1) // decode(encodedPC, siteKey)
|
|
268
|
+
goto *r0 // indirect jump
|
|
269
|
+
|
|
270
|
+
// fn_2_3:
|
|
271
|
+
function decode(x, k) {
|
|
272
|
+
return ((x ^ k) + 52048) & 65535;
|
|
273
|
+
}
|
|
274
|
+
```
|
|
275
|
+
|
|
182
276
|
#### `macroOpcodes` (true/false)
|
|
183
277
|
|
|
184
278
|
Combines multiple opcodes commonly used from your bytecode.
|
|
@@ -282,7 +376,7 @@ case OP.LOAD_CONST:
|
|
|
282
376
|
// [59, 2, 0], MICRO_LOAD_CONST_1 [2, 0]
|
|
283
377
|
// [43, 5, 1, 3, 1, 4], CALL_METHOD reg[5] = reg[3](recv=reg[1], 1 args) 1:0-1:27
|
|
284
378
|
|
|
285
|
-
// What the opcodes "MICRO_LOAD_CONST_0" (58) and "MICRO_LOAD_CONST_1" (59)
|
|
379
|
+
// What the opcodes "MICRO_LOAD_CONST_0" (58) and "MICRO_LOAD_CONST_1" (59) look like:
|
|
286
380
|
case 58:
|
|
287
381
|
// MICRO_LOAD_CONST_0
|
|
288
382
|
this._internals[0] = this._operand();
|