Android中的软件安全和逆向分析[二]—apk反破解技术与安全保护机制

  在Android应用开发中,当我们开发完软件之后,我们不希望别人能够反编译破解我们的应用程序,不能修改我们的代码逻辑。实际上,在应用程序的安全机制考虑中,我们希望自己的应用程序安全性高,通过各种加密操作等来增大竞争对手的反编译破解成本。设想,竞争对手开发一个同样的应用程序需要10天,而破解我们的软件程序需要100天,那么势必会打消黑客程序员破解我们应用程序的念头。如何增加对手的破解成本,就需要考验我们应用程序的安全性有多高,加密技术有多强。一个优秀的应用程序,不仅能为用户带来利益,同时也能保护自己的核心技术。



  本文主要从以下几个方面简单介绍下Android应用程序的保护机制。

一、不让程序安装到模拟器上

  在上一篇文章中Android中的软件安全和逆向分析[一]—apk反编译破解以及java汇编代码读写 里面介绍了的大多数操作是Android里的静态反编译破解apk文件。有些应用程序作了一些混淆,从SDK2.3开始我们可以看到在android-sdk-windows\tools\下面多了一个proguard文件夹,proguard是一个java代码混淆的工具,具体介绍参考这篇博文,使的代码逻辑比较复杂,此时我们如果还要静态反编译破解的话,就需要插入一些smali代码动态的去调试观察apk的逻辑。那么如何保护自己的应用程序免受反编译破解?我们需要阻止别的程序员反编译,动态调试我的应用。换句话说,就是需要阻止黑客程序员安装我的应用到模拟器上。

  一种方式是不让自己的应用程序运行在模拟器上,当应用程序发现自己安装到模拟器上的时候就会自杀。

package com.example.cracktest;

import android.app.Activity;
import android.os.Build;
import android.os.Bundle;

public class MainActivity1 extends Activity {

    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if (isEmulator()) {
            // 立刻自杀,发现自己运行在模拟器上,赶紧自杀
            android.os.Process.killProcess(android.os.Process.myPid());
        }
        setContentView(R.layout.activity_main);
    }

    /**
     * 判断应用程序是否运行在模拟器上
     *
     * @return
     */
    public boolean isEmulator() {
        // model:Android SDK built for x86
        //只要是在模拟器中,不管是什么版本的模拟器,在它的MODEL信息里就会带有关键字参数sdk
        if (Build.MODEL.contains("sdk") || Build.MODEL.contains("SDK")) {
            return true;
        } else {
            return false;
        }
    }
}

  上述应用程序部署到真机上是可以运行的, 但是在模拟器上是打不开的,这样就防止了黑客程序员动态调试我们的应用程序。

二、检测应用程序的完整性

  第二种保护应用程序的安全机制是检测应用程序的完整性,我们可以用jni技术校验应用程序的完整性,也可以利用数字签名的方式来检测应用程序的完整性。我们知道当一个apk文件被反编译破解、修改完代码逻辑之后,要使用jarsigner工具来重新给apk签名,才能运行修改后的apk文件。一个应用程序的签名,是识别一个开发者的唯一标识,如果一个应用程序被别人反编译,那么这个应用程序的签名肯定会改变。当发现程序的签名改变时,我们使之自杀就可以避免程序带来损失。下面我们来介绍下数字签名的方式检测应用程序的完整性。

package com.example.cracktest;

import android.app.Activity;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.os.Bundle;

public class MainActivity2 extends Activity {

    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        System.out.println(getSignature());
    }

    /**
     * 获得应用程序的数字签名
     *
     * @return
     */
    public String getSignature() {
        PackageManager pm = getPackageManager();
        try {
            // 得到当前应用程序的签名
            PackageInfo info = pm.getPackageInfo(getPackageName(),
                    PackageManager.GET_SIGNATURES);
            return info.signatures[0].toCharsString();
        } catch (NameNotFoundException e) {
            e.printStackTrace();
            return "";
        }
    }
}

  上述简单实例代码获取到的应用程序的数字签名为,

  

  任何一个对原apk的操作都会修改原apk的数字签名,为了在程序中判断方便,我们取数字签名的MD5哈希值来判断。

  

package com.example.cracktest;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

public class MD5 {

    /**
     * 对字符串进行MD5加密
     * @param content
     * @return
     */
    public static String getMD5(String content) {
        try {
            MessageDigest digest = MessageDigest.getInstance("MD5");
            digest.update(content.getBytes());
            return getHashString(digest);

        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        return null;
    }

    private static String getHashString(MessageDigest digest) {
        StringBuilder builder = new StringBuilder();
        for (byte b : digest.digest()) {
            builder.append(Integer.toHexString((b >> 4) & 0xf));
            builder.append(Integer.toHexString(b & 0xf));
        }
        return builder.toString();
    }
}

  

  我们在应用程序运行时,判断当前的数字签名的MD5哈希值是否等于上述图片中的哈希值,如果等于,合法运行,如果不等于,就能够证明apk文件被反编译破解过,这个时候我们1.5s后自杀程序。

  

package com.example.cracktest;

import android.app.Activity;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.os.Bundle;
import android.widget.Toast;

public class MainActivity2 extends Activity {

    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        System.out.println(getSignature());

        // 正确的签名信息为77e980cae813e5dacc11fdb4c67988fd
        if ("77e980cae813e5dacc11fdb4c67988fd".equals(getSignature())) {
            Toast.makeText(this, "自校验完毕,合法正常运行。", 0).show();
        } else {
            Toast.makeText(this, "你敢破解我的代码!", 0).show();
            new Thread() {
                public void run() {
                    try {
                        Thread.sleep(1500);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    android.os.Process.killProcess(android.os.Process.myPid());
                };
            }.start();
        }
    }

    /**
     * 获得应用程序的数字签名
     *
     * @return
     */
    public String getSignature() {
        PackageManager pm = getPackageManager();
        try {
            // 得到当前应用程序的签名
            PackageInfo info = pm.getPackageInfo(getPackageName(),
                    PackageManager.GET_SIGNATURES);
            return MD5.getMD5(info.signatures[0].toCharsString());
        } catch (NameNotFoundException e) {
            e.printStackTrace();
            return "";
        }
    }
}

  具体的反编译过程可以参见上一篇文章 Android中的软件安全和逆向分析[一]—apk反编译破解以及java汇编代码读写 ,当反编译apk,修改smali代码,重新给apk签名后,部署到模拟器上运行,发现1.5s后程序自杀。

  检测包名,版本名和版本号,然后做判断,与检测数字签名方法大同小异。有兴趣的可以自己研究研究。

三、动态字节码技术

  应用程序的运行字节码不在本地,而是在网络端,就是说我们的应用程序的关键性核心代码不要放在本地,应该放在网络服务器端上。而在网络端的字节码如何获取呢?我们通过URLClassLoader从服务器上把字节码下载到本地,然后编译运行。这种动态从网络获取字节码的技术可以防止黑客程序员本地静态的反编译我们的应用程序。

四、zip包加密

五、花指令加壳技术

  开发程序员先做一个so的壳,当做应用程序的运行环境,壳里面运行着我们的程序代码,相当于在java虚拟机的上层加了一个代码监视器。也可以说是在加密后的虚拟机里运行我们的应用程序,增加了安全性。

六、参考引用

未完待续。。。

时间: 2024-07-29 11:07:52

Android中的软件安全和逆向分析[二]—apk反破解技术与安全保护机制的相关文章

Android逆向分析(2) APK的打包与安装

http://blog.zhaiyifan.cn/2016/02/13/android-reverse-2/ 2/18日增加对aidl和java编译的描述. 前言 上一次我们反编译了手Q,并遇到了Apktool反编译直接crash的问题,虽然笔者很想在这次解决这个问题,但在解决途中,发现该保护依赖于很多知识,所以本次先插入一下,正所谓知其然知其所以然,授之鱼不如授之以渔,只有知道一些基本原理,才能让我们以后能自行解决更多问题. 那么,你知道么?从我们在Android Studio中,点击run,

Android中的消息处理实例与分析

Android中的消息处理实例与分析 摘要 本文介绍了Android中的消息处理机制,给出了Android消息处理中的几个重点类Handler.Message.MessageQueue.Looper.Runnable.Thread的详细介绍,提供了两个消息处理的实例代码,并深入分析了使用Android消息机制应该遵循的几个原则. 阅读本文的收获 在具有java基础的情况下,Android的学习比较轻松,很多人在没有深刻了解Android消息处理机制的背景下,已经能够开发出可用的app,很多人开始

Android 4.4 音量调节流程分析(二)

之前在Android 4.4 音量调节流程分析(一)里已经有简单的分析音量控制的流程,今天想接着继续分析下音量大小计算的方法.对于任一播放文件而言其本身都有着固定大小的音量Volume_Max,而在AudioPolicyManagerBase.cpp文件中音量调节可以理解为在Volume_Max的基础上乘以系数κ(0≤κ≤1). 现在对AudioPolicyManagerBase.cpp中volIndexToAmpl函数做具体分析,volIndexToAmpl的函数定义如下: 1 float A

Android中相机和相册使用分析

Android中相机和相册使用分析 欢迎转载,但请尊重原创(文章来自不易,转载请标明转载出处,谢谢) 在手机应用程序中,使用自带的相机拍照以及相册选择喜欢的图片是最常见不过的用户需求,那么怎么合理使用相机和相册来选择照片是重要的,下面就以项目中实际需求为例进行说明,这里实现的功能如下: 1 使用相机和相册选择图片,并裁剪较小图片(常用于剪裁小图) 2 使用相机和相册选择图片,并裁剪较大图片(常用于裁剪大图) 具体的实现功能清楚了,那么就一一进行说明,具体如下(这里不会罗列怎么上传图片到服务端,只

Android中关于JNI 的学习(二)对于JNI方法名,数据类型和方法签名的一些认识

处理特征数据 及 代码 本文地址: http://blog.csdn.net/caroline_wendy/article/details/26240241 输入文件:  1. 归一化后的特征文件, 第1列是标签, 其余列是特征; 2. 特征最大值向量文件: 前3列是标准格式, 其余列是最大值; 输出文件: 1. 符合SVM训练数据的特征格式; 2. Mat存储的标准XML文件; 代码: /* 处理特征数据程序 By C.L.Wang 数据格式: 特征数据: 第1列是标签, 其余列是特征; 最大

Android中app卡顿原因分析示例

在知乎回答了一个“为什么微博的app在iPhone比Android上流畅”的问题.后面部分是一个典型的动画卡顿的性能分析过程,因此帖在这里.有编程问题可以在这里交流.知乎链接. ========================================================= 我来说下我所知道的事情.我不知道iOS为什么流畅,但我知道一些Android为什么不流畅的原因. 首先,就题主所说的问题,我用iPad和小米Pad对比了一下微博滑动滚屏这件事情(2014年8月10日目前微博

android中倒计时控件CountDownTimer分析

android中倒计时控件CountDownTimer分析 1 示例代码 new CountDownTimer(10000, 1000) { public void onTick(long millisUntilFinished) { LogUtil.i(TAG, "seconds remaining: " + millisUntilFinished / 1000); } public void onFinish() { LogUtil.i(TAG, "done!"

笔记-Android中打开各种格式的文件(apk、word、excel、ppt、pdf、音视频、图片等)

打开后缀.apk的文件,即启动安装程序: //apkFilePath 文件路径 public void installAPK(String apkFilePath) { // 创建URI Uri uri = Uri.fromFile(new File(apkFilePath)); Intent intent = new Intent(Intent.ACTION_VIEW); // 设置Uri和类型 intent.setDataAndType(uri, "application/vnd.andro

Android程序反破解技术

0x1 对抗反编译可以大概分为以下几点: 1.对抗反编译工具,例如apktool.dex2jar等 2.对抗静态编译,分为代码混淆技术.NDK保护.apk加壳保护. 3.对抗动态调试,分为检测调试器.检测模拟器. 4.防止重编译,分为检查签名,校验保护. 更多相关内容请参考<Android软件安全与逆向分析>. 0x02 对抗反编译工具,例如dex2jar,通常是在分析dex2jar源码后,来找到漏洞,在java源码中加入会触发dex2jar异常的代码,从而使dex2jar不能正常使用. de