APK自我保護 - DEX/APK校驗

DEX/APK 校驗是在應用開發結束後,在本地計算出其 CRC 值或者 MD5值。在應用運行的時候,經過網絡或者資源文件中獲取事前算好的值進行比對,若是不一致則說明 DEX/APK 可能存在被篡改的風險。java

傳送門: APK自我保護 - DEX/APK校驗android

DEX校驗

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();
    }
}

計算 CRC 值

這一步必須在應用開發完成的時候去計算,若是改動了代碼就必須從新計算。this

利用 unzip 解壓

解壓命令: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

利用 crc32 命令獲取 crc 值

mac系統自帶 crc32 命令:xml

crc32 classes.dex

這裏生成的 crc 值是16進制數咱們能夠轉換成十進制。ip

保存到 string.xml 文件

由於 string.xml 文件是資源文件不會影響到 classes.dex 因此修改是沒有關係的。md5

APK校驗

與 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();
    }
}

計算 CRC 值

這一步必須在應用開發完成而且打包 release 版本的時候進行計算。
mac 系統爲例:

md5 release.apk

總結

固然上述的保護方式容易被暴力破解, 完整性檢查最終仍是經過返回 true/false 來控制 後續代碼邏輯的走向,若是攻擊者直接修改代碼邏輯,完整性檢查始終返回 true,那這種方 法就無效了,因此相似文件完整性校驗須要配合一些其餘方法,或者有其餘更爲巧妙的方式 實現?

相關文章
相關標籤/搜索