Skip to content

Releases: Rainyqwq/Lua-Obfuscator

v3.4.0 — editor cursor alignment, VM advanced mode, theme spread animation

Choose a tag to compare

@Rainyqwq Rainyqwq released this 19 Aug 17:40

Lua Obfuscator v3.4.0 Release Notes

发布日期:2026-08-20

概要

  • 编辑器光标错位修复:textarea 不再被 min-height:100% 钳在容器高度内,强制以 scrollHeight 长高,光标永远停在正确的 gutter 行号上
  • VM 高级模式生效vm_mode='advanced' 不再被 JS 桥全部推成 boolean / 被 worker 的 typeof value === 'boolean' 过滤器丢弃
  • 主题切换扩散动画:基于 document.startViewTransition(Chrome 111+/Edge 111+)+ JS fallback,从按钮位置圆形扩散/收缩回按钮位置,0.28s linear
  • UI 设计规范合规(Apple Liquid Glass):token 化所有颜色/圆角/阴影/缓动/字号;3 个 panel 视觉统一
  • 全局动效统一:13 处裸 .15s transition 全部补 var(--ease-out-quart);loading overlay/scrim 用项目缓动 token
  • 可访问性prefers-reduced-motion / prefers-reduced-transparency / prefers-contrast 三条 media query 完整覆盖
  • 代码健壮性:9 处隐藏 bug 修复(worker race / Worker race / memory leak / null deref / duplicate resize listener 等)
  • 新增 design tokens--danger / --warn / --dark-mode 变体全部 5 处硬编码替换

修复

编辑器光标错位(核心 bug)

<textarea>height:auto + min-height:100% + overflow:hidden 三者并存时不会随内容自动长高 —— 它被钉在 scroll 容器高度处。当用户输入很多行时,文本溢出被隐藏,但 caret 仍画在 textarea box 内。结果:在末行按 Enter 时光标跳到错误的位置(差约一行高)。

修复index.html):

  • 移除 min-height:100%
  • 在每次 updateLineCount()强制 textarea.style.height = textarea.scrollHeight + 'px',让 textarea 跟随内容长高

实测对齐偏差从 22.5px → ≤0.19px(亚像素圆整)。

VM 高级模式开关无效

JS→Worker 消息桥把 options 中所有 value 都过滤成 boolean(if (typeof value === 'boolean')),丢弃了 vm_mode='advanced' 等字符串。同时 sync 路径的 obfuscateLua() 走相同过滤逻辑。

修复

  • Worker 的 onmessagetypeof 分发 boolean / number / string / array / null
  • obfuscateLuaAsync / obfuscateLua 同样改为按类型分发
  • 数组(name_whitelist / string_whitelist)也走 table push

_luaObfuscatorReady 单 flag bug

单一 flag 同时代表 main-thread Lua + Worker 都已初始化。但两者是异步独立完成的:主线程同步,Worker 异步。Worker 还没 ready 时点击混淆 → 直接拒绝。

修复:拆成三个 flag:

  • _luaMainReady — 主线程 Lua 已初始化
  • _luaWorkerReady — Worker 已 postMessage ready
  • _luaObfuscatorReady = _luaMainReady && _luaWorkerReady(派生)

obfuscateLuaAsync 快速双击 → 首个 Promise 永远 hang

obfuscateLuaAsync 直接覆盖 _obfuscateCallbacks,没有 reject 前一个 → 第一个 promise 永远不 resolve。修复:覆盖前先 reject(new Error('新的混淆请求已发起,上一个被取消'))

Worker 内存泄漏

每次 new Worker(URL.createObjectURL(blob)) 都没 revokeObjectURLURL.createObjectURL 是 ObjectURL,每条都持久占用。修复:Worker 构造后立即 revokeObjectURL(Worker 已快照引用,安全)。

Worker 报错后 handle 仍占用

onerror_luaObfuscatorReady=false 但不 terminate worker → 下次 postMessage 投到死 handle。修复onerrorterminate() + _obfuscateWorker = null,下次自动重建。

Resizer 拖拽时每帧 window.matchMedia(...)

isMobile()mousemove 高频事件里创建新 MediaQueryList。修复:缓存 MQL 到 closure 外层。

DOM null deref(多处)

  • appendOutputclearOutputdoObfuscate 等:加 null guard
  • 删除 line-count / output-status 后残留的 JS 引用加 null guard

重复的 window.addEventListener('resize', ...)

syncGutterScroll listener 还在;新的在 initUI 里。修复:删旧的。

新增

Theme 切换扩散动画

1. Path 1 — View Transitions API(Chrome 111+/Edge 111+)

document.startViewTransition(() => {
  swap();  // 切换 :root.dark
});
transition.ready.then(() => {
  // 用 WAAPI 动画 clip-path:从点击位置扩散/收缩回
  document.documentElement.animate(
    { clipPath: isDark ? expand : shrink },
    { duration: 280, easing: 'linear', pseudoElement: '::view-transition-...' }
  );
});
  • light → dark:新 snapshot(dark)从点击位置扩散覆盖 viewport
  • dark → light:旧 snapshot(dark)从全屏收缩回按钮位置

2. Path 2 — JS fallback(旧浏览器)

body 级 .theme-veil div,clip-path: circle() 从 0 扩到 endRadius(或反向)。veil 颜色 = OLD theme;50% 时 swap class + 切换 veil 颜色 = NEW theme。动画结束 display:none + opacity:0 双重隐藏,避免合成器残留。

3. 闪烁修复

::view-transition-old(root)@keyframes vt-hide { from { opacity:1 } to { opacity:0 } },在 260ms 内淡出,配合 transition.skipTransition() 在 WAAPI finish 事件强制终止 SVT —— 彻底消除"dark→light 末尾黑色闪烁"。

Startup 进入动画

四个元素 stagger 进入(总时长 < 600ms):

  • nav 从 -12px 滑入(delay 0.05s)
  • 左 panel 从 +14px 滑入(delay 0.18s)
  • 右 panel 从 +14px 滑入(delay 0.30s)
  • 动作条 + scale(.96) 弹入(delay 0.46s)

prefers-reduced-motion 下所有 delay 归零,立即落到 resting state。

实时跟随系统主题

Theme.userPref 区分"用户已锁定"和"跟随系统"。matchMedia.addEventListener('change', ...) 监听 OS 主题变化;锁定后不再被 OS变化覆盖。带旧浏览器 addListener fallback。

预渲染主题 class(无 FOUC)

<head> 中插入同步小脚本,在 fengari/JS 加载前就根据 locallocalStorage + prefers-color-scheme<html>dark/light class —— 首屏渲染前不闪烁。

Design Tokens 补全

:root {
  --danger:    #ff375f;
  --danger-bg: rgba(255,55,95,.1);
  --warn:      #ff9f0a;
  --warn-bg:   rgba(255,159,10,.1);
}
:root.dark {
  --danger:    #ff5e7a;
  --danger-bg: rgba(255,94,122,.12);
  --warn:      #ffb340;
  --warn-bg:   rgba(255,179,64,.12);
}

替换 5 处硬编码 #ff375f / #ff9f0a

  • .panel-header .badge.status-err / .status-warn
  • .btn-danger(含 hover bg)
  • .tok-number.output-sink .error.output-sink .warn
  • .batch-file-row .fstatus.error.fbtn:hover

UI 重做(按 DESIGN 设计规范)

Segmented control(快速/均衡/最强/自定义)

  • pill ::afterleft+width 动画改为 transform: translateX + scaleX(compositor 友好)
  • duration 0.35s → 0.22s(Apple HIG)
  • 移动端 flex-wrap:wrap 时隐藏 pill,按钮变 plain chip,避免跨行穿模

iOS Switch

  • track / thumb 统一 0.22s(之前 0.2s + 0.25s 不同步)
  • thumb 高度 20px → 18px,更轻盈
  • translateX(16px) 落点改精确

Output panel

  • radius --r-panel (22px) → --r-card (18px),与邻居面板统一
  • shadow --sh-card--sh-panel,与邻居面板统一
  • 去掉 1px hairline border(shadow 已经分隔了)

Stats bar

  • 左右两栏 padding 统一 var(--pad-x)(之前输出栏用 24px,输入栏 22px,1-5px 错位)
  • border-top:1px solid var(--hairline)

Action bar

  • 所有按钮统一 32px 高(之前主按钮 30px,cluster 34px,4px 错位)
  • cluster 用 inset 0 0 0 1px var(--hairline) 描边,内部按钮 -1px 0 0 var(--hairline) 分隔线
  • 图标 stroke-width:1.75 + currentColor + round caps(DESIGN icons.md)
  • 隐藏"全选/全不选"按钮(按 DESIGN 简化)

Whitelist input

  • radius --r-chip (6px) → --r-thumb (12px)
  • focus box-shadow: 0 0 0 3px halo + z-index:1(不被 .unified-paneloverflow:hidden 截断)

Placeholder

  • 重命名 .ic.placeholder-icon(避免与 utility .ic 冲突)
  • HTML 用 .placeholder-icon / .placeholder-title / .placeholder-hint 三个 scoped class

全局动效统一

位置
13 处 .15s transition 无 easing(默认 ease var(--ease-out-quart)
.loading-overlay / .drawer-scrim ease var(--ease-out-quart)
.btn:active 100ms 裸数字 80ms var(--ease-out-quart)
.btn transition 多 duration/easing 混合 统一 transform .22s var(--ease-out-quart)

可访问性

三条 media query 完整覆盖:

@media (prefers-reduced-motion: reduce) {
  /* 所有 transition / animation: none */
}
@media (prefers-reduced-transparency: reduce) {
  /* glass / backdrop-filter 退化为实色 */
}
@media (prefers-contrast: more) {
  /* border 加粗,开关描边可见 */
}

Editor 块下的 .enter-nav / .enter-panel / .enter-cta 也在 reduced-motion 下用 0.01s 动画立即落到 resting state。

版本

模块 版本
index.html (Web) v3.4.0
package.json 3.4.0
package-lock.json 3.4.0
obfuscator.lua v3.3.0
passes/vm.lua v3.3.0
passes/vm_advanced.lua v3.1.0
passes/vm_protect.lua v2.9.2
passes/num_encrypt.lua v1.4.0
passes/header.lua v1.1.1
passes/api_indirect.lua v1.0.0
passes/string_pool.lua v1.2.0
passes/var_mangle.lua v1.2.0
passes/cf_flatten.lua v1.0.0
passes/bcf.lua v1.0.0
passes/bb_split.lua v1.0.0
passes/adv_fake_cf.lua v1.1.1
passes/junk_comment.lua v1.0.1
passes/anti_debug.lua v1.0.0
passes/call_indirect.lua v1.0.0
passes/string_restore.lua v1.0.0

测试

  • 编辑器:headless Edge 实测 caret 对齐 ≤ 0.19px 偏差(27 / 28 / 31 行)
  • 混淆:obfuscate('local x = 1') 在 JS fallback 路径 OK,veils 元素创建成功
  • Theme:headless Edge 实测 startViewTransition=true,Theme.mq 监听器绑定成功
  • 可访问性:prefers-reduced-motion 下动画时长 0.01ms

构建

  • obfuscator_bundle.lua:22 模块
  • index.html:Web 版本同步更新
  • 体积:index.html 编辑器 CSS + JS 总长 ≈ 50KB(含 FENGARI_SOURCE / OBFUSCATOR_LUA / build_html.js 注入的 ≈ 220KB 之外)

Migration

无破坏性变更。从 v3.3.0 升级:

  1. 替换 index.html
  2. package.json / package-lock.json 的 version 字段更新(npm install 不会重新装,只是 metadata)
  3. 主题切换体验变化:之前是瞬时切换,现在是 0.28s linear wipe 动画(如果用户希望关闭,prefers-reduced-motion: reduce 已自动跳过)
  4. 可访问性:reduced-motion / reduced-transparency / contrast 用户体验改善

Known Issues

  • Worker 在 file:// 协议下仍打印 "Unsafe attempt to load URL from frame with URL file://..." —— Chrome 同源策略限制(每个 file: URL 是独立 opaque origin)。Worker 仍正常运行,警告仅是信息性。发行版打包为 Electron 或用 chrome://flags/#unsafely-treat-insecure-origin-as-secure 启动可消除。

License

MIT · Author: Rainy_qwq · GitHub

v2.10.0

Choose a tag to compare

@Rainyqwq Rainyqwq released this 24 Jul 07:30

Lua Obfuscator v2.10.0 Release Notes

发布日期:2026-07-24

概要

P2 函数级 VM 保护:通过 --@vm 注解选择性保护关键函数,兼顾强度与性能。

新增

函数级 VM 保护 (Function-Level VM)

  • 新增 vm_function Pass(passes/vm_function.lua
  • 通过 --@vm 注解标记需要保护的顶层函数
  • 每个函数独立编译为 VM 字节码,运行时按需解密执行
  • 与整文件 VM (vm_protect) 互斥:启用函数级 VM 时自动关闭整文件 VM

注解语法

--@vm
local function sensitive_algorithm(data)
  -- 此函数将被 VM 字节码虚拟化保护
  return transform(data)
end

local function normal_function(x)
  -- 此函数不受影响
  return x + 1
end

CLI

  • --vm-function:启用函数级 VM 保护

Web

  • 新增 "函数级VM保护" 复选框
  • 预设:balanced/max 默认开启,fast 默认关闭

修复

  • 修复 protect_as_expr 函数体解析 bug(func_stmt.bodyfunc_stmt.body.stmts
  • 修复 protect_as_expr 输出作用域问题(移除外层 do...end 包裹)

测试

  • tests/test_vm_function.lua:4 个测试用例
    • 单函数保护
    • 多函数选择性保护
    • 递归函数保护
    • 无注解时透传

版本

  • 版本号:v2.10.0
  • CLI / Web / 输出头 / package.json / 文档均已更新

升级

git pull origin main

v2.9.0

Choose a tag to compare

@Rainyqwq Rainyqwq released this 23 Jul 10:45

Lua Obfuscator v2.9.0 Release Notes

?????2026-07-23

??

P1 ????????????/??????????????CLI + Web??

??

????

  • fast?????? + ???? + ???? + ????????
  • balanced??????? VM / ????
  • max??????? VM + ????

CLI?--preset fast|balanced|max
Web????????

???

  • ????? name_whitelist / --preserve-name <id>????????????
  • ?????? string_whitelist / --preserve-string <s>?????????????

??????

  • CLI?--export-config <file> / --import-config <file>?Lua ??
  • Bridge?export_user_config / import_user_config / apply_preset / list_presets
  • Web???/?? JSON ??

??

  • tests/test_p1_presets_whitelist.lua
  • CI ?? P1 ??
  • ?? P0 / full / string_pool ????

??

lua build_bundle.lua
node build_html.js
lua tests/test_p1_presets_whitelist.lua

Web ???? Ctrl+F5 ?????

License

MIT ? Rainy_qwq

v2.8.2

Choose a tag to compare

@Rainyqwq Rainyqwq released this 23 Jul 10:12

Lua Obfuscator v2.8.2 Release Notes

发布日期:2026-07-23

概要

P0 工程质量:自动化回归、流水线超时、Web 混淆超时收紧。

新增

  • tests/test_p0_regression.lua:单 Pass / 组合 / 语义对拍 / 大文件防挂死 / VM 冒烟
  • .github/workflows/ci.yml:CI 跑 P0 + test_full + string_pool 回归
  • PassManager:run(..., { max_total_ms }):整条流水线总耗时上限
  • 主程序默认 max_total_ms = 120000
  • Web 异步混淆超时 5 分钟 → 90 秒,失败可取消并提示

升级

lua tests/test_p0_regression.lua
lua build_bundle.lua && node build_html.js

License

MIT · Rainy_qwq

v2.8.1

Choose a tag to compare

@Rainyqwq Rainyqwq released this 23 Jul 10:02

Lua Obfuscator v2.8.1 Release Notes

发布日期:2026-07-23

概要

v2.8.1 是一次紧急稳定性修复:修复变量名混淆在含表构造输入上的死循环,以及默认功能开关策略调整。

修复

variable_mangling 死循环(关键)

  • 文件: passes/var_mangle.lua
  • 现象: 浏览器即使用户不开启 VM,混淆含 { ... } 的源码(例如仓库内 passes/instr_sub.lua)也会页面卡死。
  • 根因: collect_table_keys 扫描表构造时,遇到 { / } 调整 depth未推进扫描下标 i,导致无限循环。
  • 修复:depth + 1 / depth - 1 时同步 i = i + 1
  • 验证: 单独变量名混淆约 28ms;默认全开(无 VM)约 156ms 完成。

行为变化

默认启用的 Pass

除以下两项外,全部默认开启

默认关闭 说明
vm_protect VM 字节码虚拟化
anti_debug 反调试检测

默认开启包括:字符串加密、变量名混淆、数字加密、指令替换、虚假控制流、控制流平坦化、BCF、基本块拆分、调用间接化、垃圾注释等。

版本标识

  • CLI / Web / 输出头部统一为 v2.8.1

升级

git pull
lua build_bundle.lua
node build_html.js

Web 用户请 Ctrl+F5 强制刷新。

完整变更基线

更完整的 2.8 系列能力与修复见 RELEASE_NOTES_v2.8.0.md

License

MIT · Author: Rainy_qwq
https://github.com/Rainyqwq/Lua-Obfuscator

v2.8.0

Choose a tag to compare

@Rainyqwq Rainyqwq released this 23 Jul 09:40

Lua Obfuscator v2.8.0 Release Notes

发布日期:2026-07-23

概要

v2.8.0 聚焦正确性与可组合性:修掉 VM / 数字加密 / BCF 等会导致错误结果或浏览器卡死的缺陷,并取消“启用 VM 时静默禁用其它 Pass”的做法。Pass 应各自正确、可任意组合。

新功能与能力(累计至 2.8.0)

  • 增强字符串加密(string_pool)
    每字符串独立密钥、密文切片乱序、哈希索引、多态解码器、诱饵解码路径;Fengari 下使用 32 位安全算术,避免 number has no integer representation
  • 反调试(anti_debug)
    debug hook / 计时异常 / JIT 状态检测;Web 端放宽计时阈值,减少误报。
  • 调用间接化(call_indirection)
    全局函数调用经分发表间接化。
  • VM op-pool + char-pool
    运行时操作码映射打乱 + 字符池编码,贴近真实 VM 保护形态。
  • Web
    运行超时 hook;功能开关默认可配置;移动端适配相关改动保留。

关键修复

VM(passes/vm.lua

  • 数值 for 支持负步长(修复 for i=#t,1,-1 等,字符串解密器依赖此语义)。
  • 修正 FORLOOP 继续条件运算符优先级错误(原先正步长几乎不退出 → 卡死)。
  • 解释器增加步数上限,损坏字节码时快速失败而非挂死浏览器。

常量数字加密(passes/num_encrypt.lua

  • 禁止不安全的 (n<<k)>>k 在高位溢出后回不来的编码。
  • 加法路径保证 sum 不超出目标位宽,避免 hex 截断。
  • 手写 hex / to_u32,兼容 Fengari。

BCF(passes/bcf.lua

  • 仅包装完整、括号平衡的单行语句;禁止打断多行 function( / 未闭合调用(修复 'end' expected near 'else')。

流水线(obfuscator.lua

  • 移除启用 VM 时自动禁用 instruction_substitution / control_flow_flattening / bogus_control_flow / basic_block_splitting 的逻辑。

其它

  • string_pool FNV/LCG 全面 32 位安全。
  • 头注释版本统一为 v2.8。

破坏性/行为变化

  • 启用 VM 后,用户勾选的结构类 Pass 会真正执行(不再被静默关掉)。若旧文档写“VM 会自动禁用三者”,以本版为准。
  • 混淆输出头部标识:Lua Obfuscator v2.8

验证

  • tests/test_full.lua:119/119
  • 全 Pass ± VM 对算法样例多轮回归通过
  • Fengari 执行 VM 输出样例通过

升级说明

  1. 拉取本版本后执行:lua build_bundle.lua && node build_html.js
  2. Web 用户 Ctrl+F5 刷新
  3. 建议重新混淆旧产物(旧 VM 循环语义有缺陷)

License

MIT · Author: Rainy_qwq
https://github.com/Rainyqwq/Lua-Obfuscator

v2.7.0

Choose a tag to compare

@Rainyqwq Rainyqwq released this 22 Jul 14:35

v2.7.0 Release Notes

v2.7.0 VM 新增 opcode + 改动

新增

1. Opcode 混淆 Op ID

  • 随机化 opcode 映射表,使用 Fisher-Yates Shuffle
  • 随机化后的 op ID
  • 修改 H[runtime_op]() handler 替换所有 if/elseif
  • 新增 OP_ADD=10 动态处理

2. 新增 Char Pool(字符池)

  • 运行时生成随机字符集替换部分 tostring 调用为 _chars 索引
  • 生成形式 (pool_index_1, pool_index_2, ...) 替代原始 _dec_str
  • 字符集大小 4-16 个字符

3. XOR 加密

  • XOR 动态解密,使用 key + 随机 key 混合 key 生成
  • Checksum 校验

对照表

功能 旧实现 新实现
Opcode混淆 原始 if/elseif 分支 handler 调用 H[op]()
字符池 string.byte(s,i) 逐字节 byte_to_idx[s[i]] 查表
字符串解密 string.byte(tostring(k)) 解密 字节拼接
动态分发 固定 OP_ADD=10 分发 随机化后的 op id
解密器 存储在 _d[] 字符 + 数字 + upvalue 组合为 _chars[]

兼容性

  • VM 适配 basic_block_splitting 多 Pass
  • API 与 CLI 兼容
  • 预留 op 扩展位

v2.6.0 性能优化 + 修复 init 检测

  • 优化 var_mangle 字符串拼接从 O(n²) 到 O(n)
  • 修复 Lua 脚本中 shebang 检测缺陷(#!/ 后不能有 package.preload 等)
  • CLI 默认开启 basic_block_splitting
  • release v2.6.0

v2.5.1 修复 CLI 兼容性

  • 修复 Pass 管理器
  • VM 与 Pass 兼容

v2.6.0

Choose a tag to compare

@Rainyqwq Rainyqwq released this 22 Jul 11:26

v2.6.0 Release Notes

性能优化

  • var_mangle: 单次 scan_identifiers + table.concat 拼接,从 O(n*k) 逐次 sub 拼接优化为 O(n)
  • string_pool: restore/restore_raw 改为单次 gsub 替代 N 次 gsub 循环,O(n) 替代 O(n*k)
  • pass_manager: 缓存 os.clock 为局部变量,避免每 pass 重复 nil 检查

手机端响应式适配

  • 768px + 480px 双断点 CSS
  • 移动端面板垂直堆叠(左面板 40vh,右面板 flex:1)
  • resizer 移动端跳过鼠标拖拽,resize 时清除 inline flex
  • body 从 height:100vh;overflow:hidden 改为移动端 height:auto;overflow:auto

bb_split 默认开启

  • CLI 默认 basic_block_splitting = true(obfuscator.lua)
  • Web 端 bb_split toggle default = true(index.html)

Bug 修复

  • BCF then/else 分支交换修复: 真实代码放 then(恒真谓词,总执行),假代码放 else,修复混淆后运行错误
  • bb_split JS 模板字面量转义修复: build_html.js 将 bundle 中反斜杠翻倍后注入 index.html,修复 Fengari 运行时解析错误

测试

  • test_full.lua: 119/119 通过
  • test_repro_web.lua: 100/100 通过
  • test_bisect.lua: 7/7 通过

v2.4.0-alpha

Choose a tag to compare

@Rainyqwq Rainyqwq released this 19 Jul 12:25
547b201