15158846557 在线咨询 在线咨询
15158846557 在线咨询
所在位置: 首页 > 营销资讯 > 网站运营 > 用虚拟机opcode保护JS源码

用虚拟机opcode保护JS源码

时间:2023-07-12 15:24:01 | 来源:网站运营

时间:2023-07-12 15:24:01 来源:网站运营

用虚拟机opcode保护JS源码:JS代码保护,有多种方式,如常规的JS混淆加密、如bytecode化、又或如虚拟机化。

这里简单探讨虚拟机JS保护。

一、原理

虚拟机保护的最终目标,是将JS代码转为opcode,或汇编语言式代码,在虚拟机中执行。

一般是保护重要的函数、算法、当然也可以保护更多更大段的代码。

更详细一些来说,汇编语言式代码,形态会类似:

push apush bpush ccall funpop这是古老的asm语法,没错,js代码可以转为此种形式,而且,可以更进一步,转为opcode,如上述asm代码,如果将push、pop等字符替换为数字的操作码,假设push为20,call为30,pop为40,形态可以变成:

20,1,20,20,3,30,4,40如果我们的JS代码,变成了这样的数字,谁能理解它的代码逻辑和作用吗?

很显然,这样起到了对代码加密保护的作用。如果再与JShaman之类的混淆加密工具配合使用,JS代码的安全性将得到极大的提升。

二、开发一个JS虚拟机

一个简单的堆栈虚拟机,并不会十分复杂,用JS数组模拟堆栈,用数组的push方法模拟压栈,用数组索实现堆栈指针、指令指针、栈帧。

本例中,汇编指令,则实现一部分操作,如:

const I = { CONST: 1, ADD: 2, PRINT: 3, HALT: 4, CALL: 5, RETURN: 6, LOAD: 7, JUMP_IF_ZERO: 8, JUMP_IF_NOT_ZERO: 9, SUB: 10, MUL: 11,};虚拟机的核心的部分,则是根据指令进行相应的堆栈操作,如:

//循环执行 switch (instruction) { //常量 case I.CONST: { //常量值 const op_value = code[ip++]; //存放到堆栈 stack[++sp] = op_value; console.log("const",stack) break; } case I.ADD: { const op1 = stack[sp--]; const op2 = stack[sp--]; stack[++sp] = op1 + op2; break; } //减法 case I.SUB: { //减数 const op1 = stack[sp--]; //被减数,都放在堆栈里 const op2 = stack[sp--]; //相减的结果,放到堆栈 stack[++sp] = op2 - op1; break; } case I.PRINT: { const value = stack[sp--]; builtins.print(value); break; } case I.HALT: { return; } //函数调用 case I.CALL: { //函数地址 const op1_address = code[ip++]; //参数个数 const op2_numberOfArguments = code[ip++]; console.log(".....",op1_address,op2_numberOfArguments) //参数个数入栈 stack[++sp] = op2_numberOfArguments; //旧栈帧入栈 stack[++sp] = fp; //指令指针 stack[++sp] = ip; //console.log("call",stack);return //独立的栈帧,从当前堆栈指针处开始 fp = sp; //指令指针变化,开始执行call函数 ip = op1_address; break; } case I.RETURN: { const returnValue = stack[sp--]; sp = fp; ip = stack[sp--]; fp = stack[sp--]; const number_of_arguments = stack[sp--]; sp -= number_of_arguments; stack[++sp] = returnValue; break; } case I.LOAD: { //补偿地址,ip指向指令地址,通过补偿值,获得函数调用前压入的参数 const op_offset = code[ip++]; const value = stack[fp + op_offset]; //console.log(value);return stack[++sp] = value; break; } case I.JUMP_IF_NOT_ZERO: { const op_address = code[ip++]; const value = stack[sp--]; if (value !== 0) { ip = op_address; } break; } default: throw new Error(`Unknown instruction: ${instruction}.`); }三、实例

JS虚拟机已简单实现。然后,准备一段JS代码生成的opcode,如下:

1, 10, 5, 7, 1, 3, 4, 7, -3,1, 1, 10, 9, 17, 1, 1, 6, 7, -3, 7, -3, 1, 1, 10, 5, 7, 1, 11, 6看起来仅仅是些数字,先看效果,在虚拟机中执行:







如上图,输出是一个数值。那么,这段opcode究竟是什么呢?

其实,它是这样一段JS源代码转化而来:

function factorial(n) { if (n === 1) { return 1; } return n * factorial(n - 1);}const result = factorial(10);console.log(result);将上述opcode转换一个形式,把数字替换为前面讲到过的汇编指令,会得到如下形式的类asm代码:

I.CONST, 10, I.CALL, /* factorial */ 7, 1, I.PRINT, I.HALT, I.LOAD, // factorial start,7指向的即是这里 -3, I.CONST, 1, I.SUB, I.JUMP_IF_NOT_ZERO, 17, I.CONST, 1, I.RETURN, /* n */ I.LOAD, -3, /* factorial(n - 1) */ I.LOAD, -3, I.CONST, 1, I.SUB, I.CALL, /* factorial */ 7, 1, I.MUL, I.RETURN, // factorial end对照JS源码、虚拟机代码,仔细阅读,方能理解此段汇编代码的含意,相应的,也就可以理解opcode。

但如果未得到得虚拟机代码,或是虚拟机代码又被进行了加密,如:使用JShaman对虚拟机代码进行了混淆加密。那,想要理解opcode,则是万难。

最后,请再来欣赏这段优雅的JS代码:

1, 10, 5, 7, 1, 3, 4, 7, -3,1, 1, 10, 9, 17, 1, 1, 6, 7, -3, 7, -3, 1, 1, 10, 5, 7, 1, 11, 6仅是一行,如果是大段大段的,或是夹杂在混淆加密保护过的JS代码中,酸爽。



关键词:保护,虚拟

74
73
25
news

版权所有© 亿企邦 1997-2025 保留一切法律许可权利。

为了最佳展示效果,本站不支持IE9及以下版本的浏览器,建议您使用谷歌Chrome浏览器。 点击下载Chrome浏览器
关闭