VM · 字节码虚拟机保护引擎

将 JavaScript 编译为
不可读的 VM 字节码

三层叠加保护:字符串加密、OLLVM 风格控制流平坦化、自定义虚拟机字节码。无法安全虚拟化的语法会自动降级为强混淆,确保运行结果与原文件完全一致。

68+操作码指令集
3叠加保护层
0兼容性损失
$1每次使用,不订阅
加密前license.js
function checkLicense(key) {
  if (key === "SK-PROD-2024") {
    return true;
  }
  return false;
}
VM 编译
加密后license.protected.js
var _0x4f2a=_0x8b91(0x1a);function _0x2c91(_0x3d){var _0x1e=[0x53,0x4b];while(!![]){switch(_0x4f2a(0x1a3)){case 0x7:if(_0x3d===_0xe4(0x2b1,0x7))return _0x4f2a(0xff);case 0x21:return _0x4f2a(0x100);}}}
源文件 .js / .mjs / .cjs · 免费版 ≤ 10 KB · $1/次解锁至 50 MB

免费:字符串加密、控制流平坦化、标识符重命名、死代码注入——文件不超过 10 KB,不含字节码 VM。Max Security(字节码 VM 、域名锁定、最大 50 MB)每次 $1——不订阅、不打包、没有起购门槛。

拖拽文件到此处 浏览
支持任意 JavaScript 文件
域名锁定会在实际输出 VM runtime 时生效;若脚本没有可 VM 化的函数,结果区会返回 warning。
高级选项
如果这段代码只会跑在你自己控制的 V8 / Node 环境(不经过浏览器),可以关掉这一项——反调试与反沙箱检测针对的是浏览器 DevTools 和无头浏览器特征,在非浏览器环境下可能没有必要,甚至会误判。
受保护输出
{ }
受保护代码将在此处生成
保护管线

三层叠加,强度逐级递进

01

字符串混淆

所有字符串字面量被收集进加密常量池,按需解密。原始字符串不再以明文形式出现。

02

控制流平坦化

函数体切分为基本块,重组为 switch(state) 状态机分发,叠加不透明控制流噪声。

03

字节码虚拟机

可虚拟化的函数被编译为自定义操作码,由运行时栈式 VM 执行,源逻辑隐藏在随机化 dispatcher 之后。

反调试响应

检测时间差异常、自动化环境、被 patch 的原生方法,以及可疑的运行时特征。

环境检测

识别 jsdom、Headless Chrome、Puppeteer、Selenium 等自动化分析环境。

域名锁定

将保护产物绑定到指定域名。fail-closed 模式会阻止未知环境下的执行。

加密字节码

采用紧凑二进制 payload、函数级懒解密、派生密钥与完整性校验,而非可读的 JSON 中间表示。

HTML 混编

HTML 混编与注释标记

HTML 内联事件(onclick)、外部脚本和全局 API 通常按函数名调用。使用 /* @public */ 保留导出名,使用 /* @VM */ 优先为关键函数启用 VM 保护。

index.html
html · javascript
给被 HTML 属性或外部代码按名字调用的函数加上 /* @public */;关键算法函数可再加 /* @VM */ 强制尝试 VM。
@public / @VM 使用规范与示例
@public
/* @public */ function myFunction(){
  // 函数名会被保留,onclick 才能正常调用。
  return compute();
}

保留导出名字,避免重命名破坏 onclick="myFunction()"、外部 script 或 window.x 调用。函数内部变量仍会继续混淆。

@VM
/* @VM */ function score(a, b){
  return (a ^ b) + 123;
}

强制为该函数尝试 VM 化。csp-safecompat 仍会做保守检查;若当前模式无法安全 VM 化,会自动降级并给出 warning。

@public + @VM
/* @public @VM */ function submitForm(){
  return protectedSubmit();
}

两者可以组合使用。@public 只负责保留名字,@VM 只负责强制尝试虚拟化,互不冲突。

推荐写法

/* @public */ function exportedApi(){ return 1; }

/* @public */ const exportedFn = function(){ return 2; };
/* @public */ const exportedArrow = (x) => x + 1;

/* @VM */ const core = function(x){ return x * 7; };

/* @public @VM */ const publicCore = function(x){
  return core(x) + 1;
};

把标记写在函数声明或变量声明之前最稳定。@public@VM 的推荐写法保持一致。

HTML 混编示例

<button onclick="submitForm()">提交</button>
<script>
/* @public @VM */ function submitForm(){
  var token = buildToken();
  console.log(token);
}

/* @VM */ function buildToken(){
  return Date.now() ^ 0x5a5a;
}
</script>

submitForm 被 HTML 字符串引用,所以必须标注 @public;它也可以同时标注 @VM。内部算法 buildToken 没有被 HTML 直接引用,只需要 @VM 即可。

注意事项

@public 不会降低保护强度,它只保留外部可见的名字。@VM 是强制尝试,不是强制破坏兼容性。在 allowEval=false 的模式下,捕获外层局部变量的函数可能会降级并返回 warning。建议把标记写在声明之前,避免写在 return 语句中间。