中文 English
mjar-java 是 mjar 的 Java 侧配套项目,主要用于对 JAR / WAR 中的 class 文件进行加密与字节码修改,并通过 libmjar 原生库完成实际加密。
本项目需要配合 mjar 一起使用。
加密无法提供绝对安全,但可以显著提高静态分析和逆向工程的成本。
Mjarencrypt4 的入口用法在 main 中:
java -jar mjar.jar <pkg_prefix> <source_jar_or_war> [DEBUG]参数说明:
pkg_prefix:包前缀,点分形式,例如com.github.jsbxyyx
程序内部会转换成com/github/jsbxyyxsource_jar_or_war:源 JAR 或 WAR 路径DEBUG(可选):打开调试输出
输出文件名规则:
- 输入
app.jar→ 输出app-enc.jar - 输入
app.war→ 输出app-enc.war
示例:
java -jar mjar.jar com.github.jsbxyyx app.jar控制台会打印类似树状结构(printTree):
Processing: app.jar
/
/├── [A] BOOT-INF/lib/...
├── [C] com/github/jsbxyyx/service/MyService.class [E][P]
...
>>> Encryption Complete: /path/to/app-enc.jar
标记含义:
[A]:archive(嵌套 JAR/WAR)[C]:class 文件[E]:会被加密[P]:会被打补丁(插入maybeDecrypt等逻辑)
包名统一为 com.github.jsbxyyx.mjar:
-
Mjarencrypt
Java 封装的原生加密器:- 定义
public native byte[] encrypt(byte[] bArr); - 根据
os.name判断当前系统:- Windows:
libmjar.dll - macOS:
libmjar.dylib - 其他:
libmjar.so
- Windows:
- 从以下路径加载原生库:
- 系统属性
LIB_MJAR_PATH;如果未设置, - 使用
user.dir(当前工作目录)
- 系统属性
- 定义
-
Mjarencrypt2
基于 ASM 的 JAR 转换工具,逻辑概括如下:- 读取目标 JAR,解析
Manifest(main-class/start-class) - 判断是否为 Spring Boot fat jar(根据 main class 包名)
- 遍历所有 Entry,将内容读入
Map<String, byte[]> - 对指定包前缀下的
.class使用Mjarencrypt.encrypt进行加密- 某些类(加载器、补丁类、
META-INF下资源等)会被忽略 (IGNORE_ENCRYPT_CLASS)
- 某些类(加载器、补丁类、
- 将处理后的类写回临时目录
- 使用原始
Manifest重新打包为*-enc.jar - 删除临时解压目录
- 读取目标 JAR,解析
-
Mjarencrypt3
一个简单的命令行测试工具,用于测试原生加密接口:java -cp mjar.jar com.github.jsbxyyx.mjar.Mjarencrypt3 <string>
会把
<string>使用 UTF‑8 转成 byte 数组,加密后以 16 进制形式打印。 -
Mjarencrypt4
新版递归式转换器,支持 JAR、WAR 及内部嵌套的 archive,具备:- 树形结构输出(标记哪些是 archive、哪些是 class、是否加密/打补丁)
- 通过 ASM 根据规则对 class 进行加密或插桩
- 最终生成
-enc.jar或-enc.war文件
典型 Maven 构建:
mvn clean package或者 Gradle:
./gradlew build构建产物通常位于 target/ 或 build/libs/ 目录(视构建脚本而定)。
java -cp mjar.jar com.github.jsbxyyx.mjar.Mjarencrypt3 <string><string>:任意要加密的字符串- 输出:加密后字节的 16 进制字符串
在 Mjarencrypt2.run 中定义的用法:
usage: java -jar mjar.jar com/github/jsbxyyx xx.jar [DEBUG]
对应参数:
args[0]:包前缀(内部路径形式),例如:com/github/jsbxyyx
args[1]:待加密的 JAR 文件路径,例如app.jarargs[2]:可选,DEBUG(大小写不敏感)启用调试输出
执行流程:
- 输出参数信息:
args : [com/github/jsbxyyx, app.jar, DEBUG] - 读取目标 JAR 的
Manifest:main-classstart-class
- 判断是否为 Spring Boot 应用:
- 通过
main-class包名前缀是否为org.springframework.boot等
- 通过
- 调用
parseJar:- 遍历所有
JarEntry - 对 Spring Boot 的
BOOT-INF/classes/、BOOT-INF/lib/做路径归一化
- 遍历所有
- 对在目标包前缀下的
.class执行加密(Mjarencrypt.encrypt) - 调用
writeClass把处理后的类写入临时目录 - 调用
writeJar重新打包为*-enc.jar - 调用
clean递归删除临时目录
控制台示例输出(简化):
main-class : ...
start-class : ...
springboot : true/false
writeJar : /path/to/app-enc.jar
clean : /path/to/app
final filename : /path/to/app-enc.jar
- 使用 ASM:
ClassReader/ClassWriter/ClassVisitor/MethodVisitor- 在指定 class 中插入
maybeDecrypt([BI)[B方法调用或其它逻辑
- 加密逻辑:
- 所有需要加密的字节数组交给
Mjarencrypt.encrypt处理 Mjarencrypt底层依赖libmjar原生库完成实际加密
- 所有需要加密的字节数组交给
- Spring Boot 特殊处理:
- 解析
BOOT-INF/classes/和BOOT-INF/lib/下的内容 - 在重新打包时保留原始
Manifest与结构
- 解析
可重点参考:
IGNORE_ENCRYPT_CLASS中列出的类不会被加密,以保证运行时解密与启动流程正常。- 某些框架/库大量使用反射、运行时生成字节码时,可能需要:
- 调整包前缀
- 将特定 class 排除在加密之外
- 密钥管理请放在 native / 外部配置中,不要直接硬编码在 Java 源码或公开仓库中。
如仓库中存在 LICENSE 文件,请以该文件为准。
- mjar —— 原生加密与运行时加载的主项目。