Skip to main content

Java VME方式保护最佳实践

Java程序介绍#

Java 是一种广泛使用的面向对象编程语言,因其语法简单、跨平台、拥有丰富又成熟的框架,开发效率高,所以大量的企业级系统都使用 Java 编写。

Java 程序可以构建为 jar 包、war 包或 class 文件,随着反编译工具的成熟,如果Java文件不保护时,反编译工具可以轻易的获取class 文件包含了类、方法、成员等信息,进而造成代码的泄露,因此对Java程序的保护变得尤为重要。

Java VME方式介绍#

Java VME 保护方式是将JVM字节码转换为自定义的虚拟机指令,运行时跳转至Native虚拟机中执行。

自定义的虚拟机代码对应了一种自定义的编码规则且保护时可以进行随机化,想要还原被保护的方法,需要逆向分析整个 C/C++ 实现的解释器的逻辑,还原其与 JVM 字节码的对应关系,这是极为困难的,而且每一个程序都要单独分析,没有通解,特别适合高安全性需求的保护场景。

另外Java VME方式还包括字符串加密,调试器检测和文件校验等功能,防止程序被调试、被篡改等风险。

支持范围#

特点#

优点

  1. 虚拟化保护:Java vme方式是对class中的所有⽅法的字节码进行代码虚拟化,可以防止jadx、jd-gui等反编译工具反编译出源码。

  2. 完整性校验:文件校验功能可校验jar包中的所有文件,防止文件被篡改。

  3. 高兼容性:保护后的jar包和war包可以在jdk1.6以上的环境运行。

  4. 跨平台部署:保护时可选择所需运行平台,保护后的程序可多个平台运行。

缺点

  1. 代码虚拟化会对程序的性能有一定影响;

  2. 目前不支持java中使用析构方法、构造方法、反射方法等代码,保护时会跳过该方法。

  3. java-vme方式不支持直接对内嵌jar包加密,需要将内嵌jar包取出后再进行加密,将加密后的内嵌jar包放回原jar包,对原jar包在进行加密。

性能问题

对一些性能敏感的方法、大量执行的方法要谨慎使用,大量测试,挑选关键的方法进行保护,不建议所有函数全部勾选代码虚拟化。

最好的方式是最为关键的代码用 JAVA VME 保护,而程序整体可以配合Java BCE方式进行保护,可达到安全性和性能最佳平衡。

运行环境#

操作系统X86X64ARM32ARM64loongarch
Windows✔️✔️N/A不支持N/A
Linux✔️✔️✔️✔️✔️
macOSN/A✔️N/A✔️N/A

功能介绍#

基础功能#

字符串加密#

加密代码中的敏感字符串,防止反编译工具直接搜索到相关的函数。

原程序反编译:

保护后反编译:

调试器检测#

程序运行时根据其调试状态去进行检测,检测到进程被调试时退出进程。

文件校验#

程序运行时检测到第一个保护的方法后,文件校验功能开始生效,文件校验可以校验jar包内所有文件的完整性,防止被篡改。

运行平台#

由于Java可跨平台使用,将Java项目入到Virbox Protector工具界面,会自动显示支持的平台。

windows和Linux系统上,如图所示:

macOS系统上,如图所示:

以上分别表示windows(x86和x64架构)、Linux(x86和x64架构)、Arm Linux(arm32和arm64架构)、macOS(x64架构和arm64架构),可根据自己需要的平台进行勾选.

注意

1.若一个运行平台都不勾选,则会保护不成功,提示"至少选择一个运行平台";

2.若要在macOS arm64平台上运行,建议在macOS系统上进行保护,需要启用签名默认对arm库进行签名;

3.若只能在windows或Linux系统上保护,但运行环境是在macOS arm64系统上,需要手动对保护后的jar包里的库进行签名,查看如何手动对jar包里loader库进行签名文档。

函数功能#

代码虚拟化#

代码虚拟化,将Java字节码从Java方法中抽离,替换为一个对Native代码的调用,抽离的Java字节码被转换成自定义的虚拟机代码,调用本地代码就是调用自定义的虚拟机执行这些字节码,无论是静态文件还是运行时内存中,永远不会有原始字节码的暴露。

原程序反编译:

保护后反编译:

SDK标签保护#

java sdk标签支持代码虚拟化保护方式,但SDK标签本身并不包含加解密或者保护的功能,而是以特征的方式标记代码位置。使用Virbox Protector对程序保护时才真正对标记的代码等进行保护。

函数标签#

代码中设置VBVirtualize注解,并在函数上引用,程序编译成功后,将编译好的程序拖入到加壳工具界面,界面会显示代码中设置的函数保护方式:

1.新建VBVirtualize.java,代码中设置VBVirtualize注解,内容参考如下:

package virbox;
public @interface VBVirtualize{}

2.在java代码中导入virbox.VBVirtualize,并在类或方法上面添加@VBVirtualize,内容参考如下:

import virbox.VBVirtualize;
@VBVirtualize //可添加到类上面,所有的方法都会默认保护public class Main {    public static void main(String[] args) {        System.out.println("hello");         test_vir();    }
@VBVirtualize //可添加到方法上面,只保护该方法    public static void test_vir()    {        System.out.println("test_vir");    }}

3.代码中添加标签后,程序进行编译,将编译好的程序拖入到加壳工具界面,界面会显示代码中设置的函数保护方式;

4.点击保护选中项目,保护成功后默认生成ssp配置文件和在protected文件夹下生成加密后的jar包。

保护指引#

Virbox Protector Java VME版可使用界面或命令行方式保护Java文件,以下介绍界面操作和命令行操作保护java文件的流程,二者选其一即可。

界面操作#

添加文件#

将待保护的 jar/war 包直接拖入到工具中;

函数设置#

在函数选项处,点击添加函数,选择需要保护的函数,设置保护方式为虚拟化,点击确定将选择的函数添加到函数列表中。

加密选项#

1.输出信息:可自定义设置加密后生成的文件存储的目录及命名,默认会自动生成在protected文件夹下;

2.加密选项:包括字符串加密、调试器检测和文件校验功能;

3.运行平台:运行平台可以根据自己需求选择。

保护项目#

点击保护选中项目,保护成功后默认生成ssp配置文件和在protected文件夹下生成加密后的jar包。

命令行操作#

命令行工具#

Virbox Protector 支持命令行选项,可以指定基础保护选项和函数选项,方便自动化集成。

命令行工具 virboxprotector_con 的默认路径位于:

Windows:C:\Program Files\senseshield\Virbox Protector 3\binLinux:/usr/share/virboxprotector/binmacOS:/Applications/Virbox Protector 3.app/Contents/MacOS/bin

命令行选项#

使用命令行工具virboxprotector_con --help=java-bce可以查看java bce保护时的参数,如图所示:

参数介绍

选项命令行默认选项
虚拟化的方法-v <method_list>随机
过滤不虚拟化的方法-ev <method_list>随机
字符串加密--str-enc=0
调试器检测--detect-dbg=0
文件校验--file-check=0
运行平台--platforms=<platform_list>所有平台
过滤不支持的方法--ignore-unsupported=随机
输出路径-o <output_path>0

其中指定运行平台可以用 --platforms= 选项,举例如下:

指定Windows平台:

--platforms="windows-x86"

指定Windows和Linux双平台:

--platforms="windows-x86;linux-x86;linux-arm"

命令行保护示例#

java vme方式对保护test1和test2的所有方法

virboxprotector_con <jar_path> -v "com.example.test1.*;com.example.test2.*" -o <output_path>

对test1的所有方法进行保护,并开启字符串加密、调试器检测和文件校验选项

virboxprotector_con <jar_path> -v "com.example.test1.*" --ignore-unsupported=1 --str-enc=1 --detect-dbg=1 --file-check=1 -o <output_path>

若命令行里指定方法较多,可以使用Virbox Protector工具在界面上先选择好函数,然后保存选中配置后会在被保护的程序所在目录会生成.ssp配置文件,然后调用virboxprotector_con进行保护

1. 若ssp和jar_path在同一目录下时,保护时默认查找.ssp里的配置文件,命令参考如下:virboxprotector_con <jar_path> -o <output_path>2. 若ssp和jar_path不在同一目录下时,保护时可以指定.ssp配置文件,命令参考如下:virboxprotector_con <jar_path> -x <jar_path.ssp> -o <output_path>

问题#

如何判断macOS系统上java是什么架构#

判断电脑上java环境是x64架构还是arm64架构,如果两个都存在的话⼀般 执⾏是java默认为x64架构,命令参考如下:

查看java位置命令:which java查看java⽂件类型:file /usr/bin/java

如何手动对jar包里loader库进行签名#

适用场景#

保护环境:只在windows或Linux系统上保护

运行java架构:macOS arm架构java

运行系统:macOS arm64架构系统

问题现象#

1.若电脑上的java只为arm64架构,如图所示:

image-20240913161406404

2.若java为macOS arm架构,且加固时不签名,则直接运⾏保护后的jar包;

3.出现以下错误,如图所⽰:

1)由于mach-O arm64架构的程序涉及到签名问题,故程序⽆法运⾏,提⽰"not valid  for use in process using Library Validation: Trying to load an  unsigned library"的错误;2)所以在程序进⾏修改后需要重新对其签名。

解决方案#

需要对保护后jar包文件里的loader_macho_a64.dylib进行签名。

1.解压保护后的jar到指定⽬录( 假设解压⽬录名为demo_new),找到loader_macho_a64.dylib库的位置,查看该库是否签名,参考命令如下:

1)可直接解压demo.jar或使⽤命令"unzip demo.jar -d ./demo_new" 2)进⼊demo_new⽬录下,loader_macho_a64.dylib 3)验证loader_macho_a64.dylib是否签名:codesign -v loader_macho_a64.dylib

2.若⽂件未签名,将提⽰code object is not signed at all In architecture: arm64,如图所示:

3.对loader_macho_a64.dylib进行签名,操作步骤参考如下:

1)查看证书信息:security find-identity -v -p codesigning2)签名:codesign -fs <证书ID> loader_macho_a64.dylib3)再使⽤“codesign -v loader_macho_a64.dylib”验证签名是否成功,若成功打印信息会显⽰为空。

4.将签名成功后loader_macho_a64.dylib重新打包到demo.jar包里,参考命令如下:

1)进⼊到解压的demo_new⽬录下2)执⾏命令:jar -cfM0 <jar包名称> ./*   例如:jar -cfM0 demo_new.jar ./*3)将重新命名的demo_new.jar拷⻉到demo.ssp.jar⽬录下4)未签名的demo.ssp.jar包可删除,签名后的demo_new.jar保留(名字可随意修改),进⾏替换。

5.再次执⾏jar包,则程序可运⾏成功。

VME⽅式和BCE⽅式如何共⽤#

答:必须先进⾏VME⽅式保护,在使⽤BCE⽅式保护。