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程序的反破解技术

转自:http://blog.csdn.net/viviwen123/article/details/9117589 逆向Android软件的步骤:首先是对其进行反编译,然后阅读反汇...
  • Hknock
  • Hknock
  • 2016年04月11日 11:00
  • 1637

APP安全之APK完整性校验

APP安全之APK完整性校验前言 APK 完整性校验,虽然很难做到绝对的安全,但能提高应用的安全性和破解难度。 一、认识APK安全性危害可以通过修改客户端文件篡改客户端行为。攻击者可以让客户端显示...
  • vfush
  • vfush
  • 2016年05月22日 21:19
  • 6936

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

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

android APK安全性校验

APK安全性校验获取签名证书keystore的SHA1值和完整性校验获取的classes.dex的SHA-1哈希值字符串 建议后台保存初始值与前端获取sha1值做判断是否可以进行下一步操作...
  • qq_18413391
  • qq_18413391
  • 2017年02月07日 12:00
  • 654

Android签名机制之---签名验证过程详解

今天是元旦前夕,也是Single Dog的嚎叫之日,只能写博客来祛除寂寞了,今天我们继续来看一下Android中的签名机制的姊妹篇:Android中是如何验证一个Apk的签名。在前一篇文章中我们介绍了...
  • jiangwei0910410003
  • jiangwei0910410003
  • 2016年01月01日 09:52
  • 25731

Android中使用Activity的权限进行启动验证

权限的使用主要用于从其他应用中调用该应用的Activity进行一些操作,比如第三方登录;进行权限的设置后可以调用该应用进行操作首先在第一个应用的AndroidManifest中定义一个权限: 然后在...
  • u013360850
  • u013360850
  • 2016年03月01日 22:09
  • 1870

APK校验码校验规则

获取签名证书keystore的SHA1值和完整性校验获取的classes.dex的SHA-1哈希值字符串进行拼接,使用MD5加密参数传入后台做比对,根据返回结果是否进行下一步登录操作 1.签名证书文...
  • woaiheima
  • woaiheima
  • 2017年03月14日 10:55
  • 669

android MD5校验码的生成与算法实现

android MD5校验码的生成与算法实现 在Java中,java.security.MessageDigest (rt.jar中)已经定义了 MD5 的计算,所以我们只需要简单地调用...
  • u012422855
  • u012422855
  • 2015年06月26日 16:55
  • 348

android对文件的MD5验证

  • 2010年08月31日 18:09
  • 868B
  • 下载

android对文件的MD5验证

1.   说明 android自带的MD5校验类 2.   例程 1)       功能 对文件/init.rc做MD5计算,并以字串的方式显示 2)       可从此处下载可...
  • andylao62
  • andylao62
  • 2015年03月18日 22:02
  • 468
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Android客户端代码保护技术-完整性校验
举报原因:
原因补充:

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