一次XJar加密SprintBoot+自有验证破解


XJar加密 + SprintBoot + 自有 API Token 验证破解

结构分析

目标服务采用 docker 容器化部署,入口点命令为。

/xjar java -jar /app.jar

JAR 分析

可以看到,除了 Spring 的 Bootloader 和静态资源都被主角 XJar 加密了,但好在 XJar 加密的过程完整开源,方便我们进行逆向分析。

XJar

https://github.com/core-lib/xjar

支持原生JAR,基于对包内资源加密及拓展 ClassLoader ,以此构建一套程序加密启动、动态解密运行的方案。技术非常值得学习,但本质上不能避免源码泄露以及反编译。

特性

  • 无代码侵入,只需要把编译好的JAR包通过工具加密即可.

  • 完全内存解密,降低源码以及字节码泄露或反编译的风险.

  • 支持所有JDK内置加解密算法。

  • 可选择需要加解密的字节码或其他资源文件。

  • 支持Maven插件, 加密更加便捷。

  • 动态生成 Go 启动器,保护密码不泄露。

审查 XJar 源码

XJar 生成加密的 JAR 后,只需要一个 xjar 二进制文件作为启动器。其源码位于 xjar/src/main/resources/xjar/xjar.go 中。这里主要是将加密参数拼接起来,向 Java 传入。

侧信道攻击

package main

import (
	"bufio"
	"fmt"
	"os"
)

func main() {
	input := bufio.NewScanner(os.Stdin) // 初始化扫描对象
	for input.Scan() {                  // 扫描输入内容
		line := input.Text()           // 转换为字符串
		fmt.Println(line)              // 输出到标准输出
	}
}

在 XJar 的加密原理背景下,每个 JAR 的加密参数不同,解密数据位于启动器中。虽然其有加密,但不妨碍我们用伪造的后继程序骗出加密参数。

JAR 包解密

package app;

import io.xjar.XCryptos;
import io.xjar.XEntryFilter;
import io.xjar.XKit;
import io.xjar.boot.XBoot;
import io.xjar.jar.XJar;
import io.xjar.key.XKey;
import org.apache.commons.compress.archivers.jar.JarArchiveEntry;

import java.security.NoSuchAlgorithmException;

public class run {
    public static void main(String[] args) {
        String password = "密码";
        XKey xKey;
        {
            try {
                xKey = XKit.key(password);
            } catch (NoSuchAlgorithmException e) {
                throw new RuntimeException(e);
            }
            try {
                XCryptos.decryption().from("C:/Users/sfc9982/Desktop/app.jar")
                        .use("密码")
                        .exclude("/static/**/*")
                        .to("C:/Users/sfc9982/Desktop/app-decrypt.jar");
//                XBoot.decrypt("C:/Users/sfc9982/Desktop/app.jar", "C:/Users/sfc9982/Desktop/app-decrypt.jar", xKey);
//                XJar.encrypt("C:/Users/sfc9982/Desktop/app-decrypt.jar", "C:/Users/sfc9982/Desktop/app-reenc.jar", xKey);

            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
    }
}

这里 OOP 的味道很浓,解密用到的方法都可以在相关的 Class 中找到。成功运行后,就得到未加密的原始 JAR 文件了。

Java 项目逆向

逆向工具使用 JADX 或者 JD-GUI。

业务代码逻辑比较清晰,这里我的目标主要是绕过一个验证服务,使自己获得高级授期。

代码

这里我们投机取巧,将 this.authUrl 改为一个非法值,使其丢出 Exception。然后修改最后 reutrn 回去的 JSON,加入激活信息。

激活信息的格式可以观察校验逻辑和利用原有验证 API 得到。

结果

成功激活!

Summary

条条大路通罗马,有些看起来逆天,但是比较短。


文章作者: sfc9982
版权声明: 本博客所有文章除特別声明外,均采用 CC BY-NC-ND 4.0 许可协议。转载请注明来源 sfc9982 !
  目录