强,不是靠某一道墙,而是八道彼此独立的防护叠在一起。攻击者要突破的不是一层,是每一层——而任何一层,都足以让一键破解失效。
先在 Lua 源码上做重命名、加密、控制流重塑,再把整段脚本编到 LuaJC 字节码打进 dex,做 dex 级别的字节码加固。走到这里,源码级反编译已经拿不到任何可读线索。
关键代码不再以任何可读形式存在,而是运行在一套私有的虚拟执行环境里。反编译器打开,只有无从下手的字节。
字符串、常量与关键数据被层层加密。静态分析拿不到哪怕一条明文线索——搜遍产物,什么都对不上。
程序的执行逻辑被彻底打散、重排。读起来像一团理不清的乱麻,跟不上它到底在做什么,更别提改动它。
脚本编成 Dalvik 字节码后,用 BlackObfuscator 在 dex 层做控制流扁平化与类名重排。jadx / apktool 打开,只有一堆乱码类名和被压成状态图、绕不清的跳转。
最要害的部分不停留在字节码。dex2c 把 dex 里的核心方法翻译成 C++,交叉编译成 .so 内嵌进产物;再套一层 O-MVLL 的 LLVM 混淆——原生层的控制流平坦化、字符串加密与 MBA 算术混淆。到这里,逆向的战场从「读脚本」被拖进了「啃原生 arm64」。
核心方法从 dex 里被抽出、逐条翻译为 C++,走 NDK 交叉工具链编成 arm64 / armv7 的 .so,与 dex 合成单文件产物。逆向从此不能只看字节码——要先把 native 层啃下来。
抽出来的 .so 再过一遍 LLVM 混淆插件:原生层控制流平坦化、字符串加密、MBA 算术混淆与反 hook。IDA / Ghidra 打开,函数图变成一张无从入手的蜘蛛网。
实时检测调试、注入、异常环境与作弊工具,并可选注入 GG / VPN 循环检测。一旦发现被撬,脚本当即自我失效——留给对手的只是一具空壳。
产物按 App 签名指纹白名单发放。被扒走、塞进别处的执行器,直接失效——就算拿到手,也跑不起来、用不了。
八道防线各自独立,攻击者必须逐层突破;而一键破解,连第一层都过不去。
别被「原生 .so」的名头唬住。纯 SO 是单层原生;Lua→DEX 走的是双层混合——先把脚本压进 Dalvik,用 BlackObfuscator 做黑盒控制流扁平化,再用 dex2c 把核心方法抽出来翻成 C++、编成 arm64 .so 内嵌回去,最后合成单个 dex。纯 SO 有的原生强度它全有,外面还多裹一层纯 .so 根本挂不上的黑盒 Dalvik——两个 decompiler 一起卡死。
从明文脚本,到纯原生 .so,再到 DEX 黑盒混合——产物一层比一层难拆。最狠的不是纯原生,是把原生核心再裹进一层黑盒 Dalvik 的混合产物。
local function grantVip(uid) local u = User.find(uid) u.vip = true u:save() return "ok" end
local _0x3f=_ENV;local a,b=_0x3f[Ϝ("\x91\x2e")],0 while b<3 do if b==0 then a=a(...) elseif b==1 then a[Ϝ("\x4d")]=!0 end b=b+1 end
0x4a1c ldr x8, [sp, #0x40] 0x4a20 eor x8, x8, x9 ; MBA 0x4a24 cbnz w0, #0x4b90 ; CFF 0x4a28 bl sub_3f80 ; str-dec
# jadx 里:控制流被压成状态图 :sw packed-switch p0, :disp :L1f invoke-static {v2}, Lﺡ;->ᰤ(I)I ; ←dex2c 原生桩 move-result v0; goto :sw :L4d if-nez v0, :L08; goto :sw
dex2c 把核心方法翻成 arm64 机器码:Lua 字节码有 luadec,机器码没有任何工具能一键还原;对 .so 跑 strings 也搜不到明文(编译前已做字符串加密)。这层纯 SO 和 DEX 都有。
DEX 是 Dalvik + 内嵌 .so 的混合,逆向要在两个完全不同的运行时之间来回跳,还得盯 JNI 边界;纯 SO 只有单层原生,啃完就到底。
BlackObfuscator 在 dex 字节码上做控制流扁平化,jadx 还原出来是一张状态图,读不出真实执行路径。这层挂在 Dalvik 上——纯 .so 没有 Dalvik,根本套不上。
抽出的核心不是干净的 C 翻译,而是机器生成的巨型 switch 状态机(本身即控制流混淆),再过 O-MVLL 平坦化 / 字符串加密 / MBA。IDA 打开又是一张蜘蛛网。
| 对比维度 | 原始脚本 | 脚本混淆 免费 | Lua→SO 纯原生 | Lua→DEX 黑盒混合 · 最强 |
|---|---|---|---|---|
| 产物形态 | 明文 Lua | 混淆 Lua | 原生 .so | Dalvik ⊕ 内嵌 .so |
| 核心方法原生化 · dex2c | — | — | ● | ● |
| 原生层 O-MVLL 混淆 | — | — | ● | ● |
| 黑盒控制流 · Dalvik 层 | — | — | 纯 .so 挂不上 | ● |
| 逆向战场 | 直接可读 | 脚本层 | 单层原生 | 双层 · 跨运行时 |
| 一键还原源码 | 直接可读 | 较难 | 几乎不可能 | 几乎不可能 |
| 逆向难度 |
纯 SO 已经够狠——单层原生,IDA 里就是一张蜘蛛网。而 Lua→DEX 在同样的原生核心外面,又套了一层纯 .so 挂不上的黑盒 Dalvik 控制流,还逼着逆向在两个运行时之间来回跳。这一档,才是天花板。
轻度保护、随手分发,用免费版足够;核心脚本、商业分发、要求「抄不走搬不动」,上付费版八层全开。两者都在注册后使用。
纯脚本级混淆,注册后免费使用,不占用任何次数。产物是普通 Lua,可跨执行器运行。
商业级纵深防护,抄不走、搬不动。含免费版全部能力,并叠加:
| 能力 | 免费版 | 付费版 |
|---|---|---|
| 脚本级混淆 | ● | ● |
| 数据加密 | 基础 | 全面 |
| 控制流保护 | 基础 | 全面 |
| 自定义虚拟机 | 可移植档 | 私有增强 |
| 字节码级 dex 加固 | — | ● |
| dex2c 原生化(→ .so) | — | ● |
| 原生层 O-MVLL 混淆 | — | ● |
| 运行时自我保护 | — | ● |
| 授权执行器绑定 | — | ● |
| 跨执行器运行 | ● | 需专属执行器 |
| 占用混淆次数 | 否 | 是 |