Android客户端代码保护技术-完整性校验

转载 2016年09月21日 09:59:39

       由于Android系统固有的缺陷、Android应用分发渠道管理机制等问题,导致Android客户端程序很容易被反编译篡改/二次打包,经任意签名后可在各个渠道或论坛中发布,这不仅损害了开发者的知识产权,更可能威胁到用户的敏感信息及财产安全,因此客户端程序自身的安全性尤为重要,本文以客户端完整校验为主题,提供几种Android客户端完整性校验的实现思路,供广大开发者参考。

思路1:对classes.dex文件完整性校验

       Android工程代码中的所有java代码经编译和优化最终生成Dalvik虚拟机可执行的DEX文件,DEX文件最终会打包在APK文件中,针对APK代码的篡改攻击就是针对该文件,如通常使用apktool反编译APK文件,修改smali代码。APK包中的DEX文件如下图所示:

       因此,我们可以设计编写校验代码,实现在应用程序启动时计算所程序安装包中的classes.dex文件的哈希值(可通过CRC32、MD5等摘要算法计算得到),然后与预先计算的dex文件的哈希值(该值可存储在代码或配置文件中、也可与服务器通信交互获取)进行比较,以此验证代码文件是否被篡改。

       通过检查classes.dex文件的CRC32摘要值来判断文件是否被篡改的java实现代码如下所示:

    /**
     * 通过检查classes.dex文件的CRC32摘要值来判断文件是否被篡改
     *
     * @param orginalCRC 原始classes.dex文件的CRC值
     */
    public static void apkVerifyWithCRC(Context context, String orginalCRC) {
        String apkPath = context.getPackageCodePath(); // 获取Apk包存储路径
        try {
            ZipFile zipFile = new ZipFile(apkPath);
            ZipEntry dexEntry = zipFile.getEntry("classes.dex"); // 读取ZIP包中的classes.dex文件
            String dexCRC = String.valueOf(dexEntry.getCrc()); // 得到classes.dex文件的CRC值
            if (!dexCRC.equals(orginalCRC)) { // 将得到的CRC值与原始的CRC值进行比较校验
                Process.killProcess(Process.myPid()); // 验证失败则退出程序
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

思路2:对apk包做完整性校验

       如果对apk包进行篡改,必会影响apk包的完整性校验值,因此根据思路1,我们也可以对整个apk包做哈希校验。

       通过检查apk包的MD5摘要值来判断代码文件是否被篡改的java实现代码如下图所示:

    /**
     * 通过检查apk包的MD5摘要值来判断代码文件是否被篡改
     *
     * @param orginalMD5 原始Apk包的MD5值
     */
    public static void apkVerifyWithMD5(Context context, String orginalMD5) {
        String apkPath = context.getPackageCodePath(); // 获取Apk包存储路径
        try {
            MessageDigest dexDigest = MessageDigest.getInstance("MD5");
            byte[] bytes = new byte[1024];
            int byteCount;
            FileInputStream fis = new FileInputStream(new File(apkPath)); // 读取apk文件
            while ((byteCount = fis.read(bytes)) != -1) {
                dexDigest.update(bytes, 0, byteCount);
            }
            BigInteger bigInteger = new BigInteger(1, dexDigest.digest()); // 计算apk文件的哈希值
            String sha = bigInteger.toString(16);
            fis.close();
            if (!sha.equals(orginalMD5)) { // 将得到的哈希值与原始的哈希值进行比较校验
                Process.killProcess(Process.myPid()); // 验证失败则退出程序
            }
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

思路3:对签名文件中classes.dex哈希值的校验

        Android工程代码经编译打包生成apk包后,开发者需要对其签名才能在安卓市场上发布供用户下载和安装。对apk包签名后,会在原apk包结构基础上加入META-INF文件目录。签名后的apk包文件目录如下图所示:

       META-INF文件目录下含有三个文件:MANIFEST.MF文件、ANDROIDD.SF文件、ANDROIDD.RSA文件,META_INF目录文件结构如下图所示:

       其中,MANIFEST.MF文件描述了在签名时,签名工具对apk包中各个文件摘要计算后的哈希值,并对哈希值做了Base64编码。MANIFEST.MF文件中描述的classes.dex文件的SHA-1哈希值如下图所示:

       一旦攻击者对APK中反编译并篡改代码,经二次打包签名后的classes.dex文件的SHA-1必定改变,因此,我们可以将该文件中的classes.dex文件的SHA-1哈希值保存起来作为校验对比值,应用程序启动时读取apk安装包中的MANIFEST.MF文件,解析出classes.dex的SHA-1哈希值,然后与原SHA-1哈希值进行比较,判断此APK包代码文件是否被篡改。

       通过检查签名文件classes.dex文件的哈希值来判断代码文件是否被篡改的java实现代码如下所示:

    /**
     * 通过检查签名文件classes.dex文件的哈希值来判断代码文件是否被篡改
     *
     * @param orginalSHA 原始Apk包的SHA-1值
     */
    public static void apkVerifyWithSHA(Context context, String orginalSHA) {
        String apkPath = context.getPackageCodePath(); // 获取Apk包存储路径
        try {
            MessageDigest dexDigest = MessageDigest.getInstance("SHA-1");
            byte[] bytes = new byte[1024];
            int byteCount;
            FileInputStream fis = new FileInputStream(new File(apkPath)); // 读取apk文件
            while ((byteCount = fis.read(bytes)) != -1) {
                dexDigest.update(bytes, 0, byteCount);
            }
            BigInteger bigInteger = new BigInteger(1, dexDigest.digest()); // 计算apk文件的哈希值
            String sha = bigInteger.toString(16);
            fis.close();
            if (!sha.equals(orginalSHA)) { // 将得到的哈希值与原始的哈希值进行比较校验
                Process.killProcess(Process.myPid()); // 验证失败则退出程序
            }
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

       以上三种完整性校验实现思路的实现代码样例采用Java语言实现,从安全角度来讲,很容易通过反编译篡改patch掉,因此在实现完整性校验代码时还需参考以下几点建议:

       1.预先计算的dex文件的哈希值、签名文件的classes.dex的SHA-1哈希值,应避免直接明文硬编码存储在代码或配置文件中,可对其采用非对称加密存储,或采取与服务端通信的方式获取。

       2.由于dex文件很容易通过dex2jar、apktool反编译后逆向分析和破解,因此该完整性校验功能可进一步使用C/C++代码进行编写实现。另外,进一步提高安全性,还可通过源码混淆,如:开源的obfuscator-llvm项目,或对.so动态库加壳,增加逆向分析和破解的难度。

常用Android程序逆向与保护技术

-
  • 1970年01月01日 08:00

Android 运行中效验文件完整合法性

1.概述        因为之前项目有动态热修复的功能,在修复的过程中会从服务器上下载一个新的dex文件来替换老的dex文件,所以就牵扯到文件身份效验的问题.通常接口会下发一个MD5值,只是一个MD5...
  • l2show
  • l2show
  • 2015-09-05 15:19:47
  • 20940

android_apk安全之完整性校验

android apk安全之完整性校验最近项目中在做安全监测,介于这个原因调查了一些第三方的加固防编译平台和自己使用中的心得,总结了apk安全的完整性校验的监测.完整性校验原理完整性校验就是我们用各种...
  • u012233285
  • u012233285
  • 2017-03-14 14:55:07
  • 2154

APP 完整性校验

在app开发完成发布后,难免会对app的安全性有所顾及,记录一下app完整性校验的机制来防止app被反编译造成后果。 完整性校验原理    所谓完整性校验就是我们用各种算法来计算一个文件的完整性,...
  • zcmain
  • zcmain
  • 2015-11-06 11:29:50
  • 2935

APP安全之APK完整性校验

APP安全之APK完整性校验 前言 APK 完整性校验,虽然很难做到绝对的安全,但能提高应用的安全性和破解难度。 一、认识APK安全性 危害 可以通过修改客户端文...
  • cc20032706
  • cc20032706
  • 2017-04-25 09:09:41
  • 569

Android下载文件合法性完整性校验

转载自:http://blog.csdn.net/l2show/article/details/48182367 一.概述        因为之前项目有动态热修复的功能,在修复的过程中...
  • u011941673
  • u011941673
  • 2018-01-04 11:30:35
  • 161

使用文件Md5值检测文件完整性

最近有客户反馈更新我组负责的产品后,一启动项目就崩溃,经检查发现是客户更新软件时,资源文件没有下载完整,导致程序无法正常进行。为了解决这个问题,博主第一次了解到文件的Md5值这个概念(技术小白还在成长...
  • u011791526
  • u011791526
  • 2016-09-13 09:39:31
  • 5523

【Android数据加密与完整性校验之使用MessageDigest类进行MD5/SHA1】校验数据传输的完整性常用方式

数据传输过程中容易反生数据丢失,导致软件包、数据等不能使用,检测完整性后可以提前预知数据是否可用,避免之后的麻烦。 工具/原料 MD5校验器 方法...
  • cangchen
  • cangchen
  • 2015-03-04 12:09:18
  • 1014

【Android数据加密与完整性校验之使用MessageDigest类进行MD5/SHA1】MessageDigest简介(二)

参考文章:http://blog.csdn.net/hudashi/article/details/8394158 一、概述 java.security.MessageDigest类用于为应用程序...
  • cangchen
  • cangchen
  • 2015-03-04 12:04:00
  • 1079

Android开发中使用CRC校验

  • 2016年04月29日 16:15
  • 2.47MB
  • 下载
收藏助手
不良信息举报
您举报文章:Android客户端代码保护技术-完整性校验
举报原因:
原因补充:

(最多只允许输入30个字)