您的位置:首页 > 其它

APK自我保护 - DEX/APK/证书校验

2016-11-22 13:54 162 查看


转载自: http://gnaixx.cc/2016/04/19/android-protect-dex_apk_cert_check/


0x00 DEX校验

classes.dex 是 Android 虚拟机的可执行文件,我们所写的 java 代码其实都在这里面,所有很多对应用程序的篡改都是针对 classes.dex 文件的。

可以找一个 APK 解压就可以看到 classes.dex 文件。APK 其实就是一个压缩包,通过将后缀名改为 
zip
 就可以直接解压,或者用 
unzip
 命令。


编写代码

代码比较简单,这里是通过建计算好的 crc 保存在 string.xml 文件里,当然我们事先可以随便拿一个值代替,等开发完成后替换掉。
校验代码:
1234567891011121314151617181920212223242526
/** * 校验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 值

这一步必须在应用开发完成的时候去计算,如果改动了代码就必须重新计算。


利用
unzip 解压

解压命令:
unzip -d output app-debug.apk

output 文件夹:
123456789
total 2200drwxr-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.xmldrwxr-xr-x   7 xiangqing  staff   238B  4 20 22:18 META-INF-rw-r--r--   1 xiangqing  staff   1.1M  9 15  2015 classes.dexdrwxr-xr-x   3 xiangqing  staff   102B  4 20 22:18 orgdrwxr-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 命令:
crc32 classes.dex

这里生成的 crc 值是16进制数我们可以转换成十进制。


保存到
string.xml 文件

因为 string.xml 文件是资源文件不会影响到 classes.dex 所以修改是没有关系的。


0x01
APK校验

与 DEX 校验不同 APK 检验必须把把计算好的 Hash 值放在网络服务端,因为对 APK 的任何改动都会影响到最后的 Hash 值。
校验代码:
12345678910111213141516171819202122232425262728293031323334353637
/** * 校验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();    }}


计算
MD5 值

这一步必须在应用开发完成并且打包 release 版本的时候进行计算。

mac 系统为例:
md5 release.apk


0x02
证书校验

每个APK都会经过开发者独有的证书进行签名,如果破解者对APK进行二次打包一般会用自己的签名证书打包。这时候我们就可以通过校验签名证书的MD5值进行校验。
校验代码:

123456789101112131415161718192021222324252627
/** * 获取签名证书 */public void verifySignature() {    String packageName = this.getPackageName();    PackageManager pm = this.getPackageManager();    PackageInfo pi;    String md5 = "";    try {        pi = pm.getPackageInfo(packageName, PackageManager.GET_SIGNATURES);        Signature[] s = pi.signatures;        //计算出MD5值        MessageDigest msgDigest = MessageDigest.getInstance("MD5");        msgDigest.reset();        msgDigest.update(s[0].toByteArray());        BigInteger bInt = new BigInteger(1, msgDigest.digest());        md5 = bInt.toString(16);    } catch (Exception e) {        e.printStackTrace();    }    Log.d("Sign", md5);    /**     * 获取服务端的 签名证书对比     */}


获取签名证书
MD5

在release前我们可以获取证书的MD5值具体操作为:

解压apk

unzip -d output release.apk

解压后文件为

1234567
lltotal 5224-rw-r--r--   1 xiangqing  staff   2.0K  6  5 11:42 AndroidManifest.xmldrwxr-xr-x   5 xiangqing  staff   170B  6  5 11:56 META-INF-rw-r--r--   1 xiangqing  staff   2.4M  6  5 11:42 classes.dexdrwxr-xr-x  22 xiangqing  staff   748B  6  5 11:56 res-rw-r--r--   1 xiangqing  staff   173K  6  5 11:28 resources.arsc
其中文件夹
META-INF
中的
CERT.RSA
文件就是签名文件,通过
keytool
工具就可以看到其中的MD5
等属性
123456789101112131415161718192021
→ keytool -printcert -file CERT.RSA所有者: CN=Android Debug, O=Android, C=US发布者: CN=Android Debug, O=Android, C=US序列号: 44bff7c9有效期开始日期: Wed Feb 18 21:01:26 CST 2015, 截止日期: Fri Feb 10 21:01:26 CST 2045证书指纹:	 MD5: 05:F1:5D:AF:1D:EA:56:A8:1B:96:F9:37:06:04:FA:A1	 SHA1: 4E:13:A8:8F:89:B1:92:89:10:9D:24:F4:9A:B5:E2:C1:22:CD:84:B4	 SHA256: BA:4E:CF:72:93:F3:AA:1B:A5:31:6E:67:6D:AE:E7:A6:84:41:BC:7C:B3:29:7B:45:56:48:36:DF:CE:58:30:2B	 签名算法名称: SHA256withRSA	 版本: 3扩展:#1: ObjectId: 2.5.29.14 Criticality=falseSubjectKeyIdentifier [KeyIdentifier [0000: 25 CF E3 1E 4F 04 22 BA   AA D8 41 6F BC 07 2D 5D  %...O."...Ao..-]0010: CB EE E3 84                                        ....]]


0x03总结

当然上述的保护方式容易被暴力破解, 完整性检查最终还是通过返回 true/false 来控制 后续代码逻辑的走向,如果攻击者直接修改代码逻辑,完整性检查始终返回 true,那这种方 法就无效了,所以类似文件完整性校验需要配合一些其他方法,或者有其他更为巧妙的方式 实现?
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: