來源博客:https://www.cnblogs.com/dartagnan/
面試官:如何防止 Java 原始碼被反編譯?我竟然答不上來,,
java作為解釋型的語言,其高度抽象的特性意味其很容易被反編譯,容易被反編譯,自然有防止反編譯措施存在,今天就拜讀了一篇相關的文章,受益匪淺,知彼知己嘛!!
之所以會對java的反編譯感興趣,那是因為自己在學習的程序中,常常需要借鑒一下別人的成果(你懂的...),或許反編譯別人的代碼不怎么道德,這個嘛......
廢話不多說,正文如下:
常用的保護技術
由于Java位元組碼的抽象級別較高,因此它們較容易被反編譯,本節介紹了幾種常用的方法,用于保護Java位元組碼不被反編譯,通常,這些方法不能夠絕對防止程式被反編譯,而是加大反編譯的難度而已,因為這些方法都有自己的使用環境和弱點,
1. 隔離Java程式
最簡單的方法就是讓用戶不能夠訪問到Java Class程式,這種方法是最根本的方法,具體實作有多種方式,例如,開發人員可以將關鍵的Java Class放在服務器端,客戶端通過訪問服務器的相關介面來獲得服務,而不是直接訪問Class檔案,
這樣黑客就沒有辦法反編譯Class檔案,
目前,通過介面提供服務的標準和協議也越來越多,例如 HTTP、Web Service、RPC等,但是有很多應用都不適合這種保護方式,例如對于單機運行的程式就無法隔離Java程式,這種保護方式見圖1所示,

?
2. 對Class檔案進行加密
為了防止Class檔案被直接反編譯,許多開發人員將一些關鍵的Class檔案進行加密,例如對注冊碼、序列號管理相關的類等,在使用這些被加密的類之前,程式首先需要對這些類進行解密,而后再將這些類裝載到JVM當中,這些類的解密可以由硬體完成,也可以使用軟體完成,
在實作時,開發人員往往通過自定義ClassLoader類來完成加密類的裝載(注意由于安全性的原因,Applet不能夠支持自定義的 ClassLoader),自定義的ClassLoader首先找到加密的類,而后進行解密,最后將解密后的類裝載到JVM當中,
在這種保護方式中,自定義的ClassLoader是非常關鍵的類,由于它本身不是被加密的,因此它可能成為黑客最先攻擊的目標,如果相關的解密密鑰和演算法被攻克,那么被加密的類也很容易被解密,這種保護方式示意圖見圖2,

3. 轉換成本地代碼
將程式轉換成本地代碼也是一種防止反編譯的有效方法,因為本地代碼往往難以被反編譯,開發人員可以選擇將整個應用程式轉換成本地代碼,也可以選擇關鍵模塊轉換,如果僅僅轉換關鍵部分模塊,Java程式在使用這些模塊時,需要使用JNI技術進行呼叫,
當然,在使用這種技術保護Java程式的同時,也犧牲了Java的跨平臺特性,對于不同的平臺,我們需要維護不同版本的本地代碼,這將加重軟體支持和維護的作業,不過對于一些關鍵的模塊,有時這種方案往往是必要的,
為了保證這些本地代碼不被修改和替代,通常需要對這些代碼進行數字簽名,在使用這些本地代碼之前,往往需要對這些本地代碼進行認證,確保這些代碼沒有被黑客更改,如果簽名檢查通過,則呼叫相關JNI方法,這種保護方式示意圖見圖3,

4、代碼混淆
代碼混淆是對Class檔案進行重新組織和處理,使得處理后的代碼與處理前代碼完成相同的功能(語意),但是混淆后的代碼很難被反編譯,即反編譯后得出的代碼是非常難懂、晦澀的,因此反編譯人員很難得出程式的真正語意,
從理論上來說,黑客如果有足夠的時間,被混淆的代碼仍然可能被破解,甚至目前有些人正在研制反混淆的工具,但是從實際情況來看,由于混淆技術的多元化發展,混淆理論的成熟,經過混淆的Java代碼還是能夠很好地防止反編譯,下面我們會詳細介紹混淆技術,因為混淆是一種保護Java程式的重要技術,圖4是代碼混淆的示圖,

幾種技術的總結
以上幾種技術都有不同的應用環境,各自都有自己的弱點,表1是相關特點的比較,

到目前為止,對于Java程式的保護,混淆技識訓是最基本的保護方法,Java混淆工具也非常多,包括商業的、免費的、開放源代碼的,Sun公司也提供了自己的混淆工具,它們大多都是對Class檔案進行混淆處理,也有少量工具首先對源代碼進行處理,然后再對Class進行處理,這樣加大了混淆處理的力度,
目前,商業上比較成功的混淆工具包括JProof公司的1stBarrier系列、Eastridge公司的JShrink和 4thpass.com的SourceGuard等,主要的混淆技術按斬訓淆目標可以進行如下分類,它們分別為符號混淆(Lexical Obfuscation)、資料混淆(Data Obfuscation)、控制混淆(Control Obfuscation)、預防性混淆(Prevent Transformation),
符號混淆
在Class中存在許多與程式執行本身無關的資訊,例如方法名稱、變數名稱,這些符號的名稱往往帶有一定的含義,例如某個方法名為 getKeyLength(),那么這個方法很可能就是用來回傳Key的長度,符號混淆就是將這些資訊打亂,把這些資訊變成無任何意義的表示,例如將所有的變數從vairant_001開始編號;對于所有的方法從method_001開始編號,這將對反編譯帶來一定的困難,
對于私有函式、區域變數,通常可以改變它們的符號,而不影響程式的運行,但是對于一些介面名稱、公有函式、成員變數,如果有其它外部模塊需要參考這些符號,我們往往需要保留這些名稱,否則外部模塊找不到這些名稱的方法和變數,因此,多數的混淆工具對于符號混淆,都提供了豐富的選項,讓用戶選擇是否、如何進行符號混淆,
資料混淆

資料混淆是對程式使用的資料進行混淆,混淆的方法也有多種,主要可以分為改變資料存盤及編碼(Store and Encode Transform)、改變資料訪問(Access Transform),
改變資料存盤和編碼可以打亂程式使用的資料存盤方式,例如將一個有10個成員的陣列,拆開為10個變數,并且打亂這些變數的名字;將一個兩維陣列轉化為一個一維陣列等,對于一些復雜的資料結構,我們將打亂它的資料結構,例如用多個類代替一個復雜的類等,
另外一種方式是改變資料訪問,例如訪問陣列的下標時,我們可以進行一定的計算,圖5就是一個例子,
在實踐混淆處理中,這兩種方法通常是綜合使用的,在打亂資料存盤的同時,也打亂資料訪問的方式,經過對資料混淆,程式的語意變得復雜了,這樣增大了反編譯的難度,
控制混淆
控制混淆就是對程式的控制流進行混淆,使得程式的控制流更加難以反編譯,通常控制流的改變需要增加一些額外的計算和控制流,因此在性能上會給程式帶來一定的負面影響,有時,需要在程式的性能和混淆程度之間進行權衡,控制混淆的技術最為復雜,技巧也最多,這些技術可以分為如下幾類:
增加混淆控制通過增加額外的、復雜的控制流,可以將程式原來的語意隱藏起來,例如,對于按次序執行的兩個陳述句A、B,我們可以增加一個控制條件,以決定B的執行,通過這種方式加大反匯編的難度,但是所有的干擾控制都不應該影響B的執行,圖6就給出三種方式,為這個例子增加混淆控制,

控制流重組重組控制流也是重要的混淆方法,例如,程式呼叫一個方法,在混淆后,可以將該方法代碼嵌入到呼叫程式當中,反過來,程式中的一段代碼也可以轉變為一個函式呼叫,另外,對于一個回圈的控制流,為可以拆分多個回圈的控制流,或者將回圈轉化成一個遞回程序,這種方法最為復雜,研究的人員也非常多,
預防性混淆
這種混淆通常是針對一些專用的反編譯器而設計的,一般來說,這些技術利用反編譯器的弱點或者Bug來設計混淆方案,例如,有些反編譯器對于 Return后面的指令不進行反編譯,而有些混淆方案恰恰將代碼放在Return陳述句后面,這種混淆的有效性對于不同反編譯器的作用也不太相同的,一個好的混淆工具,通常會綜合使用這些混淆技術,
案例分析
在實踐當中,保護一個大型Java程式經常需要綜合使用這些方法,而不是單一使用某一種方法,這是因為每種方法都有其弱點和應用環境,綜合使用這些方法使得Java程式的保護更加有效,另外,我們經常還需要使用其它的相關安全技術,例如安全認證、數字簽名、PKI等,
本文給出的例子是一個Java應用程式,它是一個SCJP(Sun Certificate Java Programmer)的模擬考試軟體,該應用程式帶有大量的模擬題目,所有的題目都被加密后存盤在檔案中,由于它所帶的題庫是該軟體的核心部分,所以關于題庫的存取和訪問就成為非常核心的類,一旦這些相關的類被反編譯,則所有的題庫將被破解,現在,我們來考慮如何保護這些題庫及相關的類,
在這個例子中,我們考慮使用綜合保護技術,其中包括本地代碼和混淆技術,因為該軟體主要發布在Windows上,因此轉換成本地代碼后,僅僅需要維護一個版本的本地代碼,另外,混淆對Java程式也是非常有效的,適用于這種獨立發布的應用系統,
在具體的方案中,我們將程式分為兩個部分,一個是由本地代碼撰寫的題庫訪問的模塊,另外一個是由Java開發的其它模塊,這樣可以更高程度地保護題目管理模塊不被反編譯,對于Java開發的模塊,我們仍然要使用混淆技術,該方案的示意圖參見圖7,

對于題目管理模塊,由于程式主要在Windows下使用,所以使用C++開發題庫訪問模塊,并且提供了一定的訪問介面,為了保護題庫訪問的介面,我們還增加了一個初始化介面,用于每次使用題庫訪問介面之前的初始化作業,它的介面主要分為兩類:
1. 初始化介面
在使用題庫模塊之前,我們必須先呼叫初始化介面,在呼叫該介面時,客戶端需要提供一個亂數作為引數,題庫管理模塊和客戶端通過這個亂數,按一定的演算法同時生成相同的SessionKey,用于加密以后輸入和輸出的所有資料,
通過這種方式,只有授權(有效)的客戶端才能夠連接正確的連接,生成正確的 SessionKey,用于訪問題庫資訊,非法的客戶很難生成正確的SessionKey,因此無法獲得題庫的資訊,如果需要建立更高的保密級別,也可以采用雙向認證技術,
2. 資料訪問介面
認證完成之后,客戶端就可以正常的訪問題庫資料,但是,輸入和輸出的資料都是由SessionKey所加密的資料,因此,只有正確的題庫管理模塊才能夠使用題庫管理模塊,圖8時序圖表示了題庫管理模塊和其它部分的互動程序,

近期熱文推薦:
1.1,000+ 道 Java面試題及答案整理(2021最新版)
2.別在再滿屏的 if/ else 了,試試策略模式,真香!!
3.臥槽!Java 中的 xx ≠ null 是什么新語法?
4.Spring Boot 2.5 重磅發布,黑暗模式太炸了!
5.《Java開發手冊(嵩山版)》最新發布,速速下載!
覺得不錯,別忘了隨手點贊+轉發哦!
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/295981.html
標籤:Java
上一篇:Spring學習筆記
下一篇:ssm-spring入門
