Twisted:开源栈式 JS 虚拟机(JSVMP)功能介绍、痛点、后续计划#

仓库:github.com/0xfffb/twisted

测试地址:click


定位#

Twisted 是用 TypeScript 实现的栈帧式 JSVMP 工具链:将子集 JavaScript 编译为自定义 IR,再汇编为字节码,由浏览器或 Node 侧 VM 解释执行。目标场景包括提高前端逻辑被脚本化还原的成本(如风控、反作弊相关研究)


模块总览#

模块 职责
Compiler Babel 解析 AST → 线性 Instruction[](IR)
Assembler IR → bundle:{ bytecode: number[], meta: string[] }
Runtime / VM 解释执行 bytecode(依赖注入、async/await、闭包、调用约定等)
Obfuscator IR 级混淆 Pass,可串联执行
Builder esbuild 打包浏览器 runtime;可选 javascript-obfuscator
CLI build / runtime / all,串联整条编译流水线

Compiler#

由 Babel 得到 AST 后,再递归遍历节点,将 JavaScript 译为 IR。

为何先 IR,再 bytecode?

多一层 IR 是为了工程上的可维护性与可扩展性:优化、混淆、回填标签等可在结构化指令序列上完成,再统一交给 Assembler 落盘为字节码,比「AST 直出 bytecode」更易迭代。


Assembler#

把 IR 编成 VM 所需的 bundle:完成 Jmp / JmpIf 等跳转回填、字符串等常量进 meta 池等。

产物形态示例:

{ bytecode: number[]; meta: string[] }

Runtime / VM#

栈帧式虚拟机,执行 Assembler 输出的 bytecode,与 Compiler 的指令语义一一对应。


Obfuscator#

在 IR 层做变换(如算术多态),使多次编译得到的 IR 不必相同,从而抬高静态/模式化分析成本。具体 Pass 以 src/obfuscator/ 为准。


Builder#

将 VM 与内嵌 bundle 打成可在浏览器加载的脚本;流程上包含 ES 降级(如降至 ES5)与可选的 javascript-obfuscator 混淆,详见 src/builder/


开发痛点#

  • 可参考的成熟开源项目很少:浏览器侧「JS → 自定义字节码 + 自研 VM」整条链路,公开、可维护、能跟着跑的仓库不多,很多细节只能自己摸。
  • 体系化文章与教程稀缺:编译器前端、IR 设计、跳转回填、VM 调用约定、与混淆流水线结合等,分散在零星博客或逆向讨论里,缺少从零到可跑产物的成篇文档,入门与对比成本都高。

后续计划#

  • 先落地控制流图(CFG):在现有线性 IR 之上建立基本块、前后继等结构,便于分析与后续优化;再在此之上逐步丰富 IR Pass。
  • 反 Hook / 环境探测:在编译期或运行时侧增加对关键 API(如 consolefetcheval 等)是否被篡改、代理或调试器附加的检测与对抗策略(与示例 example/fingerprint.js 一类逻辑对齐,逐步产品化)。
  • 按优先级补齐 Compiler / VM(逻辑运算、throwtry catch、等语法)。
  • 欢迎通过 Issue / PR 讨论架构与对抗思路;功能与修复建议尽量附带或可更新 npm test

我并不是反作弊和风控业内人士,很多想法和功能都是闭门造车,希望大家指正