傳統 Java 混淆器(ProGuard、yGuard 等)工作於編譯後的 bytecode 階段,面臨三大痛點:
Java 混淆編譯器 (JOC) 打破傳統模式:直接在 javac 編譯器內部修改代碼生成階段,實現「編譯即混淆」單一步驟,並引入源碼級 @preserve 註解精準控制符號保留。
Java Source (.java)
│
▼
┌─────────────────────────────────────┐
│ Modified Javac Compiler │
│ ┌──────────────┐ ┌──────────────┐ │
│ │ 前端解析 │──▶│ 符號表構建 │ │
│ └──────────────┘ └──────────────┘ │
│ │ │
│ ▼ │
│ ┌──────────────────┐ │
│ │ 混淆邏輯注入點 │◀── @preserve 註解解析
│ │ (符號重命名/打亂) │ │
│ └──────────────────┘ │
│ │ │
│ ▼ │
│ ┌──────────────┐ ┌──────────────┐ │
│ │ 後端代碼生成 │──▶│ .class 輸出 │ │
│ └──────────────┘ └──────────────┘ │
└─────────────────────────────────────┘
javac -Xobfuscate ... 直接產出混淆後 class@preserve 註解內嵌於 JavaDoc,無需外部配置檔下載 joc.jar,執行 java -jar joc.jar 啟動。參數與 javac 完全相容,新增 -Xobfuscate:
| 參數 | 混淆範圍 | 適用場景 |
|---|---|---|
-Xobfuscate:none | 不混淆 | 除錯/對照基準 |
-Xobfuscate:private | 所有 private 成員 | 內部實現細節保護 |
-Xobfuscate:package | private + package-private | 預設推薦,平衡保護與擴展 |
-Xobfuscate:protected | private + package + protected | 繼承體系內部保護 |
-Xobfuscate:public / :all | 所有成員(含 public) | 極高安全需求,需配合 @preserve 保留 API |
注意:若使用 -Xobfuscate 不帶等級,等同 -Xobfuscate:package。
/**
* 核心業務介面,必須保留完整符號供外部呼叫
* @preserve public 保留所有 public/protected/package 成員
*/
public class PaymentService { ... }
public class User {
/** @preserve */ private String id; // 保留此欄位
/** 普通私有欄位,將被混淆為 _$1 等 */ private String tempCache;
/** @preserve */ public void login() {} // 保留公開方法
private void encryptPassword() {} // 將被混淆
}
| 註解 | 效果 |
|---|---|
@preserve | 僅保留類別名,成員依命令列等級決定 |
@preserve public | 保留所有 public 成員 |
@preserve protected | 保留 public + protected |
@preserve package | 保留 public + protected + package-private |
@preserve private / @preserve all | 保留所有成員(含 private) |
public class AboutBox extends JDialog {
JPanel panel1 = new JPanel();
JButton button1 = new JButton();
JLabel jLabel2 = new JLabel();
JTextArea jTextArea1 = new JTextArea();
private void initForm() { ... }
private void button1_actionPerformed(ActionEvent ev) { dispose(); }
}
public class AboutBox extends JDialog {
JPanel panel1; JButton button1; JLabel jLabel2; JTextArea jTextArea1;
private void initForm() { ... }
private void button1_actionPerformed(ActionEvent ev) { dispose(); }
}
public class AboutBox extends JDialog {
JPanel _$1; JButton _$2; JLabel _$3; JTextArea _$4;
public AboutBox() {
_$1 = new JPanel(); _$2 = new JButton(); _$3 = new JLabel(); _$4 = new JTextArea();
_$1(); // initForm 被重命名
}
private void _$1() { // initForm
2; this; JVM INSTR swap; setDefaultCloseOperation(); // 指令序列化特徵明顯
...
_$2.addActionListener(new IIlIlIIIIlllIIII(this)); // 匿名類別名混淆
}
private void _$1(ActionEvent actionevent) { dispose(); } // 事件處理方法
// 合成存取方法
static void Access$0(AboutBox aboutbox, ActionEvent actionevent) { ... }
// 匿名內部類別
final class IIlIlIIIIlllIIII implements ActionListener { ... }
}
JVM INSTR swap 等底層指令,增加閱讀難度Access$0 等存取方法仍可見,屬 Java 語言規範限制Class.forName() 字串參數需手動 @preserve 類別名javac 任務為 joc-Xobfuscate:package + 類別 @preserve public-Xobfuscate:private 或 :protected-Xobfuscate:all + 主類別 @preserveJOC 開創了「源碼級混淆編譯」新範式,以編譯器內建方式解決傳統工具的流程複雜、配置沉重、風險不可控三大難題。雖受限於不支援分別編譯與 JDK 版本綁定,但在對安全性要求極高、程式碼基礎相對穩定的專案(如授權機制、核心演算法、嵌入式 Java)中,具有不可替代的價值。現代專案亦可參考其 @preserve 註解設計思想,結合 ProGuard/R8 等主流工具,建立「源碼標記 + 建置階段混淆」的輕量化保護體系。