手搓 jsvmp
代码
一个支持自定义虚拟机指令集和解释器的简易版 jsvmp
const instructions = [
{ op: "LOAD", arg: Math.random },
{ op: "LOAD", arg: Math },
{ op: "LOAD", arg: 0 },
{ op: "CALL" },
{ op: "RETURN" },
];
class BytecodeGenerator {
constructor() {
this.bytecode = [];
this.constantMap = {};
this.opcodeMap = {};
}
generate(instructions) {
for (const instr of instructions) {
const op = instr.op;
if (!(op in this.opcodeMap)) {
this.opcodeMap[op] = Object.keys(this.opcodeMap).length + 1;
}
this.bytecode.push(this.opcodeMap[instr.op]);
if (typeof instr.arg === "number") {
this.bytecode.push(-1);
this.bytecode.push(instr.arg);
} else if (instr.arg !== undefined) {
const k = typeof instr.arg + ":" + instr.arg;
if (!(k in this.constantMap)) {
this.constantMap[k] = {
value: instr.arg,
index: Object.keys(this.constantMap).length,
};
}
this.bytecode.push(this.constantMap[k].index);
}
}
return [
this.bytecode,
Object.entries(this.constantMap)
.sort((a, b) => a[1].index - b[1].index)
.map(([k, v]) => v.value),
this.opcodeMap,
];
}
}
const [bytecode, constants, opcodeMap] = new BytecodeGenerator().generate(
instructions,
);
console.log(bytecode);
console.log(constants);
console.log(opcodeMap);
class VM {
constructor(bytecode, constants, opcodeMap) {
this.bytecode = bytecode;
this.constants = constants;
this.opcodeMap = opcodeMap;
}
run(...args) {
this.stack = [];
this.pc = 0;
while (this.pc < this.bytecode.length) {
const opcode = this.bytecode[this.pc++];
switch (opcode) {
case this.opcodeMap["LOAD"]:
const i = this.bytecode[this.pc++];
if (i >= 0) {
this.stack.push(this.constants[i]);
} else {
this.stack.push(this.bytecode[this.pc++]);
}
break;
case this.opcodeMap["CALL"]:
const s = this.stack.pop();
const args = [];
for (let i = 0; i < s; i++) {
args.unshift(this.stack.pop());
}
const obj = this.stack.pop();
const func = this.stack.pop();
this.stack.push(Function.prototype.call.call(func, obj, ...args));
break;
case this.opcodeMap["RETURN"]:
return this.stack.pop();
}
}
}
}
const result = new VM(bytecode, constants, opcodeMap).run();
console.log(result);
输出结果
[
1, 0, 1, 1, 1,
-1, 0, 2, 3
]
[ [Function: random], Object [Math] {} ]
{ LOAD: 1, CALL: 2, RETURN: 3 }
0.7665310789085834
增强方案
- 符号混淆
- 字符串加密
- bytecode 加密
- 字节码自修改
- GOTO 乱序执行
- vm in vm
逆向分析方法
- 线性反汇编
- 控制流反汇编
- 插桩打印日志 (trace)
附:
babel ast spec: https://github.com/babel/babel/blob/main/packages/babel-parser/ast/spec.md
ast explorer: https://astexplorer.net/

浙公网安备 33010602011771号