Android apk如何加固防止被破解(防止逆向编译)

本文涉及的产品
密钥管理服务KMS,1000个密钥,100个凭据,1个月
简介: 现在主要工具是接触SDK,为了防止游戏包被破解编译,以及发现加密串,我来分享下以下几点: 防破解技术主要有四种实现方式: 1.代码混淆(ProGuard)技术 2.签名比对技术 3.NDK .so 动态库技术 4.动态加载技术 5.第三方平台加密以及检测漏洞这个在 Android 安全之如何反编译与加密apk包 这篇文章中也提及到了相关的知识点。

现在主要工具是接触SDK,为了防止游戏包被破解编译,以及发现加密串,我来分享下以下几点:
防破解技术主要有四种实现方式:
1.代码混淆(ProGuard)技术
2.签名比对技术
3.NDK .so 动态库技术
4.动态加载技术
5.第三方平台加密以及检测漏洞

这个在 Android 安全之如何反编译与加密apk包 这篇文章中也提及到了相关的知识点。

  • 第一种: 代码混淆技术(ProGuard) 该技术主要是进行代码混淆,降低代码逆向编译后的可读性,但该技术无法防止加壳技术进行加壳(加入吸费、广告、病毒等代码),而且只要是细心的人,依然可以对代码依然可以对代码进行逆向分析,所以该技术并没有从根本解决破解问题,只是增加了破解难度。
  • 第二种: 签名比对技术 该技术主要防止加壳技术进行加壳,但代码逆向分析风险依然存在。而且该技术并不能根本解决被加壳问题,如果破解者将签名比对代码注释掉,再编译回来,该技术就被破解了。
  • 第三种: NDK .so动态库技术,该技术实现是将重要核心代码全部放在C文件中,利用NDK技术,将核心代码编译成.so动态库,再用JNI进行调用。该技术虽然能将核心代码保护起来,但被加壳风险依然存在。
  • 第四种: 动态加载技术,该技术在Java中是一个比较成熟的技术,而Android中该技术还没有被大家充分利用起来。
  • 第五种: 第三方平台使用

    主要讲解第四种方法,该技术可以有效的防止逆向分析、被破解、被加壳等问题,动态加载技术分为以下几步:

  • 将核心代码编译成dex文件的Jar包

  • 对jar包进行加密处理
  • 在程序主入口利用NDK进行解密
  • 再利用ClassLoader将jar包进行动态加载
  • 利用反射技术将ClassLoader 设置成系统的ClassLoader。

主要优点有:
       1.核心代码在被加密的jar中,所以破解者无法解压出class文件,如果加密秘钥被破解者拿到,那将是另外一层面的安全问题了。
      2.该技术也可以有效防止加壳技术,代码是动态加载上来的,破解者的壳程序无法加入到已加密的jar包中,及时破解者注入壳程序入口,壳程序因为不在ClassLoader 的jar包中,所以也无法被执行起来,除非破解者替换ClassLoader的jar包,关掉NDK解密代码.但这种安装到手机上,已经不在是我们的应用,用户一定会将其卸载掉。

所以综合起来比较,第四种动态加载技术是最安全的,但效率问题,本人并没做严格测试,粗略实验了一下,效率并没有明显降低。

//   1.Jar包加密加密解密文件//  
public static boolean enOrDecryptFile(byte[] paramArrayOfByte,  
        String sourceFilePath, String destFilePath,int mode){  
    File sourceFile = new File(sourceFilePath);  
    File destFile = new File(destFilePath);  
    CipherOutputStream cout = null;  
    FileInputStream in  = null;  
    FileOutputStream out = null;  
    if (sourceFile.exists() && sourceFile.isFile()) {  
        if (!destFile.getParentFile().exists()) {  
            destFile.getParentFile().mkdirs();  
        }  
        try {  
            destFile.createNewFile();  
            in = new FileInputStream(sourceFile);  
            out = new FileOutputStream(destFile);  
            // 获取密钥//  
            init();  
            SecretKeySpec secretKeySpec = new SecretKeySpec(defPassword, "AES");  
            Cipher cipher;  
            cipher = Cipher.getInstance("AES");  
            cipher.init(mode, secretKeySpec);  
            cout = new CipherOutputStream(out, cipher);  
            byte[] cache = new byte[CACHE_SIZE];  
            int nRead = 0;  
            while ((nRead = in.read(cache)) != -1) {  
                cout.write(cache, 0, nRead);  
                cout.flush();  
            }  
        }catch (IOException e) {  
            e.printStackTrace();  
            return false;  
        } catch (NoSuchAlgorithmException e) {  
            e.printStackTrace();  
            return false ;  
        } catch (NoSuchPaddingException e) {  
            e.printStackTrace();  
            return false ;  
        }catch (InvalidKeyException e) {  
            e.printStackTrace();  
            return false;  
        }finally{  
                if(cout != null){  
                    try {  
                        cout.close();  
                    } catch (IOException e) {  
                        e.printStackTrace();  
                    }  
                }  
                if(out != null){  
                    try {  
                        out.close();  
                    } catch (IOException e) {  
                        e.printStackTrace();  
                    }  
                }  
                if(in != null){  
                    try {  
                        in.close();  
                    } catch (IOException e) {  
                        e.printStackTrace();  
                    }  
                }  
        }  
        return true;  
    }  
    return false;  
}  

jar用SDK\platform-tools\下的dx命令进行dex格式转化

dx   --dex    --output=生成的目标文件的地址(绝对路径)     需要转化的jar文件(绝对路径)
                       例如:dx --dex --output=H:\classdex.jar     H:\dujinyang-KARL.jar

然后再用加密工具将生成jar文件进行加密处理

最后通过代码动态加载:

File file = new File("/data/data/" + base.getPackageName() + "/.cache/");  
        if (!file.exists()) {  
            file.mkdirs();  
        }  
        try {  
            Runtime.getRuntime().exec("chmod 755 " + file.getAbsolutePath()).waitFor();  
        } catch (InterruptedException e1) {  
            // TODO Auto-generated catch block  
            e1.printStackTrace();  
        } catch (IOException e1) {  
            // TODO Auto-generated catch block  
            e1.printStackTrace();  
        }  
        Util.copyJarFile(this);  
        Object currentActivityThread = RefInvoke.invokeStaticMethod(  
                "android.app.ActivityThread", "currentActivityThread",  
                new Class[] {}, new Object[] {});  
        String packageName = getPackageName();  
        HashMap mPackages = (HashMap) RefInvoke.getFieldOjbect(  
                "android.app.ActivityThread", currentActivityThread,  
                "mPackages");  
        WeakReference wr = (WeakReference) mPackages.get(packageName);  
        MyClassLoader dLoader = new MyClassLoader("/data/data/"  
                + base.getPackageName() + "/.cache/classdex.jar", "/data/data/"  
                + base.getPackageName() + "/.cache", "/data/data/"  
                + base.getPackageName() + "/.cache/", base.getClassLoader());  
        try {  
            Class<?>  class1 = dLoader.loadClass("com.example.test.TestActivity");  
            Log.i("b364","----------->class1: "+class1);  
        } catch (ClassNotFoundException e){  
            Log.i("b364","----------->class not found Exception!");  
            e.printStackTrace();  
        }  
        Log.i("b364","------>PackageInfo: "+wr.get());  
        // DexClassLoader dLoader = new DexClassLoader(apkFileName, odexPath,  
        // libPath, (ClassLoader) RefInvoke.getFieldOjbect(  
        // "android.app.LoadedApk", wr.get(), "mClassLoader"));  
        RefInvoke.setFieldOjbect("android.app.LoadedApk", "mClassLoader",  
                wr.get(), dLoader);  

处理完成,如果在Application中做特别处理也是可行的。之前就有人分析了爱加密的加密方式,不过这里不做阐述,有兴趣可以一起讨论。

下篇文章中我们来讲讲如何 逆向apk的动态库

相关文章
|
3天前
|
移动开发 安全 Java
Android历史版本与APK文件结构
通过以上内容,您可以全面了解Android的历史版本及其主要特性,同时掌握APK文件的结构和各部分的作用。这些知识对于理解Android应用的开发和发布过程非常重要,也有助于在实际开发中进行高效的应用管理和优化。希望这些内容对您的学习和工作有所帮助。
120 83
|
14天前
|
前端开发 Java 编译器
当flutter react native 等混开框架-并且用vscode-idea等编译器无法打包apk,打包安卓不成功怎么办-直接用android studio如何打包安卓apk -重要-优雅草卓伊凡
当flutter react native 等混开框架-并且用vscode-idea等编译器无法打包apk,打包安卓不成功怎么办-直接用android studio如何打包安卓apk -重要-优雅草卓伊凡
73 36
当flutter react native 等混开框架-并且用vscode-idea等编译器无法打包apk,打包安卓不成功怎么办-直接用android studio如何打包安卓apk -重要-优雅草卓伊凡
|
1月前
|
Dart 前端开发 Android开发
【02】写一个注册页面以及配置打包选项打包安卓apk测试—开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草央千澈
【02】写一个注册页面以及配置打包选项打包安卓apk测试—开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草央千澈
36 1
【02】写一个注册页面以及配置打包选项打包安卓apk测试—开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草央千澈
|
4月前
|
Linux API 开发工具
FFmpeg开发笔记(五十九)Linux编译ijkplayer的Android平台so库
ijkplayer是由B站研发的移动端播放器,基于FFmpeg 3.4,支持Android和iOS。其源码托管于GitHub,截至2024年9月15日,获得了3.24万星标和0.81万分支,尽管已停止更新6年。本文档介绍了如何在Linux环境下编译ijkplayer的so库,以便在较新的开发环境中使用。首先需安装编译工具并调整/tmp分区大小,接着下载并安装Android SDK和NDK,最后下载ijkplayer源码并编译。详细步骤包括环境准备、工具安装及库编译等。更多FFmpeg开发知识可参考相关书籍。
144 0
FFmpeg开发笔记(五十九)Linux编译ijkplayer的Android平台so库
|
4月前
|
编译器 Android开发
配置环境变量,使CMakeLists.txt可直接使用Android NDK工具链编译项目
配置环境变量,使CMakeLists.txt可直接使用Android NDK工具链编译项目
|
4月前
|
Ubuntu Shell API
Ubuntu 64系统编译android arm64-v8a 的openssl静态库libssl.a和libcrypto.a
Ubuntu 64系统编译android arm64-v8a 的openssl静态库libssl.a和libcrypto.a
|
6月前
|
Java Android开发 C++
Android Studio JNI 使用模板:c/cpp源文件的集成编译,快速上手
本文提供了一个Android Studio中JNI使用的模板,包括创建C/C++源文件、编辑CMakeLists.txt、编写JNI接口代码、配置build.gradle以及编译生成.so库的详细步骤,以帮助开发者快速上手Android平台的JNI开发和编译过程。
449 1
|
6月前
|
Java Android开发 Windows
使用keytool查看Android APK签名
本文介绍了如何使用Windows命令行工具和keytool查看APK的签名信息,并提供了使用AOSP环境中的signapk.jar工具对APK进行系统签名的方法。
492 0
使用keytool查看Android APK签名
|
6月前
|
Java Android开发 芯片
使用Android Studio导入Android源码:基于全志H713 AOSP,方便解决编译、编码问题
本文介绍了如何将基于全志H713芯片的AOSP Android源码导入Android Studio以解决编译和编码问题,通过操作步骤的详细说明,展示了在Android Studio中利用代码提示和补全功能快速定位并修复编译错误的方法。
351 0
使用Android Studio导入Android源码:基于全志H713 AOSP,方便解决编译、编码问题
|
6月前
|
Ubuntu 开发工具 Android开发
Repo下载、编译AOSP源码:基于Ubuntu 21.04,android-12.1.0_r27
文章记录了作者在Ubuntu 21.04服务器上配置环境、下载并编译基于Android 12.1.0_r27版本的AOSP源码的过程,包括解决编译过程中遇到的问题和错误处理方法。
368 0

热门文章

最新文章

  • 1
    如何修复 Android 和 Windows 不支持视频编解码器的问题?
  • 2
    【08】flutter完成屏幕适配-重建Android,增加GetX路由,屏幕适配,基础导航栏-多版本SDK以及gradle造成的关于fvm的使用(flutter version manage)-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
  • 3
    【04】flutter补打包流程的签名过程-APP安卓调试配置-结构化项目目录-完善注册相关页面-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程
  • 4
    APP-国内主流安卓商店-应用市场-鸿蒙商店上架之必备前提·全国公安安全信息评估报告如何申请-需要安全评估报告的资料是哪些-优雅草卓伊凡全程操作
  • 5
    【09】flutter首页进行了完善-采用android studio 进行真机调试开发-增加了直播间列表和短视频人物列表-增加了用户中心-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
  • 6
    Android经典面试题之Kotlin中Lambda表达式和匿名函数的区别
  • 7
    【02】仿站技术之python技术,看完学会再也不用去购买收费工具了-本次找了小影-感觉页面很好看-本次是爬取vue需要用到Puppeteer库用node.js扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-优雅草卓伊凡
  • 8
    【01】仿站技术之python技术,看完学会再也不用去购买收费工具了-用python扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-客户的麻将软件需要下载落地页并且要做搜索引擎推广-本文用python语言快速开发爬取落地页下载-优雅草卓伊凡
  • 9
    Android历史版本与APK文件结构
  • 10
    Cellebrite UFED 4PC 7.71 (Windows) - Android 和 iOS 移动设备取证软件