四、 系統實作暨測試
4.1 系統實作
4.1.4 系統套件的考量
如同在 3.5 小節所述,Java 擁有豐富的類別庫支援,可以說實用的程式一定 會使用到系統的類別庫。在此需考量的問題是這些預設/延伸套件須要加以混淆 嗎?還是保留原有的類別檔?整體概念如圖 4.5 所示。
圖 4.5 套件圖解析 關於這個議題,亦有兩種實作方式:
1. 系統套件亦予以混淆:
如同要保護的程式,亦將系統預設/延伸套件予以混淆,然而如此做之後將具 有如下缺點:
因為 1.具有上述缺點,因此,建議採用第二種方式。然而,在實作的時候必
if(thisMethod->ofClass->clazz.packageName ==NULL){
//anonymous package 進行反轉換並載入至記憶體 }else{
if(strstr(thisMethod->ofClass->clazz.packageName->string, JAVA) !=
NULL || strstr(thisMethod->ofClass->clazz.packageName->string, JAVAX) !=
NULL){
packageName:指向存有 packageName 的結構的指標 string:真正儲存的字串內容
4.1.5 變換運算元(Change operand)
在 3.4 節圖 3.9 的轉換器演算法之中有一個「Change Operand」的項目,此 項目的功能很簡單,判斷此道指令是否需要變換 operand,如果是,則依轉換規 格進行轉換,如果不需要則不作任何處理。
設計此功能具有幾項優點:
1. 可以改變分支指令的 offset,讓反編譯器、攻擊者弄不清那裡是分支指 令的跳躍目的地,例如:
goto 2 → goto 18 將會使反編譯器、攻擊者弄錯真正的跳躍目的地。
2. 對一些 operand 代表常數池索引(index)的指令而言,此方式可以讓反編 譯器、攻擊者誤用常數池之中的項目,例如:
getstatic 10 → getstatic 20 將會使人誤以為是使用常數池中第 20 個項目。
整體的設計概念可以圖 4.6 表示:
圖 4.6 Change operand 示意圖
其中轉換函數代表使用者可自由選定的數學函數
f ( ) x 及f
−1( ) x
,分別安插在 TS及 RTS之中,而 x 則置於轉換規格之中。當 TS有需要轉換 operand 之時依轉換 規格取出 x 再計算 f( )
x ,而後即以 f( )
x 之值做為新的 operand,RTS的建構原理 亦同,不再贅述。4. 記憶體:256MB
5. 編譯器:Sun j2sdk1.4.2_03 版、Visual C++ 6.0
為了測試本論文所提「以定性的有限狀態機為基礎的 Java 程式混淆」之效 果,於網路上取得各家發表的反編譯器進行測試,由於可取得的反編器過多(超過 20 套),因此僅挑選其中具有代表性、使用不同反編譯引擎者加以測試,挑選後 結果如表 4.2 所示。
表 4.6 測試用反編譯器列表
開發程式語言 版本 說明
Mocha[4] Java Beta 1 第一個 Java 反編譯器 SourceTec
Decompiler[33] Java 1.10 Jasmin Java Decompiler A patch of Mocha Jad[14] Win32 1.5.8e 有數個反編譯器使其引擎
作為建構基礎 JReversePro[34] Java 1.4.1
JODE[35] Java 1.1.2-pre1 有數個反編譯器使用其引 擎作為建構基礎
Dava Decompiler[25] Java 2.1.0 Soot framework 2.1.0 ClassSpy[36] Java 2.0
JAscii[37] Java 1.0.20 Evaluation version
4.2.1 測試範例一
測試程式:3.3.5 節中的表 3.6 轉換規格:3.3.5 節中的表 3.9 表格符號:
項 目 名 稱
X:無法產生.java 檔,或是產生了程式碼卻不完整或是無法重新編譯
○:表示混淆後,反編譯成功,重新編譯成功,執行不正確
☆:表示混淆後,反編譯成功,重新編譯成功,執行正確 表 4.7 範例一測試結果
反 編 譯 器 名 稱 使 用 原 始 碼
使 用 本 法
混 淆 後 說 明
Mocha X X 版本老舊,無法辦識新版類別檔
SourceTec
Decompiler X X 版本老舊,無法辦識新版類別檔
Jad ☆ X
JReversePro ☆ X
JODE ☆ X
Dava Decompiler ☆ X ClassSpy ☆ X
JAscii ☆ X
4.2.2 測試範例二 測試程式:附錄二 轉換規格:附錄二
表 4.8 範例二測試結果
反 編 譯 器 名 稱 使 用 原 始 碼
使 用 本 法
混 淆 後 說 明
Mocha X X 版本老舊,無法辦識新版類別檔
SourceTec
Decompiler X X 版本老舊,無法辦識新版類別檔
Jad ☆ X
JReversePro ☆ X
JODE ☆ X
Dava Decompiler ☆ X
ClassSpy ☆ X
JAscii ☆ X
4.3 轉換規格之選擇考量
了解了相關元件建構上的考量後,接著探討一下在選擇一個轉換規格的時 候,有什麼是值得我們加以注意的,以下分述之。
1. 在選擇「需混淆的指令」時,應考慮這道指令出現的頻率,在 202 個 opcode 之中,其實有些 opcode 出現的頻率非常低,建議可以適當地選擇幾個,不用 多選。
2. 在選擇轉換規格之時,可以先分析一下原始程式編譯後的類別檔,針對最重 要的部分予以最高度的混淆。
3. 此外,將分支指令變成非分支指令則流程會改變,反之亦然。
4. 改變分支指令的 operand,則其 offset 改變。
5. 對於參考到常數池的指令而言,改變其 operand 將會造成常數池的誤用。
當然,上述五點只是一個簡單的摘要,有興趣的讀者可以自行研究、探討。
4.4 應用方向
本論文所提出的「DFA-Based Obfuscation」在應用上適合使用於以下情況:
當應用程式內含高價值的演算法或是不欲人知的機密,卻又擔心現有技術保護能 力不足,則可搭配各種技術促成「多重防禦」之保護方式,讓反編譯的層級涵蓋 原生語言,大幅增加反編譯難度並限制使用對象,沒有獲得相對應虛擬機器的人 即使獲得了該程式也無法執行。
此外,當有需要時,亦可以建構一個能同時執行混淆過及未曾混淆過程式的 系統,如下圖所示。舉例而言,數位電視之中亦使用了 JVM,在此,系統廠所開 發的應用/系統程式可以保護模式執行,而使用者後續加入的應用程式可以一般模 式執行。
圖 4.7 應用方式─多執行模式系統
五 、 結 論 與 未 來 展 望
5.1 結論
軟 體 保 護 與 反 編 譯 /反 組 譯 就 像 早 年 美 蘇 雙 方 的 軍 備 競 賽 一 般,這 場 較 競 會 持 續 到 何 時 沒 人 知 曉 , 亦 無 法 判 斷 誰 將 獲 得 最 後 的 勝 利 。 處 於 現 今 這 個 年 代 , 或 許 我 們 所 能 做 的 只 有 防 護 再 防 護 , 避 免 他 人 惡 意 侵 害 智 慧 財 產 權 。
本 研 究 提 出 的 「 以 定 性 的 有 限 狀 態 機 為 基 礎 的 Java 程 式 混 淆 」 , 是 從 既 有 保 護 技 術 的 「 互 補 」 層 面 來 看 待 整 個 保 護 系 統 , 最 主 要 的 優 點 在 於 結 合 既 有 的 保 護 技 術 提 昇 整 體 保 護 效 果 。
5.2 未來展望
當 反 編 譯 的 工 具 、 相 關 知 識 越 來 越 容 易 取 得 、 學 習 之 際 , 混 淆 技 術 所 擔 負 的 責 任 就 相 形 加 重 。 未 來 , 如 何 增 加 軟 體 反 編 譯 的 難 度 仍 有 賴 於 相 關 人 員 的 研 究 。 此 外 , 由 於 智 慧 財 產 相 關 法 規 規 定 權 利 人 需 自 行 舉 證 以 證 明 他 人 確 有 侵 害 本 身 權 利 , 故 軟 體 浮 水 印 (Software Watermarking) 的 重 要 性 將 與 日 俱 增 , 亦 是 值 得 加 以 研 究 的 領 域 。 最 後 , 法 律 、 道 德 上 的 防 範 更 是 值 得 加 強 的 重 點 , 如 此 才 能 全 面 、 有 效 地 防 止 他 人 惡 意 反 編 譯 、 竊 取 機 密 進 而 保 護 自 身 的 智 慧 財 產 權 。
參考文獻
[1] Tim Lindholm, Frank Yellin, “The JavaTM Virtual Machine Specification" Second Edition, Addison Wesley, 1999
[2] Meyer, Downing, “Java Virtual Machine", O'REILLY, 1997
[3] Bill Venners. “Inside the Java 2 virtual machine", McGraw-Hill, 1999.
[4] Mocha, the Java Decompiler,
http://www.brouhaha.com/~eric/computers/mocha.html
[5] Rachel Greenstadt, “Virtual Machine Technology Alone Cannot Stop Software Piracy".
[6] Collberg, Christian, Clark Thomborson and Douglas Low. “A taxonomy of obfuscating transformations", Technical Report 148, Department of Computer Science, University of Auckland, New Zealand, July, 1997.
http://www.cs.auckland.ac.nz/~collberg/Research/Publications/Collb ergThomborsonLow97a/index.html
[7] Jien-Tsai Chan and W. Yang, " Advanced obfuscation techniques for Java bytecode", Journal of Systems and Software, July 2002. (NSC 89-2213-E-009-146 and NSC 90-2213-E-009-142).
[8] Bill Joy, Guy Steele, Jar Gosling, Gilad Bracha, “The Java Language Specification", Second Edition, Addison Wesley, 2000
[9] Mikhail Sosonkin, Gleb Naumovich and Nasir Menmon, “Obfuscation of
[12]蔡明修,「使用反反編譯混淆法設計與實作 Java 抗加入式浮水印產生器」,
國立成功大學,碩士論文,民國九十二年。
[13]Java Obfuscator: Zelix Klass Master, http://www.zelix.com
[14]Jad - the fast Java Decompiler, http://kpdus.tripod.com/jad.html [15]Christian Collberg, Clark Thomborson, “Watermarking,
Tamper-Proofing, and Obfuscation – Tools for Software Protection", IEEE Transactions on Software Engineering, vol.28, no.8, August 2002, pp. 735-746
[16]Christain Collberg, Clark Thomborson, "Software watermarking: models and dynamic embeddings", In Proceedings of the 26th ACM SIGPLAN-SIGACT symposium on Principles of programming languages, San Antonio, Texas, United States, 1999, pp. 311-324
[17]Christian Collberg, Clark Thomborson, Douglas Low,“Manufacturing Cheap, Resilient, and Stealthy Opaque Constructs", In Proceedings of the 25th ACM SIGPLAN-SIGACT symposium on Principles of programming languages, San Diego, California, United States, 1998, pp. 184-196 [18]Douglas Low, “Protection Java Via Code Obfuscation", ACM Crossroads
Student Magazine, April 1998,
http://www.acm.org/crossroads/xrds4-3/codeob.html
[19]Christian Collberg, Clark Thomborson, Douglas Low, “Breaking Abstractions and Unstructuring Data Structures", IEEE International Conference on Computer Languages (ICCL'98).
[20]Chenghui Luo, Jian Zhao, “Obfuscating and Watermarking Java Software for Copyright protection", In the INI GraphicsNet research publications, Computer Graphik topics Issue 4, vol 11, 1999, pp. 31-32 [21]How to Write Unmaintainable Code Coding Obfuscation.
http://mindprod.com/unmainobfuscation.html
[22]Barak, B., Goldreich, O., Impagliazzo, R., Rudich, S., Sahai A., Vadhan, S. and Yang, K. (2001), "On the (im)possibility of obfuscating
programs" Lecture Notes in Computer Science, 2139:1-18, Springer-Verlag.
[23]Patrick Lam., “Of Graphs and Grounds: Decompiling Java", Sable Technical Report No. 6, September 10, 1998.
[24]Raja Vallee-Rai, “Soot: A Java Bytecode Optimization Framework", Master Thesis, School of Computer Science, McGill University, Montreal, 2000.
[25]McGill's "Dava" Java Decompiler,
http://www.program-transformation.org/twiki/bin/view/Transform/Dec ompilationDava#McGill_s_Dava_Java_Decompiler
[26]Miecznikowski, J.Hendren, "Decompiling Java Using Staged Encapsulation", In Reverse Engineering, 2001. Proceedings. Eighth Working Conference, Oct. 2001, pp.368-374
[27]Jclasslib,
http://www.ej-technologies.com/products/jclasslib/overview.html [28]Barrantes, E.G., Ackley, D.H., Forrest, S., Palmer, T.S.,Stefanovic,
D. and Zovi, D.D. (2003),"Randomized instruction set emulation to disrupt binary code injection Attacks", Proc. 10th ACM Conference on Computer and Communications Security (CCS2003), 281-289,Washington DC, USA.
[29]Jonh C. Martin. “Introduction to Languages and the Theory of Computation", Third Edition, McGRAW-Hill, 2003.
[33]SourceTec Java Decompiler, http://www.srctec.com/decompiler/
[34]JReversePro,
http://sourceforge.net/project/showfiles.php?group_id=31100 [35]JODE, http://jode.sourceforge.net/
[36]ClassSpy,
http://www.freedownloadscenter.com/Programming/Java/ClassSpy.html [37]JAscii, http://zdnet.com.com/3001-2417_2-10227092.html?idl=n [38]Stunnix CXX-Obfus - the obfuscator for C and C++ source code.
http://www.stunnix.com/prod/cxxo/overview.shtml?g [39]C++ Source Code Obfuscator.
http://www.semdesigns.com/Products/Obfuscators/CppObfuscator.html
附錄一
附錄一:指令分類 1.Simple Instruction
<1>opcode 之後沒有 operand
<2>指令長度為 1
wide nop aconst_null iconst_m1 iconst_0 iconst_1 iconst_2 iconst_3 iconst_4 iconst_5 lconst_0 lconst_1 fconst_0 fconst_1 fconst_2 dconst_0 dconst_1 iload_0 iload_1 iload_2 iload_3 lload_0 lload_1 lload_2 lload_3 fload_0 fload_1 fload_2 fload_3 dload_0 dload_1 dload_2 dload_3 aload_0 aload_1 aload_2 aload_3 iaload laload faload daload aaload baload caload saload istore_0 istore_1 istore_2 istore_3 lstore_0 lstore_1 lstore_2 lstore_3 fstore_0 fstore_1 fstore_2 fstore_3 dstore_0 dstore_1 dstore_2 dstore_3 astore_0 astore_1 astore_2 astore_3 iastore lastore fastore dastore aastore bastore castore sastore pop pop2
dup dup_x1 dup_x2 dup2 dup2_x1
dup2_x2 swap iadd ladd fadd
dadd isub lsub fsub dsub imul lmul fmul dmul idiv ldiv fdiv ddiv irem lrem frem drem ineg lneg fneg dneg ishl lshl ishr lshr iushr lushr iand land ior
lor ixor lxor i2l i2f
i2d l2i l2f l2d f2i f2l f2d d2i d2l d2f
i2b i2c i2s lcmp fcmpl
fcmpg dcmpl dcmpg ireturn lreturn freturn dreturn areturn return xxxunusedxxx arraylength athrow monitorenter monitorexit breakpoint
impdep1 impdep2
2.ImmediateByte Instruction
<1>opcode 之後的第一個位元組為其 operand
<2>指令長度為 2
bipush ldc iload lload fload
dload aload istore lstore fstore dstore astore ret newarray
3. ImmediateShort Instruction
<1> opcode 之後的第一、二個位元組為其 operand
<2>指令長度為 3
ldc_w ldc2_w getstatic putstatic getfield putfield invokevirtual invokespecial invokestatic new anewarray checkcast instanceof sipush
4. Branch Instruction
<1> opcode 之後的第一、二個位元組為其 operand
<2>指令長度為 3
<3>灰影所示是 non-conditional branch instruction
ifeq ifne iflt ifge ifgt
ifle if_icmpeq if_icmpne if_icmplt if_icmpge if_icmpgt if_icmple if_acmpeq if_acmpne goto
jsr ifnull ifnonnull
5. ImmediateInt Instruction
<1> opcode 之後的第一到第四個位元組為其 operand
<2>指令長度為 5
7. TableSwitch Instruction
<1>operand 的全部數目依前幾個 operand 計算而得
<2>變動長度指令,指令長度需依其 operand 進行運算 tableswitch
8. LookupSwitchInstruction
<1>operand 的全部數目依前幾個 operand 計算而得
<2>變動長度指令,指令長度需依其 operand 進行運算 lookupswitch
9. InvokeInterface Instruction
<1>opcode 之後第一、二個位元組為 operand 1,之後兩個位元組為 operand 2
<2>指令長度為 5 invokeinterface
10. Multianewarray Instruction
<1>opcode 之後第一、二個位元組為 operand 1,第三個位元組為 operand 2
<2>指令長度為 4 multianewarray
附錄二:測試程式二 PaperDemo2.java:
package a;
import java.util.Calendar;
public class PaperDemo2{
public static void main(String[] args){
Calendar rightNow = Calendar.getInstance();
int[] added = { 1, 5, 10, 20};
B b = new B();
b.add(added);
b.show();
System.out.println("Date = " + rightNow.getTime());
} }
B.java:
package a;
import java.lang.Integer;
import java.util.Vector;
public class B{
Vector v;
public B(){
v = new Vector(2);
}
public void show(){
for(int i = 0; i < v.size(); i++){
System.out.println("Element" + i + " = " + (Integer)v.elementAt(i));
} }
public void add(int[] added){
Object ob = null;
for(int i = 0; i < added.length; i++){
ob = new Integer(added[i]);
v.addElement(ob);
} } }
轉換規格(S):
state input/output transition x state input/output transition x
goto /if_icmplt 4 0 goto /if_icmplt 5 0
if_icmplt /goto 7 2 if_icmplt/goto 4 1
aload_2 /newarray 5 0 aload_2/bipush 2 0
iconst_1 /aload_2 2 0 iconst_1/dup 1 0
newarray/iconst_1 1 0 newarray/astore_2 3 2
bipush/dup 6 3 bipush/aload_2 0 2
if_icmplt/if_icmplt 3 1 if_icmplt/if_icmplt 1 0
aload_2/iconst_1 4 0 aload_2/dup 4 0
iconst_1/iconst_1 5 0 iconst_1/iconst_1 1 0
newarray/bipush 4 2 newarray/newarray 6 0
if_icmplt/if_icmplt 6 7 if_icmplt/if_icmplt 2 0