今天和大家一起學(xué)習(xí)下java中的代碼混淆技術(shù),后面你也可以讓你的代碼不再裸露在外了,讓人輕易窺視
代碼混淆技術(shù)
當(dāng)需要閱讀jar文件的內(nèi)容時(shí),可能你會(huì)使用一些反編譯工具,比如jd-gui,但是否有遇到反編譯后的內(nèi)容和想象的不一樣,但正常引用該jar又都是正常的?
開始的話
前段時(shí)間,使用了docx4j的庫(kù)來(lái)操作.docx文件進(jìn)行一些復(fù)雜的操作,比如對(duì)多個(gè)docx文件進(jìn)行合并,在網(wǎng)上找了很多的方式發(fā)現(xiàn)最終生成的文檔都有很多多余的內(nèi)容, 導(dǎo)致原本幾兆的文件合并后有幾十兆,記得docx4j官網(wǎng)有提供商業(yè)版本的方法,準(zhǔn)備窺探下其源碼來(lái)研究下,然而當(dāng)我下載好jar后打開時(shí),我蒙了...
簡(jiǎn)介
我們知道,一般情況下編譯打包后的jar文件可以通過(guò)反編譯工具看到j(luò)ar中的接口、類、方法都是可以被,這樣相關(guān)的代碼實(shí)現(xiàn)很容易被模仿借鑒,企業(yè)的核心代碼很可能被人盜用。特別是一些涉密較強(qiáng)或者商業(yè)性的行業(yè)軟件,當(dāng)被拿到j(luò)ar并反編譯后如同開源一般。那么通過(guò)對(duì)class文件進(jìn)行字節(jié)碼級(jí)別的混淆加密,就能夠在一定程度防止技術(shù)被模仿或復(fù)用, 從而對(duì)java軟件起到很好的保護(hù)作用。
實(shí)現(xiàn)方式
- 對(duì)class文件進(jìn)行加密,但是需要特定的Classloader在加載class時(shí)對(duì)其解密
- 針對(duì)class文件反編譯原理,通過(guò)花指令防止文件被反編譯
- 基于代碼混淆技術(shù),對(duì)代碼中的包、類、方法等名稱進(jìn)行混淆,從而提高代碼閱讀成本
示例
今天主要介紹通過(guò)第3種方法實(shí)現(xiàn)代碼混淆,這里主要使用了proguard工具對(duì)應(yīng)的maven插件 proguard-maven-plugin :
Proguard是一個(gè)Java類文件壓縮器、優(yōu)化器、混淆器、預(yù)校驗(yàn)器。壓縮環(huán)節(jié)會(huì)檢測(cè)以及移除沒有用到的類、字段、方法以及屬性。優(yōu)化環(huán)節(jié)會(huì)分析以及優(yōu)化方法的字節(jié)碼。混淆環(huán)節(jié)會(huì)用無(wú)意義的短變量去重命名類、變量、方法。這些步驟讓代碼更精簡(jiǎn),更高效,也更難被逆向(破解)
比如我們基于Restful開發(fā)一個(gè)用戶服務(wù)接口
- 可能你的項(xiàng)目結(jié)構(gòu)會(huì)是這樣的:
packages...
├ entity
| ├ User
├ dao
| ├ UserDao
| ├ impl
| ├ UserDaoImpl
├ service
| ├ UserService
| ├ impl
| ├ UserServiceImpl
├ web
| ├ UserController
通過(guò)命令mvn package打包后,結(jié)構(gòu)是這樣的:
- 現(xiàn)在引入proguard:
需要在pom.xml中build標(biāo)簽中加入插件,具體配置如下:
< !-- ProGuard混淆插件-- >
< plugin >
< groupId >com.github.wvengen< /groupId >
< artifactId >proguard-maven-plugin< /artifactId >
< version >2.6.0< /version >
< executions >
< execution >
< !-- 混淆時(shí)刻,這里是打包的時(shí)候混淆-- >
< phase >package< /phase >
< goals >
< !-- 使用插件的什么功能-- >
< goal >proguard< /goal >
< /goals >
< /execution >
< /executions >
< configuration >
< !-- 是否將生成的PG文件安裝部署-- >
< attach >true< /attach >
< !-- 對(duì)什么東西進(jìn)行加載,這里僅有classes成功,畢竟你也不可能對(duì)配置文件及JSP混淆吧-- >
< injar >${project.build.finalName}.jar< /injar >
< !--class 混淆后輸出的jar包-- >
< outjar >${project.build.finalName}-pg.jar< /outjar >
< !-- 是否混淆-- >
< obfuscate >true< /obfuscate >
< !-- 配置一個(gè)文件,通常叫做proguard.cfg,該文件主要是配置options選項(xiàng),也就是說(shuō)使用proguard.cfg那么options下的所有內(nèi)容都可以移到proguard.cfg中 -- >
< proguardInclude >${project.basedir}/proguard.cfg< /proguardInclude >
< !-- 指定生成文件分類 -- >
< attachArtifactClassifier >pg< /attachArtifactClassifier >
< !-- 額外的jar包,通常是項(xiàng)目編譯所需要的jar -- >
< libs >
< lib >${java.home}/lib/rt.jar< /lib >
< /libs >
< !-- 對(duì)輸入jar進(jìn)行過(guò)濾比如,如下配置就是對(duì)META-INFO文件不處理。 -- >
< inLibsFilter >!META-INF/**< /inLibsFilter >
< !-- 這是輸出路徑配置,但是要注意這個(gè)路徑必須要包括injar標(biāo)簽填寫的jar -- >
< outputDirectory >${project.basedir}/target< /outputDirectory >
< !--這里特別重要,此處主要是配置混淆的一些細(xì)節(jié)選項(xiàng),比如哪些類不需要混淆,哪些需要混淆-- >
< options >
< !-- 可以在此處寫option標(biāo)簽配置,不過(guò)我上面使用了proguardInclude,故而我更喜歡在proguard.cfg中配置 -- >
< /options >
< /configuration >
< /plugin >
其中配置文件proguard.cfg如下:
#指定Java的版本
-target 1.8
#proguard會(huì)對(duì)代碼進(jìn)行優(yōu)化壓縮,他會(huì)刪除從未使用的類或者類成員變量等
-dontshrink
#是否關(guān)閉字節(jié)碼級(jí)別的優(yōu)化,如果不開啟則設(shè)置如下配置
-dontoptimize
#混淆時(shí)不生成大小寫混合的類名,默認(rèn)是可以大小寫混合
-dontusemixedcaseclassnames
# 對(duì)于類成員的命名的混淆采取唯一策略
-useuniqueclassmembernames
#混淆時(shí)不生成大小寫混合的類名,默認(rèn)是可以大小寫混合
-dontusemixedcaseclassnames
#混淆類名之后,對(duì)使用Class.forName('className')之類的地方進(jìn)行相應(yīng)替代
-adaptclassstrings
#對(duì)異常、注解信息予以保留
-keepattributes Exceptions,InnerClasses,Signature,Deprecated,SourceFile,LineNumberTable,*Annotation*,EnclosingMethod
# 此選項(xiàng)將保存接口中的所有原始名稱(不混淆)-- >
# -keepnames interface ** { *; }
# 此選項(xiàng)將保存所有軟件包中的所有原始接口文件(不進(jìn)行混淆)
#-keep interface * extends * { *; }
#保留參數(shù)名,因?yàn)?a target="_blank">控制器,或者M(jìn)ybatis等接口的參數(shù)如果混淆會(huì)導(dǎo)致無(wú)法接受參數(shù),xml文件找不到參數(shù)
-keepparameternames
# 保留枚舉成員及方法
-keepclassmembers enum * { *; }
# 不混淆所有類,保存原始定義的注釋-
-keepclassmembers class * {
@org.springframework.context.annotation.Bean *;
@org.springframework.beans.factory.annotation.Autowired *;
@org.springframework.beans.factory.annotation.Value *;
@org.springframework.stereotype.Service *;
@org.springframework.stereotype.Component *;
}
#忽略warn消息
-ignorewarnings
#忽略note消息
-dontnote
#打印配置信息
-printconfiguration
- 執(zhí)行打包命令mvc package,可以看到target目錄下新增了幾個(gè)文件
- obfuscation-pg.jar 混淆處理后的輸出jar
- proguard_map.txt 存放混淆前后類、方法的對(duì)應(yīng)關(guān)系
- proguard_seed.txt 存放保持不變的類 可見包的名稱、類名都改成了短字母
實(shí)現(xiàn)技術(shù)
通過(guò)proguard來(lái)實(shí)現(xiàn)class內(nèi)容的混淆相對(duì)比較簡(jiǎn)單,當(dāng)然還有很多其他的技術(shù)方法,比如上面說(shuō)到的對(duì)class進(jìn)行加密這種更安全的技術(shù)手段,感興趣的你可以繼續(xù)探究。
其他技術(shù)
- Jocky
- retroguard
- androidkiller
- ClassFinal
結(jié)束語(yǔ)
此篇文章簡(jiǎn)單介紹了java中的代碼混淆技術(shù),我們可以根據(jù)具體的項(xiàng)目需求對(duì)編譯后的代碼進(jìn)行混淆或加密處理,從而保護(hù)自己的勞動(dòng)成果。開頭看到的docx4j企業(yè)級(jí)功能提供 的jar具體是怎么實(shí)現(xiàn)代碼保護(hù)的,目前還沒發(fā)現(xiàn)其具體采用了什么技術(shù)實(shí)現(xiàn),后面繼續(xù)研究。
-
JAVA
+關(guān)注
關(guān)注
19文章
2974瀏覽量
104981 -
開源
+關(guān)注
關(guān)注
3文章
3398瀏覽量
42648 -
源碼
+關(guān)注
關(guān)注
8文章
652瀏覽量
29370 -
代碼
+關(guān)注
關(guān)注
30文章
4823瀏覽量
68902 -
編譯
+關(guān)注
關(guān)注
0文章
661瀏覽量
32977
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論