Skip to content

Latest commit

 

History

History
210 lines (161 loc) · 7.22 KB

File metadata and controls

210 lines (161 loc) · 7.22 KB

JNVM - Java Native VM 保护器

一款强大的 Java 字节码保护工具,将 Java 方法转换为原生代码执行,提供强有力的反编译和逆向工程保护。

特性

  • 原生 VM 执行:将 Java 字节码转换为自定义 VM 解释器执行的原生代码
  • 操作码混淆:每条字节码指令映射到随机操作码值,防止轻易重建
  • ChaCha20 加密:所有字节码和字符串使用 ChaCha20 流密码加密
  • 跨平台:通过 Zig 编译器支持多平台(Windows、Linux、macOS、Android)
  • INVOKEDYNAMIC 支持:支持 lambda 表达式和动态方法调用(实验性)

警告:INVOKEDYNAMIC 实现为实验性功能,可能存在 bug。生产环境请谨慎使用。

环境要求

  • Java 8+
  • Zig 0.11+(用于原生编译,需解压到程序 JAR 同级目录)
  • Gradle 8+

Zig 不再从系统 PATH 中查找。请将 Zig 官方压缩包解压到与 jnvm.jar 同级的目录下,目录名使用 zig-<架构>-<系统>-<版本> 形式,例如:

app/
  jnvm.jar
  zig-x86_64-windows-0.14.0/
    zig.exe

程序会自动扫描同级目录下所有 zig-* 文件夹,并优先选择与当前系统/架构匹配的 Zig 可执行文件。

使用方法

配置文件

创建 config.yml 文件:

# 输入 JAR 文件
jar: test/app.jar

# 输出 JAR 文件
out: test/app-protected.jar

# 保护规则
protect:
  - "**"  # 保护所有方法

# 目标平台
targets:
  - x86_64-windows-gnu

# 选项
debug: false
native-dir: native
zig-exe: D:/tools/zig/zig.exe
encrypt-strings: false
direct-native-rewrite: false

zig-exe 为可选项。设置后会优先使用该路径指向的 Zig 可执行文件;未设置时,程序才会回退到 jnvm.jar 同级目录下的 zig-* 文件夹自动发现机制。

运行

java -jar jnvm.jar config.yml

保护规则

规则 描述
package.** 保护包及子包中的所有方法
ClassName 保护类中的所有方法
ClassName#methodName 保护特定方法
@annotation 保护带有注解的方法

direct-native-rewrite 选项:

  • false(默认):通过重写方法体调用桥接方法进行保护
  • true:将被保护的非 <clinit> 方法重写为真正的 native 方法,并在该类的 <clinit> 中注册每个类的原生方法

保护前后示例

原始代码

package pack.tests.reflects.annot;
import java.lang.reflect.Field;
import pack.tests.reflects.annot.anno;
public class annoe {
    @anno(val="PASS")
    private static final String fail = "WHAT";
    @anno
    public void dox() throws Exception {
        String toGet = "FAIL";
        for (Field f : annoe.class.getDeclaredFields()) {
            f.setAccessible(true);
            anno obj = f.getAnnotation(anno.class);
            if (obj == null) continue;
            toGet = obj.val();
        }
        System.out.println(toGet);
    }
    @anno(val="no")
    public void dov() {
        System.out.println("FAIL");
    }
}

保护后代码

package pack.tests.reflects.annot;
import lib.xml.abc.Dispatcher;
import pack.tests.reflects.annot.anno;
public class annoe {
   @anno(val="PASS")
   private static final String fail = "WHAT";
   @anno
   public void dox() throws Exception {
      Dispatcher.executeVoid(1282844577, new Object[]{this, annoe.class});
   }
   @anno(val="no")
   public void dov() {
      Dispatcher.executeVoid(1282844576, new Object[]{this, annoe.class});
   }
}

原始方法体被替换为原生 VM 调用,使逆向工程变得极其困难。

工作原理

  1. 扫描:分析输入 JAR,查找匹配保护规则的方法
  2. 加密:使用 ChaCha20 加密字节码,每个方法使用唯一密钥
  3. 代码生成:生成 C 源文件:
    • vm_types.h - VM 类型定义
    • vm_data.c - 加密的方法数据和字符串池
    • vm_interpreter.c - 自定义字节码解释器
    • vm_bridge.c - 带 RegisterNatives 的 JNI 桥接
  4. 编译:使用 Zig 为指定目标编译原生代码
  5. 修补:重写被保护的方法以调用原生 VM
  6. 打包:将原生库嵌入输出 JAR

兼容性

JNVM 已通过以下混淆器处理的 JAR 测试:

  • Zelix KlassMaster (ZKM) - 支持包括加密字符串解密、invokedynamic
  • ProGuard - 标准混淆
  • Allatori - 字符串加密和流程混淆
  • 原生 Java - 无混淆

支持的字节码指令(190/202 操作码)

常量指令(19 个操作码)

NOP, ACONST_NULL, ICONST_M1ICONST_5, LCONST_0, LCONST_1, FCONST_0FCONST_2, DCONST_0, DCONST_1, BIPUSH, SIPUSH, LDC, LDC_W, LDC2_W

加载/存储(50 个操作码)

ILOAD, LLOAD, FLOAD, DLOAD, ALOAD, ILOAD_0ILOAD_3, LLOAD_0LLOAD_3, FLOAD_0FLOAD_3, DLOAD_0DLOAD_3, ALOAD_0ALOAD_3, ISTORE, LSTORE, FSTORE, DSTORE, ASTORE, ISTORE_0ISTORE_3, LSTORE_0LSTORE_3, FSTORE_0FSTORE_3, DSTORE_0DSTORE_3, ASTORE_0ASTORE_3

栈操作(9 个操作码)

POP, POP2, DUP, DUP_X1, DUP_X2, DUP2, DUP2_X1, DUP2_X2, SWAP

算术运算(52 个操作码)

  • 加/减/乘/除/取余IADD, LADD, FADD, DADD, ISUB, LSUB, FSUB, DSUB, IMUL, LMUL, FMUL, DMUL, IDIV, LDIV, FDIV, DDIV, IREM, LREM, FREM, DREM
  • 取负INEG, LNEG, FNEG, DNEG
  • 位运算/移位ISHL, LSHL, ISHR, LSHR, IUSHR, LUSHR, IAND, LAND, IOR, LOR, IXOR, LXOR
  • 类型转换I2L, I2F, I2D, L2I, L2F, L2D, F2I, F2L, F2D, D2I, D2L, D2F, I2B, I2C, I2S
  • 比较LCMP, FCMPL, FCMPG, DCMPL, DCMPG

控制流(26 个操作码)

  • 条件跳转IFEQ, IFNE, IFLT, IFGE, IFGT, IFLE, IF_ICMPEQ, IF_ICMPNE, IF_ICMPLT, IF_ICMPGE, IF_ICMPGT, IF_ICMPLE, IF_ACMPEQ, IF_ACMPNE, IFNULL, IFNONNULL
  • 无条件跳转GOTO, GOTO_W
  • 开关TABLESWITCH, LOOKUPSWITCH
  • 返回RETURN, IRETURN, LRETURN, FRETURN, DRETURN, ARETURN
  • 其他IINC, ATHROW

对象操作(12 个操作码)

NEW, CHECKCAST, INSTANCEOF, GETFIELD, PUTFIELD, GETSTATIC, PUTSTATIC, INVOKEVIRTUAL, INVOKESPECIAL, INVOKESTATIC, INVOKEINTERFACE, INVOKEDYNAMIC

数组操作(20 个操作码)

NEWARRAY, ANEWARRAY, MULTIANEWARRAY, ARRAYLENGTH, IALOAD, LALOAD, FALOAD, DALOAD, AALOAD, BALOAD, CALOAD, SALOAD, IASTORE, LASTORE, FASTORE, DASTORE, AASTORE, BASTORE, CASTORE, SASTORE

监视器(2 个操作码)

MONITORENTER, MONITOREXIT

未实现(12 个操作码)

操作码 原因
JSR, RET, JSR_W 自 Java 6 起已弃用
WIDE 扩展局部变量索引(很少需要)
RET_* 变体 WIDE 扩展的一部分

从源码构建

git clone https://github.com/AlphaAutoLeak/jnvm.git
cd JNVM
./gradlew build

编译后的 JAR 位于 build/libs/ 目录。

许可证

本项目仅供教育和合法软件保护目的使用。

免责声明

请负责任地使用本工具。作者不对任何滥用或本软件造成的损害负责。