之前有寫過一篇博客介紹了下java字節(jié)碼的查看和分析
其實除了分析java內(nèi)部類、枚舉等java語言的實現(xiàn)原理之外,在一些特定的場景也是比較有用的.
這篇文章做個死,給大家講解通過字節(jié)碼去破解某些安卓應(yīng)用的原理.(現(xiàn)在一般都是通過修改smali去做的,但是其實基于字節(jié)碼也是可以做到的党远,這篇文章基于之前的java字節(jié)碼分析,所以只講字節(jié)碼的方式,smali的話大家可以自行搜索)
很多的單機游戲,甚至是一些網(wǎng)絡(luò)游戲他們運行的時候邏輯運算都是放在本地的.服務(wù)端只是接收客戶端上傳的運算結(jié)果.還有一些收費應(yīng)用,其實功能都在本地代碼里面了,只不過是判斷了下是否有付費,如果有付費才顯示功能入口.
如果我們可以修改它的代碼,將上傳的結(jié)果或者是否付費的判斷改成我們希望的,就可以為所欲為了.
反編譯
要修改應(yīng)用的代碼邏輯,首先要先分析原來的代碼邏輯是怎樣的.
但由于應(yīng)用的代碼都是各家公司的私有財產(chǎn),除非有人做大死泄露了出來,一般我們是拿不到的.所以這個時候我們就只能使用反編譯技術(shù)了.
如果大家到網(wǎng)上搜索apk的反編譯技術(shù),大概率會搜到下面的方法:
- 使用apktool工具解壓apk
- 使用dex2jar工具將安卓優(yōu)化后的dex文件轉(zhuǎn)換成java的class
- 使用jd-gui工具查看class里面的java代碼
這么繁瑣的操作其實已經(jīng)過時了,我這邊介紹個一鍵式傻瓜操作的工具給大家
jadx
jadx是個開源的安卓反編譯工具,它的代碼托管在github上,大家可以去下載來使用
用法很簡單,下載之后解壓,然后進入bin目錄運行jadx-gui(linux/mac)或者jadx-gui.bat(windows),就可以啟動一個可視化的界面了,然后點擊"文件->打開",并且選擇我們想要反編譯的應(yīng)用,就能看到apk里面的代碼了
我這里反編譯了一個demo應(yīng)用,它的MainActivity.onCreate里面判斷了一個flag變量,然后彈出Toast.
我們安裝這個apk運行起來可以看到彈出toast: "hello world!"
其他應(yīng)用也是類似的,可以這樣查看它們的代碼.
不過正式發(fā)布的應(yīng)用一般都會做混淆操作,這個時候我們反編譯處理看到的代碼的類名、方法名抵碟、變量名就都會變成a,b,c這樣無意義的字符.
但是只是名字變了,執(zhí)行邏輯是完全一樣的,所以只要夠細心,還是可以理清楚它的代碼邏輯的.
jadx有個厲害的功能就是可以導(dǎo)出gradle工程,點擊"文件->另存為Gradle項目"就可以導(dǎo)出gradle項目了,然后改下目錄結(jié)構(gòu),就可以用Android studio去打開工程并且編輯修改代碼了.
如果修改之后編譯成功,那么我們的目的就達到了,可以為所欲為,但是這個項目大概率是不能編譯成功的,有很多奇奇怪怪的錯誤.
接下來我就帶大家一步步破解這個apk桃漾,修改它的邏輯,不彈"hello world!"而是彈"hello java".
修改應(yīng)用的字節(jié)碼
我們可以用jadx去很方便的分析代碼邏輯,但是如果重新編譯失敗的話我們就只有走別的路子了.
這里介紹直接編輯字節(jié)碼的方式.走這條路的話就沒有什么傻瓜操作可以用了.還是老老實實一步步來吧
1. 解壓apk
apk其實是一種zip壓縮包,我們可以將它的后綴改成.zip,然后直接解壓
我們將解壓出來的東西都放到app-release-unsigned目錄里面:
2. 將dex轉(zhuǎn)換成jar
我們都知道安卓的虛擬機不是普通的java虛擬機,它不能直接運行java的class文件,需要優(yōu)化成dex文件.
而我們修改字節(jié)碼的時候就需要將它轉(zhuǎn)換回來了,這里使用的就是dex-tools工具的dex2jar功能:
這里我只介紹Linux下命令的用法,就不介紹Windows上的使用了,其實是類似的使用.bat的版本,大家可以自行搜索.
將classes.dex轉(zhuǎn)換成jar文件:
~/dex-tools-2.1-SNAPSHOT/d2j-dex2jar.sh classes.dex
它會生成classes-dex2jar.jar文件:
3. 修改class字節(jié)碼
其實jar文件也是一種zip壓縮包,我們依然可以直接把后綴改成zip,然后解壓:
然后找到MainActivity.class
這個時候我們就能用上篇文章說的javap命令去查看里面的代碼了:
javap -c MainActivity
這里第16行的意思就是付過棧頂?shù)膬蓚€變量不相等就跳到第32行代碼,否則繼續(xù)執(zhí)行
16: if_icmpne 32
而我們可以看到,繼續(xù)執(zhí)行的話會輸出hello world!,如果跳的32行的話就會輸出hello java!
這里我們可以直接將if_icmpne改成if_icmpeq,在相等的時候跳到32行,否則繼續(xù)執(zhí)行,這樣原來的"hello world!"提示就會變成"hello java!"了
如果直接用編輯器打開class文件,里面是一些二進制的值.
那我們要怎么修改呢?
這里我們會用到另外一個工具jbe,全稱是java bytecode editor
下載了之后解壓,進入bin目錄使用下面命令打開圖形界面:
java ee.ioc.cs.jbe.browser.BrowserApplication
在圖形界面打開MainActivity.class,并且找到我們的MainActivity.onCreate代碼:
然后點擊Code Editor選項就可以對字節(jié)碼進行修改了,這里我們將if_icmpne改成if_icmpeq,然后點擊Save method:
這樣我們的邏輯修改就完成了
4. 重新打包dex
接下來我們將重新打包apk,首先將class壓縮成zip,注意目錄結(jié)構(gòu):
然后將后綴改成jar,并且使用jar2dex生成dex:
~/dex-tools-2.1-SNAPSHOT/d2j-jar2dex.sh classes-dex2jar.jar
接著用生成的dex替換原來的classes.dex,然后刪除所有剛剛生成的臨時文件,如classes-dex2jar.zip和classes-dex2jar目錄
5.刪除簽名信息
一般我們拿到的應(yīng)用都是簽名過的應(yīng)用拟逮,應(yīng)用簽名之后會將資源和代碼的校驗信息保存到apk里撬统,如果我們修改了dex文件,就會導(dǎo)致校驗失敗敦迄,這樣的話apk是不能安裝的宪摧。
所以我們需要把原來的簽名刪掉,具體做法就是刪除META-INF目錄里面的三個文件:
CERT.RSA
CERT.SF
MANIFEST.MF
6. 重新打包apk
接下來同樣的壓縮文件生成zip壓縮包,注意目錄結(jié)構(gòu):
最后將zip后綴改成apk,我們的apk就打包好了
重簽名
由于我們重新打包的apk刪除了簽名信息,如果直接安裝是會失敗的,需要我們重新給它簽名.
創(chuàng)建簽名
可以用下面命令創(chuàng)建alias為android.keystore,文件名也是android.keystore的簽名文件
keytool -genkeypair -alias android.keystore -keyalg RSA -validity 400 -keystore android.keystore
按下回車之后它會讓你輸入一些密碼颅崩、開發(fā)者信息等,完成之后就能得到一個android.keystore文件
簽名應(yīng)用
然后我們使用得到的android.keystore去給應(yīng)用重新簽名:
jarsigner -keystore android.keystore -signedjar release.apk app-release-unsigned.apk android.keystore
得到簽好名的release.apk
大功告成!
讓我們安裝進去運行看看,toast已經(jīng)變成了"hello java!":