C/C++ 靠加殼(加密 + 專用載入器解密)保護二進制,Java 因 Class 格式規範、反編譯工具成熟,傳統加殼被視為不可能。但 Java 動態類載入機制與字節碼操作庫,實則提供了實現「Java 版加殼」的技術路徑。
核心思路:
.class 檔案進行對稱加密(AES/DES)或自定義變換。URLClassLoader,覆寫 findClass(String name):public class EncryptedClassLoader extends URLClassLoader {
private final SecretKey key;
public EncryptedClassLoader(URL[] urls, SecretKey key) {
super(urls);
this.key = key;
}
@Override
protected Class> findClass(String name) throws ClassNotFoundException {
// 1. 定位加密資源流
// 2. 解密位元組陣列
// 3. defineClass(name, decryptedBytes, 0, decryptedBytes.length);
}
}
弱點:解密邏輯、密鑰管理代碼本身暴露在啟動路徑上,經反編譯即可還原解密算法。需配合原生代碼(JNI)將關鍵邏輯移出 JVM,提高逆向難度。
Javassist(由東京工業大學 Chiba Shigeru 創建,現屬 JBoss 專案)提供高層級字節碼操作 API:
// 範例:為所有 setter 注入審計日誌
ClassPool pool = ClassPool.getDefault();
CtClass cc = pool.get("com.example.User");
for (CtMethod m : cc.getDeclaredMethods()) {
if (m.getName().startsWith("set")) {
m.insertBefore("{ System.out.println(\"Audit: setting \" + $1); }");
}
}
byte[] modified = cc.toBytecode();
// 寫入加密存儲或直接 defineClass
結合加密存儲:構建工具階段用 Javassist 將業務類「編織」加密邏輯、剝離符號資訊、甚至將關鍵算法拆分為動態生成的匿名類,最終產出高度混淆、結構破碎的字節碼集合。運行時由自定義 ClassLoader 解密、定義、執行。
| 維度 | URLClassLoader 方案 | Javassist 深度編織 |
|---|---|---|
| 實現難度 | 中 | 高 |
| 抗逆向強度 | 低(解密器暴露) | 高(結構破壞+邏輯分散) |
| 運行效能影響 | 啟動期一次性解密 | 類載入期字節碼轉換開銷 |
| 相容性風險 | 低 | 中(可能觸發 JVM 驗證器拒絕) |
結論:Java 確可實現類加殼效果,但無法達到原生代碼級別的絕對保護。工程上建議:
「授人以魚不如授人以漁」,理解類載入機制與字節碼模型,才是應對代碼保護挑戰的根本之道。