欢迎访问移动开发之家(rcyd.net),关注移动开发教程。移动开发之家  移动开发问答|  每日更新
页面位置 : > > > 内容正文

Androidapk完整性检测的实现思路和代码实现,

来源: 开发者 投稿于  被查看 15739 次 评论:195

Androidapk完整性检测的实现思路和代码实现,


目录
  • 需求和背景
  • 实现
    • 安全管理类
  • 相关工具类

    需求和背景

    行业相关,对安全性较高的程序一般都需要添加完整性检测的功能,以防止程序被篡改,从而导致安全问题的发生。
    相关的支付应用项目今年也做了好几个,这些程序也都已通过了行业相关安全标准的认证。

    实现

    下面来分享Android APP完整性校验的实现思路和代码实现。

    通过sp判断当前是否是第一次安装apk,第一次安装默认apk是从市场下载安装,默认认为是没有被篡改过的。可以不用检查,只计算当前的hash值并保存到文件中。

    可以在application中执行,计算apk的hash值并写文件的操作是耗时操作,记得开子线程进行。

     
        private boolean integrityCheckResult = false;
        private boolean isFirstRun;//可以通过文件保存,例如SP
       @Override
        public void onCreate() {
            super.onCreate();
               ThreadPoolManager.getInstance().runInBackground(new Runnable() {
                @Override
                public void run() {
                    //检测apk完整性
                    if (isFirstRun){//skip and calculate apk's hash
                        SecurityManager.getInstance().checkIntegrity(true);
                        integrityCheckResult = true;
                    }else {
                        integrityCheckResult = SecurityManager.getInstance().checkIntegrity(false);
                    }
                }
            });
    	 public boolean isIntegrityCheckResult() {
            return integrityCheckResult;
        }

    在入口activity中判断是否完整性校验通过,假如不通过,可以弹窗提示然后锁定APP,让用户重新在安全的平台重新下载安装。当前APP无法使用,存在安全问题。

      @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            if (App.getApp().isIntegrityCheckResult()) {
                Log.d(TAG, "onCreate: checkIntegrity success");
            } else {
                Log.d(TAG, "onCreate: checkIntegrity failed");
            }
        }

    安全管理类

    新建一个安全管理类,用于管理所有和安全相关的类

    public class SecurityManager {
        //做一个单例
        private static SecurityManager instance = null;
        private final Integrity integrity;
        private SecurityManager(){
            integrity = new Integrity();
        }
        public static synchronized SecurityManager getInstance() {
            if (instance == null)
                instance = new SecurityManager();
            return instance;
        }
        public boolean checkIntegrity(boolean isFirstInstall) {
            return integrity.checkIntegrity(isFirstInstall);
        }
    }

    实现完整性检测类的接口

    public interface IIntegrity {
        boolean checkApkIntegrity();
    }

    完整性检测实现类:

    public class Integrity implements IIntegrity {
      public boolean checkIntegrity(boolean isFirstInstall) {
            if (isFirstInstall) {
                calcAndSaveApkSoHash();
                return true;
            } else {
                return compareHashsWithLastTime();
            }
        }
      private void calcAndSaveApkSoHash() {
            File apk = new File(BaseApplication.getAppContext().getPackageCodePath());
            byte[] apkHash = HashCalculator.calculateHashBytes(apk, HashCalculator.SHA_256);
            FileUtils.writeBytesToFile(filePath + APK_HASH_FILE, apkHash);
        }
     private boolean compareHashsWithLastTime() {
            //检测apk so
            return checkApkIntegrity();
        }
      @Override
        public boolean checkApkIntegrity() {
            if (BuildConfig.DEBUG) {
                Log.w(TAG, "Debug version,skip apk‘s hash verification");
                return true;
            }
            try {
                String apkPath = BaseApplication.getAppContext().getPackageCodePath();
                byte[] originalApkHash = FileUtils.readFileToBytes(filePath + APK_HASH_FILE);
                return calcSrcAndCompareWithLastHash(originalApkHash, new File(apkPath));
            } catch (IOException e) {
                Log.e(TAG, "checkApkAndLibs: ", e);
            }
            return false;
        }
        /**
         * 计算明文数据并和上一次hash进行比较
         *
         * @param decHashBytes 明文hash数据
         * @param decSrc 明文源数据
         */
        private static boolean calcSrcAndCompareWithLastHash(byte[] decHashBytes, File decSrc) {
            String decHash = Utils.bcd2Str(decHashBytes);
            //计算解密ksn的hash
            String calcHash = HashCalculator.calculateHash(decSrc, HashCalculator.SHA_256);
            LogUtils.i(TAG,
                    "calculate hash = " + Utils.bcd2Str(
                            HashCalculator.calculateHashBytes(decSrc, HashCalculator.SHA_256)));
            return decHash.equalsIgnoreCase(calcHash);
        }
    }

    相关工具类

    这个只是工具类,方便获取Application ,只要获取context即可,可以随意发挥。

    public class BaseApplication extends Application {
     private static BaseApplication mBaseApplication ;
      mBaseApplication = this;
    }
     public static BaseApplication getAppContext(){
            return mBaseApplication;
        }

    编码转换工具:

      @NonNull
        public static String bcd2Str(@Nullable byte[] b, int length) {
            if (b == null) {
                return "";
            }
            StringBuilder sb = new StringBuilder(length * 2);
            for (int i = 0; i < length; ++i) {
                sb.append(ARRAY_OF_CHAR[((b[i] & 0xF0) >>> 4)]);
                sb.append(ARRAY_OF_CHAR[(b[i] & 0xF)]);
            }
            return sb.toString();
        }

    hash计算器

      @NonNull
        public static String bcd2Str(@Nullable byte[] b, int length) {
            if (b == null) {
                return "";
            }
            StringBuilder sb = new StringBuilder(length * 2);
            for (int i = 0; i < length; ++i) {
                sb.append(ARRAY_OF_CHAR[((b[i] & 0xF0) >>> 4)]);
                sb.append(ARRAY_OF_CHAR[(b[i] & 0xF)]);
            }
            return sb.toString();
        }

    文件工具类

        /**
         * 文件锁定(File Locking)
         * 强制刷新缓冲(Force Flushing Buffer):
         */
        public static boolean writeBytesToFile(String filePath, byte[] bytes) {
            try (FileOutputStream fos = new FileOutputStream(filePath)) {
                fos.write(bytes);
                // 获取文件锁定
                FileChannel fileChannel = fos.getChannel();
                try (FileLock fileLock = fileChannel.lock()) {
                    // 强制刷新缓冲
                    fileChannel.force(true);
                }
                return true;
            } catch (IOException e) {
                LogUtils.e(e);
                return false;
            }
        }

    到此这篇关于Android apk完整性检测的实现思路和实现过程全记录的文章就介绍到这了,更多相关Android apk完整性检测内容请搜索3672js教程以前的文章或继续浏览下面的相关文章希望大家以后多多支持3672js教程!

    您可能感兴趣的文章:
    • Taro打包Android apk过程详解
    • Android Studio打包H5网址页面,封装成APK
    • 一款Android APK的结构构成解析
    • android9.0 默认apk权限添加方法
    • Android串口通信apk源码详解(附完整源码)
    • android 禁止第三方apk安装和卸载的方法详解

    用户评论