首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java 類別加密保護實戰:自訂 ClassLoader 結合 DES 對稱加密完整實作

     編輯:Java 相關知識

Java 類別檔案易被反編譯的根本原因

Java 編譯產生的 .class 位元碼保留豐富元資料,標準類別載入器公開讀取,配合反編譯器 (JAD, CFR, Fernflower) 輕易還原源碼。自訂 ClassLoader 可在載入管道植入解密邏輯,實現原始碼保護。

類別載入器工作流程與切入點

1. findClass() / loadClass() → 定位類別資料來源
2. 讀取位元碼資料 (byte[])
3. defineClass(name, bytes, 0, bytes.length) → 交給 JVM 定義類別
// 切入點:步驟 2 與 3 之間進行解密

完整實作三步驟

步驟 1:產生 DES 金鑰

package com.neusoft.jiami;
import javax.crypto.*;
import java.io.*;
import java.security.SecureRandom;

public class KeyGenerator {
    public static void main(String[] args) throws Exception {
        SecureRandom sr = new SecureRandom();
        KeyGenerator kg = KeyGenerator.getInstance("DES");
        kg.init(sr);
        SecretKey key = kg.generateKey();
        byte[] raw = key.getEncoded();
        try (FileOutputStream fos = new FileOutputStream("key.dat")) {
            fos.write(raw);
        }
        System.out.println("Key saved to key.dat");
    }
}

步驟 2:加密目標類別檔案

package com.neusoft.jiami;
import javax.crypto.*;
import java.io.*;
import java.security.spec.DESKeySpec;

public class ClassEncryptor {
    public static void main(String[] args) throws Exception {
        // 讀取金鑰
        byte[] raw = readFile("key.dat");
        DESKeySpec dks = new DESKeySpec(raw);
        SecretKey key = SecretKeyFactory.getInstance("DES").generateSecret(dks);
        
        // 初始化加密器
        Cipher cipher = Cipher.getInstance("DES");
        SecureRandom sr = new SecureRandom();
        cipher.init(Cipher.ENCRYPT_MODE, key, sr);
        
        // 讀取並加密類別檔
        byte[] classBytes = readFile("DigestPass.class");
        byte[] encrypted = cipher.doFinal(classBytes);
        
        // 覆寫原檔 (部署時分發加密後的 .class)
        writeFile("DigestPass.class", encrypted);
        System.out.println("Class encrypted.");
    }
    
    static byte[] readFile(String path) throws IOException {
        try (FileInputStream fis = new FileInputStream(path)) {
            byte[] buf = new byte[fis.available()];
            fis.read(buf);
            return buf;
        }
    }
    static void writeFile(String path, byte[] data) throws IOException {
        try (FileOutputStream fos = new FileOutputStream(path)) { fos.write(data); }
    }
}

步驟 3:自訂 ClassLoader 解密載入

package com.neusoft.classloader;
import javax.crypto.*;
import java.io.*;
import java.security.spec.DESKeySpec;

public class MyClassLoader extends ClassLoader {
    private final String classPath;
    private final SecretKey key;
    private final Cipher cipher;

    public MyClassLoader(String classPath) throws Exception {
        this.classPath = classPath;
        byte[] raw = readFile(classPath + "key.dat");
        DESKeySpec dks = new DESKeySpec(raw);
        this.key = SecretKeyFactory.getInstance("DES").generateSecret(dks);
        this.cipher = Cipher.getInstance("DES");
        this.cipher.init(Cipher.DECRYPT_MODE, key, new SecureRandom());
    }

    @Override
    protected Class findClass(String name) throws ClassNotFoundException {
        try {
            // 1. 讀取加密位元碼
            String path = classPath + name.replace('.', '/') + ".class";
            byte[] encrypted = readFile(path);
            
            // 2. 解密
            byte[] decrypted = cipher.doFinal(encrypted);
            
            // 3. 定義類別
            return defineClass(name, decrypted, 0, decrypted.length);
        } catch (Exception e) {
            throw new ClassNotFoundException(name, e);
        }
    }
    
    private byte[] readFile(String path) throws IOException {
        try (FileInputStream fis = new FileInputStream(path)) {
            byte[] buf = new byte[fis.available()];
            fis.read(buf);
            return buf;
        }
    }
}

// 使用範例
public class App {
    public static void main(String[] args) throws Exception {
        MyClassLoader cl = new MyClassLoader("E:/classes/");
        Class c = cl.loadClass("com.neusoft.jiami.DigestPass");
        Object instance = c.getDeclaredConstructor().newInstance();
        // 使用 instance...
    }
}

安全性分析與強化方向

弱點風險強化對策
金鑰檔案外洩完全破解金鑰內建於載入器原生代碼 (JNI)、硬體安全模組 (HSM)、白盒加密
JVM 記憶體傾印解密後位元碼可被提取運行時加密 (JVMTI Agent)、記憶體保護、混淆器配合
自訂載入器被替換繞過解密邏輯載入器簽名驗證、啟動類別鏈完整性檢查
DES 演算法脆弱暴力破解可行升級 AES-256、ChaCha20、國密 SM4
單一金鑰全專案通用一把鑰匙開所有鎖每類別/模組獨立金鑰、金鑰分級派生

生產級保護方案建議

  1. 分層防護:ProGuard/R8 混淆 + 字串加密 + 控制流扁平化 + 自訂 ClassLoader 加密。
  2. 原生載入器:核心解密邏輯移至 JNI/.so,提高逆向難度。
  3. 完整性驗證:啟動時校驗關鍵類別雜湊,偵測竄改。
  4. 授權綁定:解密金鑰衍生自裝置指紋/授權檔,防止檔案複製部署。
  5. 商業方案:考慮 DexGuard (Android)、Zelix KlassMaster、Stringer Java Obfuscator 等成熟工具。

法律與合規提醒

  • 加密保護屬技術保護措施,受數位千禧年法案 (DMCA) 等法律保障。
  • 開源專案需確認授權條款允許加密分發。
  • 部分國家對加密軟體匯出有管制規定。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved