DEX/APK 校驗是在應用開發結束後,在本地計算出其 CRC 值或者 MD5值。在應用運行的時候,經過網絡或者資源文件中獲取事前算好的值進行比對,若是不一致則說明 DEX/APK 可能存在被篡改的風險。java
傳送門: APK自我保護 - DEX/APK校驗android
classes.dex 是 Android 虛擬機的可執行文件,咱們所寫的 java 代碼其實都在這裏面,全部不少對應用程序的篡改都是針對 classes.dex 文件的。能夠找一個 APK 解壓就能夠看到 classes.dex 文件。APK 其實就是一個壓縮包,經過將後綴名改成zip
就能夠直接解壓,或者用 unzip
命令。網絡
代碼比較簡單,這裏是經過建計算好的 crc 保存在 string.xml 文件裏,固然咱們事先能夠隨便拿一個值代替,等開發完成後替換掉。
校驗代碼:app
/** * 校驗Dex CRC值 */ private void verifyDex(){ //獲取String.xml中的value Long dexCrc = Long.parseLong(this.getString(R.string.crc_value)); String apkPath = this.getPackageCodePath(); try { ZipFile zipFile = new ZipFile(apkPath); ZipEntry dexEntry = zipFile.getEntry("classes.dex"); //計算classes.dex的 crc long dexEntryCrc = dexEntry.getCrc(); Log.d("DEX", dexEntryCrc + ""); //對比 if(dexCrc == dexEntryCrc){ Log.d("DEX", "dex hasn't been modified"); }else{ Log.d("DEX", "dex has been modified"); } } catch (IOException e) { e.printStackTrace(); } }
這一步必須在應用開發完成的時候去計算,若是改動了代碼就必須從新計算。this
解壓命令:debug
unzip -d output app-debug.apk
output 文件夾:code
total 2200 drwxr-xr-x 8 xiangqing staff 272B 4 20 22:18 . drwxr-xr-x 6 xiangqing staff 204B 4 20 22:18 .. -rw-r--r-- 1 xiangqing staff 3.1K 9 15 2015 AndroidManifest.xml drwxr-xr-x 7 xiangqing staff 238B 4 20 22:18 META-INF -rw-r--r-- 1 xiangqing staff 1.1M 9 15 2015 classes.dex drwxr-xr-x 3 xiangqing staff 102B 4 20 22:18 org drwxr-xr-x 10 xiangqing staff 340B 4 20 22:18 res -rw-r--r-- 1 xiangqing staff 4.4K 9 15 2015 resources.arsc
mac系統自帶 crc32 命令:xml
crc32 classes.dex
這裏生成的 crc 值是16進制數咱們能夠轉換成十進制。ip
由於 string.xml 文件是資源文件不會影響到 classes.dex 因此修改是沒有關係的。md5
與 DEX 校驗不一樣 APK 檢驗必須把把計算好的 Hash 值放在網絡服務端,由於對 APK 的任何改動都會影響到最後的 Hash 值。
校驗代碼:
/** * 校驗APK MD5值 */ private void verifyApk(){ //獲取data/app/****/base.apk 路徑 String apkPath = getPackageResourcePath(); Log.d("APK", apkPath); MessageDigest msgDigest; try { //獲取apk並計算MD5值 msgDigest = MessageDigest.getInstance("MD5"); byte[] bytes = new byte[4096]; int count; FileInputStream fis; fis = new FileInputStream(new File(apkPath)); while((count = fis.read(bytes)) >0){ msgDigest.update(bytes, 0, count); } //計算出MD5值 BigInteger bInt = new BigInteger(1, msgDigest.digest()); String md5 = bInt.toString(16); fis.close(); Log.d("APK", md5); /** * 獲取服務端的 MD5值進行對比 */ } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } }
這一步必須在應用開發完成而且打包 release 版本的時候進行計算。
mac 系統爲例:
md5 release.apk
固然上述的保護方式容易被暴力破解, 完整性檢查最終仍是經過返回 true/false 來控制 後續代碼邏輯的走向,若是攻擊者直接修改代碼邏輯,完整性檢查始終返回 true,那這種方 法就無效了,因此相似文件完整性校驗須要配合一些其餘方法,或者有其餘更爲巧妙的方式 實現?