js-confuser-vm 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/README.md +281 -147
- package/dist/build-runtime.js +41 -15
- package/dist/compiler.js +714 -265
- package/dist/disassembler.js +367 -0
- package/dist/index.js +7 -2
- package/dist/runtime.js +160 -119
- package/dist/template.js +163 -42
- package/dist/transforms/bytecode/aliasedOpcodes.js +4 -1
- package/dist/transforms/bytecode/concealConstants.js +2 -2
- package/dist/transforms/bytecode/controlFlowFlattening.js +569 -0
- package/dist/transforms/bytecode/dispatcher.js +15 -111
- package/dist/transforms/bytecode/macroOpcodes.js +2 -2
- package/{src/transforms/bytecode/resolveContants.ts → dist/transforms/bytecode/resolveConstants.js} +30 -56
- package/dist/transforms/bytecode/resolveRegisters.js +23 -4
- package/dist/transforms/bytecode/selfModifying.js +88 -21
- package/dist/transforms/bytecode/semanticOpcodes.js +162 -0
- package/dist/transforms/bytecode/specializedOpcodes.js +23 -12
- package/dist/transforms/bytecode/stringConcealing.js +288 -0
- package/dist/transforms/runtime/classObfuscation.js +43 -0
- package/dist/transforms/runtime/handlerTable.js +91 -0
- package/dist/transforms/runtime/semanticOpcodes.js +35 -0
- package/dist/transforms/runtime/specializedOpcodes.js +11 -5
- package/dist/types.js +1 -1
- package/dist/utils/ast-utils.js +75 -0
- package/dist/utils/op-utils.js +1 -2
- package/dist/utils/pass-utils.js +100 -0
- package/dist/utils/profile-utils.js +3 -0
- package/package.json +8 -1
- package/.gitmodules +0 -4
- package/.prettierignore +0 -1
- package/CHANGELOG.md +0 -335
- package/babel-plugin-inline-runtime.cjs +0 -34
- package/babel.config.json +0 -23
- package/index.ts +0 -38
- package/jest-strip-types.js +0 -10
- package/jest.config.js +0 -52
- package/src/build-runtime.ts +0 -78
- package/src/compiler.ts +0 -2593
- package/src/index.ts +0 -14
- package/src/minify.ts +0 -21
- package/src/options.ts +0 -18
- package/src/runtime.ts +0 -923
- package/src/template.ts +0 -141
- package/src/transforms/bytecode/aliasedOpcodes.ts +0 -148
- package/src/transforms/bytecode/concealConstants.ts +0 -52
- package/src/transforms/bytecode/dispatcher.ts +0 -398
- package/src/transforms/bytecode/macroOpcodes.ts +0 -193
- package/src/transforms/bytecode/microOpcodes.ts +0 -291
- package/src/transforms/bytecode/resolveLabels.ts +0 -112
- package/src/transforms/bytecode/resolveRegisters.ts +0 -221
- package/src/transforms/bytecode/selfModifying.ts +0 -121
- package/src/transforms/bytecode/specializedOpcodes.ts +0 -153
- package/src/transforms/runtime/aliasedOpcodes.ts +0 -191
- package/src/transforms/runtime/internalVariables.ts +0 -270
- package/src/transforms/runtime/macroOpcodes.ts +0 -138
- package/src/transforms/runtime/microOpcodes.ts +0 -93
- package/src/transforms/runtime/minify.ts +0 -1
- package/src/transforms/runtime/shuffleOpcodes.ts +0 -24
- package/src/transforms/runtime/specializedOpcodes.ts +0 -156
- package/src/types.ts +0 -93
- package/src/utils/op-utils.ts +0 -48
- package/src/utils/random-utils.ts +0 -31
- package/tsconfig.json +0 -12
package/src/types.ts
DELETED
|
@@ -1,93 +0,0 @@
|
|
|
1
|
-
// Bytecode supports both real instructions and IR pseudo-instructions
|
|
2
|
-
// Real instruction: [OP.ADD, 5] or multi-operand: [OP.MAKE_CLOSURE, labelRef, 2, 3, 0]
|
|
3
|
-
// IR instruction: [null, { type: "defineLabel", label: "FN_ENTRY_1" }]
|
|
4
|
-
|
|
5
|
-
// IR instructions are used to hold symbolic information during compilation
|
|
6
|
-
// All "null" instructions are dropped before assembly time.
|
|
7
|
-
// Instructions may carry any number of operands; the flat output serializes
|
|
8
|
-
// each operand as a separate u16 slot in the bytecode array.
|
|
9
|
-
// A virtual register reference emitted by the compiler.
|
|
10
|
-
// fnId identifies which function's register file this belongs to.
|
|
11
|
-
// resolveRegisters() replaces these with concrete slot indices (type:"number").
|
|
12
|
-
export type RegisterOperand = Op<{
|
|
13
|
-
type: "register";
|
|
14
|
-
id: number;
|
|
15
|
-
fnId: number;
|
|
16
|
-
kind?: string;
|
|
17
|
-
scopeId?: string | number;
|
|
18
|
-
}>;
|
|
19
|
-
|
|
20
|
-
// A placeholder for a function's concrete regCount, emitted in MAKE_CLOSURE.
|
|
21
|
-
// resolveRegisters() fills resolvedValue once it knows the concrete slot count.
|
|
22
|
-
export type FnRegCountOperand = Op<{ type: "fnRegCount"; fnId: number }>;
|
|
23
|
-
|
|
24
|
-
// IR pseudo-instruction that marks the end of a register's live range.
|
|
25
|
-
// Emitted as [null, FreeRegOperand] so it is dropped before final assembly.
|
|
26
|
-
//
|
|
27
|
-
// NOTE: resolveRegisters() already computes correct lastUse from the last real
|
|
28
|
-
// operand appearance, so freeReg is EXTRANEOUS for any programmatically generated
|
|
29
|
-
// IR — the scanner will find the tightest possible range without it.
|
|
30
|
-
// It is only useful when a register has a late syntactic appearance that does
|
|
31
|
-
// NOT reflect its true logical end-of-life (e.g. a read emitted purely for
|
|
32
|
-
// side-effects long after the value is logically dead). No current pass in this
|
|
33
|
-
// codebase emits freeReg; it is kept as an extension point only.
|
|
34
|
-
export type FreeRegOperand = Op<{
|
|
35
|
-
type: "freeReg";
|
|
36
|
-
fnId: number;
|
|
37
|
-
id: number;
|
|
38
|
-
kind?: string;
|
|
39
|
-
scopeId?: string | number;
|
|
40
|
-
}>;
|
|
41
|
-
|
|
42
|
-
export type InstrOperand =
|
|
43
|
-
| number
|
|
44
|
-
| Op<{ type: "number"; value?: number }>
|
|
45
|
-
| Op<{
|
|
46
|
-
type: "label";
|
|
47
|
-
label: string;
|
|
48
|
-
offset?: number;
|
|
49
|
-
transform?: (resolvedPC: number) => number;
|
|
50
|
-
}>
|
|
51
|
-
| Op<{ type: "defineLabel"; label: string }>
|
|
52
|
-
| Op<{ type: "constant"; value: any }>
|
|
53
|
-
| RegisterOperand
|
|
54
|
-
| FnRegCountOperand
|
|
55
|
-
| FreeRegOperand;
|
|
56
|
-
|
|
57
|
-
export interface Operand {
|
|
58
|
-
type: string;
|
|
59
|
-
placeholder?: boolean; // This operand will not be emitted in the final bytecode, but used as a reference
|
|
60
|
-
resolvedValue?: number; // This operand knows its resolved value, but kept as a object to keep metadata info available
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
type Op<T extends object> = Operand & T;
|
|
64
|
-
|
|
65
|
-
export type Instruction = [number | null, ...InstrOperand[]];
|
|
66
|
-
|
|
67
|
-
export type Bytecode = Instruction[];
|
|
68
|
-
|
|
69
|
-
export function constantOperand(value: any): Instruction[1] {
|
|
70
|
-
return {
|
|
71
|
-
type: "constant",
|
|
72
|
-
value: value,
|
|
73
|
-
};
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
export function registerOperand(
|
|
77
|
-
id: number,
|
|
78
|
-
fnId: number,
|
|
79
|
-
metadata: Partial<Pick<RegisterOperand, "kind" | "scopeId">> = {},
|
|
80
|
-
): RegisterOperand {
|
|
81
|
-
return { type: "register", id, fnId, ...metadata };
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
export function fnRegCountOperand(fnId: number): FnRegCountOperand {
|
|
85
|
-
return { type: "fnRegCount", fnId };
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
export function freeRegOperand(reg: RegisterOperand): FreeRegOperand {
|
|
89
|
-
const op: FreeRegOperand = { type: "freeReg", fnId: reg.fnId, id: reg.id };
|
|
90
|
-
if (reg.kind !== undefined) op.kind = reg.kind;
|
|
91
|
-
if (reg.scopeId !== undefined) op.scopeId = reg.scopeId;
|
|
92
|
-
return op;
|
|
93
|
-
}
|
package/src/utils/op-utils.ts
DELETED
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
import { getRandomInt } from "./random-utils.ts";
|
|
2
|
-
import * as b from "../types.ts";
|
|
3
|
-
import { Compiler } from "../compiler.ts";
|
|
4
|
-
|
|
5
|
-
export const U16_MAX = 0xffff; // bytecode operands are u16
|
|
6
|
-
|
|
7
|
-
/** Returns the next free opcode slot, or -1 when the space is exhausted. */
|
|
8
|
-
export function nextFreeSlot(compiler: Compiler): number {
|
|
9
|
-
// ── Collect used opcodes exactly as specified ─────────────────────────────
|
|
10
|
-
const usedOpcodes = new Set<number>(
|
|
11
|
-
Object.keys(compiler.OP_NAME)
|
|
12
|
-
.map((k) => parseInt(k, 10))
|
|
13
|
-
.filter((v) => !isNaN(v)) as number[],
|
|
14
|
-
);
|
|
15
|
-
|
|
16
|
-
if (usedOpcodes.size > U16_MAX) return -1;
|
|
17
|
-
|
|
18
|
-
// Random opcode
|
|
19
|
-
if (compiler.options.randomizeOpcodes) {
|
|
20
|
-
let attempts = 0;
|
|
21
|
-
while (attempts++ < 512) {
|
|
22
|
-
const candidate = getRandomInt(0, U16_MAX);
|
|
23
|
-
if (!usedOpcodes.has(candidate)) {
|
|
24
|
-
usedOpcodes.add(candidate);
|
|
25
|
-
return candidate;
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
// Fallback: linear scan from a random start
|
|
31
|
-
const start = Object.keys(compiler.OP_NAME).length;
|
|
32
|
-
for (let i = 0; i <= U16_MAX; i++) {
|
|
33
|
-
const v = (start + i) & U16_MAX;
|
|
34
|
-
if (!usedOpcodes.has(v)) {
|
|
35
|
-
usedOpcodes.add(v);
|
|
36
|
-
return v;
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
return -1;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
export function getInstructionSize(instr: b.Instruction): number {
|
|
43
|
-
if (instr[0] === null) return 0;
|
|
44
|
-
|
|
45
|
-
const size = instr.filter((op) => (op as any)?.placeholder !== true).length;
|
|
46
|
-
|
|
47
|
-
return size;
|
|
48
|
-
}
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import { ok } from "assert";
|
|
2
|
-
|
|
3
|
-
export function getPlaceholder() {
|
|
4
|
-
return Math.random().toString(36).substring(2, 15);
|
|
5
|
-
}
|
|
6
|
-
|
|
7
|
-
export function choice<T>(elements: T[]): T {
|
|
8
|
-
ok(elements.length > 0, "choice() called on empty sequence");
|
|
9
|
-
return elements[Math.floor(Math.random() * elements.length)];
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export function getRandom(): number {
|
|
13
|
-
return Math.random();
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
export function getRandomInt(min: number, max: number): number {
|
|
17
|
-
ok(min <= max, "min must be <= max");
|
|
18
|
-
return Math.floor(Math.random() * (max - min + 1)) + min;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* Shuffles an array in-place using the Fisher-Yates algorithm.
|
|
23
|
-
* @param array - The array to shuffle (mutated)
|
|
24
|
-
*/
|
|
25
|
-
export function shuffle<T>(array: T[]): T[] {
|
|
26
|
-
for (let i = array.length - 1; i > 0; i--) {
|
|
27
|
-
const j = Math.floor(Math.random() * (i + 1));
|
|
28
|
-
[array[i], array[j]] = [array[j], array[i]];
|
|
29
|
-
}
|
|
30
|
-
return array;
|
|
31
|
-
}
|