平常不太會(huì)用得到,但是一旦真的需要用到的了鸽粉,而你卻不會(huì)的話斜脂,那就非常頭疼了。別人可以反編譯程序触机,我們對程序進(jìn)行一定程度的保護(hù)帚戳,因此代碼混淆也是我們必須要掌握的一項(xiàng)技術(shù)。
Android程序打完包之后得到的是一個(gè)APK文件儡首,這個(gè)文件直接安裝到任何Android手機(jī)上片任,我們反編譯其實(shí)也就是對這個(gè)APK文件進(jìn)行反編譯。Android的反編譯主要兩個(gè)部分蔬胯,一個(gè)是對代碼的反編譯对供,一個(gè)是對資源的反編譯。
反編譯代碼
要想將APK文件中的代碼反編譯出來氛濒,我們需要用到以下兩款工具:
dex2jar 這個(gè)工具用于將dex文件轉(zhuǎn)換成jar文件
下載地址:http://sourceforge.net/projects/dex2jar/files/
jd-gui 這個(gè)工具用于將jar文件轉(zhuǎn)換成java代碼
下載地址:http://jd.benow.ca/
解壓dex2jar壓縮包后产场,你會(huì)發(fā)現(xiàn)有很多個(gè)文件,如下圖所示:
其中我們要用到的是d2j-dex2jar.bat這個(gè)文件舞竿,當(dāng)然如果你是linux或mac系統(tǒng)的話就要用d2j-dex2jar.sh這個(gè)文件京景。
然后我們將app-release.apk文件也進(jìn)行解壓,如果不知道怎么直接解壓的可以先將文件重命名成app-release.zip骗奖,然后用解壓軟件打開确徙。解壓之后你會(huì)發(fā)現(xiàn)里面有一個(gè)classes.dex文件醒串,如下圖所示:
這個(gè)classes.dex文件就是存放所有java代碼的地方了,我們將它拷貝到dex2jar解壓后的目錄下米愿,并在cmd中也進(jìn)入到同樣的目錄厦凤,然后執(zhí)行:
d2j-dex2jar classes.dex
執(zhí)行結(jié)果如下圖所示:
雖然報(bào)了錯(cuò)誤,但我們已經(jīng)轉(zhuǎn)換成功了∮叮現(xiàn)在觀察dex2jar目錄较鼓,你會(huì)發(fā)現(xiàn)多了一個(gè)文件,如下圖所示:
可以看到违柏,classes-dex2jar.jar這個(gè)文件就是我們借助工具之后成功轉(zhuǎn)換出來的jar文件了博烂。但是對于我們而言,jar文件也不是可讀的漱竖,因此這里還需要再借助一下jd-gui這個(gè)工具來將jar文件轉(zhuǎn)換成java代碼禽篱。
下面就很簡單了,使用jd-gui工具打開classes-dex2jar.jar這個(gè)文件馍惹,結(jié)果如下圖所示:
我們的代碼反編譯工作已經(jīng)成功了躺率,MainActivity中的代碼非常清晰,基本已經(jīng)做到了90%以上的還原工作万矾。但是如果想要做到100%的代碼還原還是非常有難度的悼吱,因?yàn)橄駍etContentView()方法傳入的參數(shù),其實(shí)就是一個(gè)資源的id值而已良狈,那么這里反編譯也就只能將相應(yīng)的id值進(jìn)行還原后添,而無法變成像R.layout.activity_main這樣直觀的代碼展示。
另外薪丁,除了MainActivity之外遇西,還有很多其它的代碼也被反編譯出來了,因?yàn)楫?dāng)前項(xiàng)目有引用support-v4和androidx的包严嗜,這些引用的library也會(huì)作為代碼的一部分被打包到classes.dex文件當(dāng)中粱檀,因此反編譯的時(shí)候這些代碼也會(huì)一起被還原。
好的阻问,學(xué)完了反編譯代碼梧税,接下來我們看一下如何反編譯資源。
反編譯資源
其實(shí)細(xì)心的朋友可能已經(jīng)觀察到了称近,剛才app-release.apk的解壓目錄當(dāng)中不是已經(jīng)有資源文件了嗎,有AndroidManifest.xml文件哮塞,也有res目錄刨秆。進(jìn)入res目錄當(dāng)中,內(nèi)容如下圖所示:
這不是所有資源文件都在這里了么忆畅?其實(shí)這些資源文件都是在打包的時(shí)候被編譯過了衡未,我們直接打開的話是看不到明文的,不信的話我們打開AndroidManifest.xml文件來瞧一瞧,內(nèi)容如下圖所示:
直接對APK包進(jìn)行解壓是無法得到它的原始資源文件的缓醋,因此我們還需要對資源進(jìn)行反編譯才行如失。
要想將APK文件中的資源反編譯出來,又要用到另外一個(gè)工具了:
apktool 這個(gè)工具用于最大幅度地還原APK文件中的9-patch圖片送粱、布局褪贵、字符串等等一系列的資源。
下載地址:https://ibotpeaches.github.io/Apktool/install/
接下來的工作就很簡單了抗俄,我們將app-release.apk拷貝到和這兩個(gè)文件同樣的目錄當(dāng)中脆丁,然后cmd也進(jìn)入到這個(gè)目錄下,并在cmd中執(zhí)行如下命令:
apktool d app-release.apk
其中d是decode的意思动雹,表示我們要對app-release.apk這個(gè)文件進(jìn)行解碼槽卫。那除了這個(gè)基本用法之外,我們還可以再加上一些附加參數(shù)來控制decode的更多行為:
- -f 如果目標(biāo)文件夾已存在胰蝠,則強(qiáng)制刪除現(xiàn)有文件夾(默認(rèn)如果目標(biāo)文件夾已存在歼培,則解碼失敗)茸塞。
- -o 指定解碼目標(biāo)文件夾的名稱(默認(rèn)使用APK文件的名字來命名目標(biāo)文件夾)躲庄。
- -s 不反編譯dex文件,也就是說classes.dex文件會(huì)被保留(默認(rèn)會(huì)將dex文件解碼成smali文件)
-
-r 不反編譯資源文件翔横,也就是說resources.arsc文件會(huì)被保留(默認(rèn)會(huì)將resources.arsc解碼成具體的資源文件)读跷。
apktool d -f app-release.apk -o app
image.png
這就說明反編譯資源已經(jīng)成功了。
現(xiàn)在你會(huì)發(fā)現(xiàn)在當(dāng)前目錄下多了一個(gè)app文件夾禾唁,這個(gè)文件夾中存放的就是反編譯的結(jié)果了效览。我們可以打開AndroidManifest.xml來瞧一瞧,如下圖所示:
image.png
這樣就完全能看得懂了吧
其中荡短,original文件夾下存放的是未經(jīng)反編譯過丐枉、原始的AndroidManifest.xml文件,res文件夾下存放的是反編譯出來的所有資源掘托,smali文件夾下存放的是反編譯出來的所有代碼瘦锹,AndroidManifest.xml則是經(jīng)過反編譯還原后的manifest文件。這里值得一提的是smali文件夾闪盔,如果你進(jìn)入到這個(gè)文件夾中你會(huì)發(fā)現(xiàn)它的目錄結(jié)構(gòu)和我們源碼中src的目錄結(jié)構(gòu)是幾乎一樣的弯院,主要的區(qū)別就是所有的java文件都變成了smali文件。smali文件其實(shí)也是真正的源代碼泪掀,只不過它的語法和java完全不同听绳,它有點(diǎn)類似于匯編的語法,是Android虛擬機(jī)所使用的寄存器語言异赫,語法結(jié)構(gòu)大概如下所示:
看上去有點(diǎn)暈頭轉(zhuǎn)向是嗎椅挣?如果你一旦能夠看得懂smali文件的話头岔,那么你就可以做很恐怖的事情了——你可以隨意修改應(yīng)用程序內(nèi)的邏輯,將其進(jìn)行破解鼠证!
也已經(jīng)可以對程序的邏輯做一定程度的修改了峡竣。比如說當(dāng)我們點(diǎn)擊按鈕時(shí)會(huì)彈出Hello World這樣一句Toast,邏輯是寫在MainActivity按鈕點(diǎn)擊事件的匿名類當(dāng)中的量九,因此這段代碼反編譯之后一定就會(huì)在MainActivity$1.smali這個(gè)文件當(dāng)中适掰,讓我們打開瞧一瞧,部分代碼如下所示:
雖說多數(shù)的代碼我是看不懂的娩鹉,但其中第47行實(shí)在太明顯了攻谁,Toast顯示的內(nèi)容不就是在這里定義的么,那么如果我們想把a(bǔ)pp-release程序hack掉弯予,就可以將這段字符串給改掉戚宦,比如說我把它改成Your app is been hacked。
關(guān)于smali的語法锈嫩,網(wǎng)上的資料也非常多受楼,如果你對這門技術(shù)十分感興趣的話可以直接上網(wǎng)去搜,這里我只是簡單介紹一下呼寸,就不再深入講解相關(guān)知識了艳汽。
改了一處代碼后我們再來改一處資源吧,比如這里想要把a(bǔ)pp-release的應(yīng)用圖標(biāo)給換掉对雪,那么首先我們要準(zhǔn)備好一張新的圖片河狐,如下圖所示:
然后從AndroidManifest.xml文件中可以看出,應(yīng)用圖標(biāo)使用的是ic_launcher.png這張圖片瑟捣,我們將上面彩虹圈這張圖片命名成ic_launcher.png馋艺,然后拷貝到所有以res/mipmap(貼圖)開頭的文件夾當(dāng)中完成替換操作。如下圖所示:
ic_launcher_foreground:這是Android 8.0的版本開始的前景圖(我們先按照目錄下的結(jié)構(gòu)弄)迈套,后面專門介紹APP圖標(biāo)適配
在做了兩處改動(dòng)之后捐祠,我們現(xiàn)在來把反編譯后的app-release文件夾重新打包成APK,其實(shí)非常簡單桑李,只需要在cmd中執(zhí)行如下命令:
-
apktool b app -o new_app.apk
其中b是build的意思踱蛀,表示我們要將app文件夾打包成APK文件,-o用于指定新生成的APK文件名贵白,這里新的文件叫作new_app.apk率拒。執(zhí)行結(jié)果如下圖所示:
image.png
現(xiàn)在你會(huì)發(fā)現(xiàn)在同級目錄下面生成了一個(gè)新的APK文件:
不過不要高興得太早了,目前這個(gè)new_app.apk還是不能安裝的禁荒,因?yàn)樗€沒有進(jìn)行簽名俏橘。那么如果這是別人的程序的話,我們從哪兒能拿到它原來的簽名文件呢圈浇?很顯然寥掐,這是根本沒有辦法拿到的,因此我們只能拿自己的簽名文件來對這個(gè)APK文件重新進(jìn)行簽名磷蜀,但同時(shí)也表明我們重新打包出來的軟件就是個(gè)十足的盜版軟件召耘。這里大家學(xué)學(xué)技術(shù)就好了,希望不要有任何人去做什么壞事情褐隆。
那么這里我就用一個(gè)之前生成好的簽名文件了污它,使用Android Studio或者Eclipse都可以非常簡單地生成一個(gè)簽名文件。
有了簽名文件之后在cmd中執(zhí)行簽名命令就可以進(jìn)行簽名了庶弃,命令格式如下:
- jarsigner -verbose -keystore [您的私鑰存放路徑] -signedjar [簽名后文件存放路徑] [未簽名的文件路徑] [您的證書名稱]
- 其中jarsigner命令文件是存放在jdk的bin目錄下的衫贬,需要將bin目錄配置在系統(tǒng)的環(huán)境變量當(dāng)中才可以在任何位置執(zhí)行此命令。
- 簽名之后的APK文件現(xiàn)在已經(jīng)可以安裝到手機(jī)上了歇攻,不過在此之前Android還極度建議我們對簽名后的APK文件進(jìn)行一次對齊操作固惯,因?yàn)檫@樣可以使得我們的程序在Android系統(tǒng)中運(yùn)行得更快。對齊操作使用的是zipalign工具缴守,該工具存放于<Android SDK>/build-tools/<version>目錄下葬毫,將這個(gè)目錄配置到系統(tǒng)環(huán)境變量當(dāng)中就可以在任何位置執(zhí)行此命令了。命令格式如下:
zipalign 4 new_app_release.apk new_app_aligned.apk
其中4是固定值不能改變屡穗,后面指定待對齊的APK文件名和對齊后的APK文件名贴捡。運(yùn)行這段命令之后就會(huì)生成一個(gè)new_app_aligned.apk文件,如下所示:
這個(gè)new_app_aligned.apk就是我們重新打包簽名對齊后的文件了村砂,現(xiàn)在把它安裝到手機(jī)上烂斋,效果如下圖所示:
可以看到础废,應(yīng)用圖標(biāo)已經(jīng)成功改成了彩虹圈汛骂,另外點(diǎn)擊按鈕后彈出的Toast的提示也變成了我們修改后的文字色迂,說明重新打包操作確實(shí)已經(jīng)成功了。
好的歇僧,我們把反編譯代碼图张、反編譯資源、重新打包這三大主題的內(nèi)容都已經(jīng)掌握了诈悍,關(guān)于反編譯相關(guān)的內(nèi)容就到這里