Android 反編譯

平常不太會用得到,但是一旦真的需要用到的了,而你卻不會的話,那就非常頭疼了。別人可以反編譯程序,我們對程序進行一定程度的保護,因此代碼混淆也是我們必須要掌握的一項技術(shù)。

Android程序打完包之后得到的是一個APK文件,這個文件直接安裝到任何Android手機上,我們反編譯其實也就是對這個APK文件進行反編譯。Android的反編譯主要兩個部分,一個是對代碼的反編譯,一個是對資源的反編譯。

反編譯代碼
要想將APK文件中的代碼反編譯出來,我們需要用到以下兩款工具:

dex2jar 這個工具用于將dex文件轉(zhuǎn)換成jar文件
下載地址:http://sourceforge.net/projects/dex2jar/files/
jd-gui 這個工具用于將jar文件轉(zhuǎn)換成java代碼
下載地址:http://jd.benow.ca/

解壓dex2jar壓縮包后,你會發(fā)現(xiàn)有很多個文件,如下圖所示:


image.png

其中我們要用到的是d2j-dex2jar.bat這個文件,當(dāng)然如果你是linux或mac系統(tǒng)的話就要用d2j-dex2jar.sh這個文件。
然后我們將app-release.apk文件也進行解壓,如果不知道怎么直接解壓的可以先將文件重命名成app-release.zip,然后用解壓軟件打開。解壓之后你會發(fā)現(xiàn)里面有一個classes.dex文件,如下圖所示:


image.png

這個classes.dex文件就是存放所有java代碼的地方了,我們將它拷貝到dex2jar解壓后的目錄下,并在cmd中也進入到同樣的目錄,然后執(zhí)行:

d2j-dex2jar classes.dex

執(zhí)行結(jié)果如下圖所示:


image.png

雖然報了錯誤,但我們已經(jīng)轉(zhuǎn)換成功了?,F(xiàn)在觀察dex2jar目錄,你會發(fā)現(xiàn)多了一個文件,如下圖所示:


image.png

可以看到,classes-dex2jar.jar這個文件就是我們借助工具之后成功轉(zhuǎn)換出來的jar文件了。但是對于我們而言,jar文件也不是可讀的,因此這里還需要再借助一下jd-gui這個工具來將jar文件轉(zhuǎn)換成java代碼。
下面就很簡單了,使用jd-gui工具打開classes-dex2jar.jar這個文件,結(jié)果如下圖所示:
image.png

我們的代碼反編譯工作已經(jīng)成功了,MainActivity中的代碼非常清晰,基本已經(jīng)做到了90%以上的還原工作。但是如果想要做到100%的代碼還原還是非常有難度的,因為像setContentView()方法傳入的參數(shù),其實就是一個資源的id值而已,那么這里反編譯也就只能將相應(yīng)的id值進行還原,而無法變成像R.layout.activity_main這樣直觀的代碼展示。
另外,除了MainActivity之外,還有很多其它的代碼也被反編譯出來了,因為當(dāng)前項目有引用support-v4和androidx的包,這些引用的library也會作為代碼的一部分被打包到classes.dex文件當(dāng)中,因此反編譯的時候這些代碼也會一起被還原。
好的,學(xué)完了反編譯代碼,接下來我們看一下如何反編譯資源。

反編譯資源

其實細心的朋友可能已經(jīng)觀察到了,剛才app-release.apk的解壓目錄當(dāng)中不是已經(jīng)有資源文件了嗎,有AndroidManifest.xml文件,也有res目錄。進入res目錄當(dāng)中,內(nèi)容如下圖所示:

image.png

這不是所有資源文件都在這里了么?其實這些資源文件都是在打包的時候被編譯過了,我們直接打開的話是看不到明文的,不信的話我們打開AndroidManifest.xml文件來瞧一瞧,內(nèi)容如下圖所示:
image.png

直接對APK包進行解壓是無法得到它的原始資源文件的,因此我們還需要對資源進行反編譯才行。
要想將APK文件中的資源反編譯出來,又要用到另外一個工具了:
apktool 這個工具用于最大幅度地還原APK文件中的9-patch圖片、布局、字符串等等一系列的資源。
下載地址:https://ibotpeaches.github.io/Apktool/install/

接下來的工作就很簡單了,我們將app-release.apk拷貝到和這兩個文件同樣的目錄當(dāng)中,然后cmd也進入到這個目錄下,并在cmd中執(zhí)行如下命令:
apktool d app-release.apk
其中d是decode的意思,表示我們要對app-release.apk這個文件進行解碼。那除了這個基本用法之外,我們還可以再加上一些附加參數(shù)來控制decode的更多行為:

  • -f 如果目標(biāo)文件夾已存在,則強制刪除現(xiàn)有文件夾(默認(rèn)如果目標(biāo)文件夾已存在,則解碼失敗)。
  • -o 指定解碼目標(biāo)文件夾的名稱(默認(rèn)使用APK文件的名字來命名目標(biāo)文件夾)。
  • -s 不反編譯dex文件,也就是說classes.dex文件會被保留(默認(rèn)會將dex文件解碼成smali文件)
  • -r 不反編譯資源文件,也就是說resources.arsc文件會被保留(默認(rèn)會將resources.arsc解碼成具體的資源文件)。
    apktool d -f app-release.apk -o app


    image.png

    這就說明反編譯資源已經(jīng)成功了。
    現(xiàn)在你會發(fā)現(xiàn)在當(dāng)前目錄下多了一個app文件夾,這個文件夾中存放的就是反編譯的結(jié)果了。我們可以打開AndroidManifest.xml來瞧一瞧,如下圖所示:


    image.png

    這樣就完全能看得懂了吧
image.png

其中,original文件夾下存放的是未經(jīng)反編譯過、原始的AndroidManifest.xml文件,res文件夾下存放的是反編譯出來的所有資源,smali文件夾下存放的是反編譯出來的所有代碼,AndroidManifest.xml則是經(jīng)過反編譯還原后的manifest文件。這里值得一提的是smali文件夾,如果你進入到這個文件夾中你會發(fā)現(xiàn)它的目錄結(jié)構(gòu)和我們源碼中src的目錄結(jié)構(gòu)是幾乎一樣的,主要的區(qū)別就是所有的java文件都變成了smali文件。smali文件其實也是真正的源代碼,只不過它的語法和java完全不同,它有點類似于匯編的語法,是Android虛擬機所使用的寄存器語言,語法結(jié)構(gòu)大概如下所示:


image.png

看上去有點暈頭轉(zhuǎn)向是嗎?如果你一旦能夠看得懂smali文件的話,那么你就可以做很恐怖的事情了——你可以隨意修改應(yīng)用程序內(nèi)的邏輯,將其進行破解!
也已經(jīng)可以對程序的邏輯做一定程度的修改了。比如說當(dāng)我們點擊按鈕時會彈出Hello World這樣一句Toast,邏輯是寫在MainActivity按鈕點擊事件的匿名類當(dāng)中的,因此這段代碼反編譯之后一定就會在MainActivity$1.smali這個文件當(dāng)中,讓我們打開瞧一瞧,部分代碼如下所示:


image.png

雖說多數(shù)的代碼我是看不懂的,但其中第47行實在太明顯了,Toast顯示的內(nèi)容不就是在這里定義的么,那么如果我們想把app-release程序hack掉,就可以將這段字符串給改掉,比如說我把它改成Your app is been hacked。
關(guān)于smali的語法,網(wǎng)上的資料也非常多,如果你對這門技術(shù)十分感興趣的話可以直接上網(wǎng)去搜,這里我只是簡單介紹一下,就不再深入講解相關(guān)知識了。
改了一處代碼后我們再來改一處資源吧,比如這里想要把app-release的應(yīng)用圖標(biāo)給換掉,那么首先我們要準(zhǔn)備好一張新的圖片,如下圖所示:


ic_launcher.png(彩虹圈)

然后從AndroidManifest.xml文件中可以看出,應(yīng)用圖標(biāo)使用的是ic_launcher.png這張圖片,我們將上面彩虹圈這張圖片命名成ic_launcher.png,然后拷貝到所有以res/mipmap(貼圖)開頭的文件夾當(dāng)中完成替換操作。如下圖所示:


image.png

ic_launcher_foreground:這是Android 8.0的版本開始的前景圖(我們先按照目錄下的結(jié)構(gòu)弄),后面專門介紹APP圖標(biāo)適配
在做了兩處改動之后,我們現(xiàn)在來把反編譯后的app-release文件夾重新打包成APK,其實非常簡單,只需要在cmd中執(zhí)行如下命令:

  • apktool b app -o new_app.apk
    其中b是build的意思,表示我們要將app文件夾打包成APK文件,-o用于指定新生成的APK文件名,這里新的文件叫作new_app.apk。執(zhí)行結(jié)果如下圖所示:


    image.png

現(xiàn)在你會發(fā)現(xiàn)在同級目錄下面生成了一個新的APK文件:


image.png

不過不要高興得太早了,目前這個new_app.apk還是不能安裝的,因為它還沒有進行簽名。那么如果這是別人的程序的話,我們從哪兒能拿到它原來的簽名文件呢?很顯然,這是根本沒有辦法拿到的,因此我們只能拿自己的簽名文件來對這個APK文件重新進行簽名,但同時也表明我們重新打包出來的軟件就是個十足的盜版軟件。這里大家學(xué)學(xué)技術(shù)就好了,希望不要有任何人去做什么壞事情。
那么這里我就用一個之前生成好的簽名文件了,使用Android Studio或者Eclipse都可以非常簡單地生成一個簽名文件。

有了簽名文件之后在cmd中執(zhí)行簽名命令就可以進行簽名了,命令格式如下:

  • jarsigner -verbose -keystore [您的私鑰存放路徑] -signedjar [簽名后文件存放路徑] [未簽名的文件路徑] [您的證書名稱]
  • 其中jarsigner命令文件是存放在jdk的bin目錄下的,需要將bin目錄配置在系統(tǒng)的環(huán)境變量當(dāng)中才可以在任何位置執(zhí)行此命令。
  • 簽名之后的APK文件現(xiàn)在已經(jīng)可以安裝到手機上了,不過在此之前Android還極度建議我們對簽名后的APK文件進行一次對齊操作,因為這樣可以使得我們的程序在Android系統(tǒng)中運行得更快。對齊操作使用的是zipalign工具,該工具存放于<Android SDK>/build-tools/<version>目錄下,將這個目錄配置到系統(tǒng)環(huán)境變量當(dāng)中就可以在任何位置執(zhí)行此命令了。命令格式如下:

zipalign 4 new_app_release.apk new_app_aligned.apk

其中4是固定值不能改變,后面指定待對齊的APK文件名和對齊后的APK文件名。運行這段命令之后就會生成一個new_app_aligned.apk文件,如下所示:


image.png

這個new_app_aligned.apk就是我們重新打包簽名對齊后的文件了,現(xiàn)在把它安裝到手機上,效果如下圖所示:
可以看到,應(yīng)用圖標(biāo)已經(jīng)成功改成了彩虹圈,另外點擊按鈕后彈出的Toast的提示也變成了我們修改后的文字,說明重新打包操作確實已經(jīng)成功了。


image.png

好的,我們把反編譯代碼、反編譯資源、重新打包這三大主題的內(nèi)容都已經(jīng)掌握了,關(guān)于反編譯相關(guān)的內(nèi)容就到這里

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容