js-confuser-vm 0.0.8 → 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 ADDED
@@ -0,0 +1,4 @@
1
+ [submodule "test262"]
2
+ path = test262
3
+ url = https://github.com/tc39/test262
4
+ branch = es5-tests
package/CHANGELOG.md CHANGED
@@ -1,4 +1,104 @@
1
- ## `0.0.7` Micro Opcodes
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) looks like:
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) looks like:
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();