手写apk加固

article/2025/10/6 13:51:21

手写apk加固

    • 加壳
    • 解压原apk并加密
    • 重命名dex文件
    • 对壳文件操作
    • 打包压缩成apk文件
    • 签名
  • 脱壳运行
      • 解压原apk, 解密原dex文件
      • 加载原dex文件
    • demo下载

apk加固的目的其实就是对app的核心代码做防护工作,避免被其他人反编译;
废话不多说了,直接开始!

加壳

首先,要想对apk加固的话,需要以下几个步骤:

  • 解压原apk
  • 对原apk里面的classes.dex 进行AES加密
  • 重命名classes.dex为classes_.dex
  • 对壳(aar)文件解压
  • 用dx工具将jar 转成classes.dex文件
  • 将壳dex文件复制到原apk的解压目录下
  • 打包压缩原apk为xxx.apk文件
  • 对打包后的apk进行签名

解压原apk并加密

public static File encryptAPKFile(File srcAPKfile, File dstApkFile) throws Exception {if (srcAPKfile == null) {System.out.println("encryptAPKFile :srcAPKfile null");return null;}
//        File disFile = new File(srcAPKfile.getAbsolutePath() + "unzip");
//		Zip.unZip(srcAPKfile, disFile);Zip.unZip(srcAPKfile, dstApkFile);//������е�dex ����Ҫ����ְ������File[] dexFiles = dstApkFile.listFiles(new FilenameFilter() {@Overridepublic boolean accept(File file, String s) {return s.endsWith(".dex");}});File mainDexFile = null;byte[] mainDexData = null;for (File dexFile: dexFiles) {//������byte[] buffer = Utils.getBytes(dexFile);//����byte[] encryptBytes = AES.encrypt(buffer);if (dexFile.getName().endsWith("classes.dex")) {mainDexData = encryptBytes;mainDexFile = dexFile;}//д����  �滻ԭ��������FileOutputStream fos = new FileOutputStream(dexFile);fos.write(encryptBytes);fos.flush();fos.close();}return mainDexFile;}

重命名dex文件

 if(newApkFile.isDirectory()){for(File newApkDirFile: Objects.requireNonNull(newApkFile.listFiles())){if(newApkDirFile.isFile()){if(newApkDirFile.getName().endsWith(".dex")){String dexName = newApkDirFile.getName();int cursor = dexName.indexOf(".dex");String reName = newApkDirFile.getParent() + File.separator + dexName.substring(0, cursor) + "_" + ".dex";System.out.println("reName value:" + reName);newApkDirFile.renameTo(new File(reName));}}}}

对壳文件操作

 File aarFile = new File(AAR_FILE_DIR + File.separator + "mylibrary-debug.aar");if(aarFile.exists()){File dexFile = Dx.jar2Dex(aarFile);if(!dexFile.exists()){System.out.println("dex file no exit xxxxxxxxxxxxxx");return;}File newDexFile = new File(apkTempFileDir.getPath() + File.separator + "classes.dex");if(!newDexFile.exists()){newDexFile.createNewFile();}FileOutputStream dexStream = new FileOutputStream(newDexFile);byte[] aarBytes = Utils.getBytes(dexFile);dexStream.write(aarBytes);dexStream.flush();dexStream.close();

打包压缩成apk文件

             File unsignApkFile = new File(PROPATH + File.separator + "apk-unsign.apk");if(!unsignApkFile.exists()){unsignApkFile.createNewFile();}//将apk/temp目录下的文件进行打包压缩Zip.zip(apkTempFileDir, unsignApkFile);

签名

 //签名Signature.signature(unsignApkFile, new File(PROPATH + File.separator + "apk-signed.apk"));

脱壳运行

所谓的脱壳其实就是将在apk安装运行的时候先运行壳文件中的dex, 然后在壳文件中的Application里面做解密处理,解密完了之后将解密后的原dex文件用BaseDexClassLoader加载到内存中;加载原dex文件的原理是仿照的tinker 框架来做的,这里只适配的android 19版本的加载方法,其他的可参照tinker 的方法或者源码进行适配, 主要原理其实就是通过反射BaseDexClassLoader中的DexPathList变量实现的, 具体流程如下:
在这里插入图片描述

从图中可以看到它最终是将要加载dex文件设置到了pathList对象里面的dexElements数组变量里面,这个dexElements就是虚拟机加载dex文件的

解压原apk, 解密原dex文件

  AES.init(getPassword());File apkFile = new File(getApplicationInfo().sourceDir);//data/data/包名/files/fake_apk/File unZipFile = getDir("fake_apk", MODE_PRIVATE);File app = new File(unZipFile, "app");if (!app.exists()) {Zip.unZip(apkFile, app);File[] files = app.listFiles();for (File file : files) {String name = file.getName();if (name.equals("classes.dex")) {} else if (name.endsWith(".dex")) {try {byte[] bytes = getBytes(file);FileOutputStream fos = new FileOutputStream(file);byte[] decrypt = AES.decrypt(bytes);
//                        fos.write(bytes);fos.write(decrypt);fos.flush();fos.close();} catch (Exception e) {e.printStackTrace();}}}}List list = new ArrayList<>();Log.d("FAKE", Arrays.toString(app.listFiles()));for (File file : app.listFiles()) {if (file.getName().endsWith(".dex")) {list.add(file);}}

加载原dex文件

 private static final class V19 {private V19() {}private static void install(ClassLoader loader, List<File> additionalClassPathEntries,File optimizedDirectory) throws IllegalArgumentException,IllegalAccessException, NoSuchFieldException, InvocationTargetException,NoSuchMethodException {Field pathListField = findField(loader, "pathList");Object dexPathList = pathListField.get(loader);ArrayList suppressedExceptions = new ArrayList();Log.d(TAG, "Build.VERSION.SDK_INT " + Build.VERSION.SDK_INT);if (Build.VERSION.SDK_INT >= 23) {expandFieldArray(dexPathList, "dexElements", makePathElements(dexPathList, newArrayList(additionalClassPathEntries), optimizedDirectory,suppressedExceptions));} else {expandFieldArray(dexPathList, "dexElements", makeDexElements(dexPathList, newArrayList(additionalClassPathEntries), optimizedDirectory,suppressedExceptions));}if (suppressedExceptions.size() > 0) {Iterator suppressedExceptionsField = suppressedExceptions.iterator();while (suppressedExceptionsField.hasNext()) {IOException dexElementsSuppressedExceptions = (IOException)suppressedExceptionsField.next();Log.w("MultiDex", "Exception in makeDexElement",dexElementsSuppressedExceptions);}Field suppressedExceptionsField1 = findField(loader,"dexElementsSuppressedExceptions");IOException[] dexElementsSuppressedExceptions1 = (IOException[]) ((IOException[])suppressedExceptionsField1.get(loader));if (dexElementsSuppressedExceptions1 == null) {dexElementsSuppressedExceptions1 = (IOException[]) suppressedExceptions.toArray(new IOException[suppressedExceptions.size()]);} else {IOException[] combined = new IOException[suppressedExceptions.size() +dexElementsSuppressedExceptions1.length];suppressedExceptions.toArray(combined);System.arraycopy(dexElementsSuppressedExceptions1, 0, combined,suppressedExceptions.size(), dexElementsSuppressedExceptions1.length);dexElementsSuppressedExceptions1 = combined;}suppressedExceptionsField1.set(loader, dexElementsSuppressedExceptions1);}}private static Object[] makeDexElements(Object dexPathList,ArrayList<File> files, FileoptimizedDirectory,ArrayList<IOException> suppressedExceptions) throwsIllegalAccessException, InvocationTargetException, NoSuchMethodException {Method makeDexElements = findMethod(dexPathList, "makeDexElements", newClass[]{ArrayList.class, File.class, ArrayList.class});return ((Object[]) makeDexElements.invoke(dexPathList, new Object[]{files,optimizedDirectory, suppressedExceptions}));}}

demo下载

demo下载地址


http://chatgpt.dhexx.cn/article/uDLmMJYy.shtml

相关文章

android apk 加固后重新签名

针对于加固平台在加固的过程中不能配置签名文件&#xff0c;加固后的apk需要进行重新签名才能安装&#xff0c;并发布到应用市场。 第一步&#xff0c;用AS对项目进行打包&#xff0c;生成签名的apk文件。 第二步&#xff0c;使用加固平台&#xff0c;对apk包进行加固&#xff…

Android Apk加固原理解析

前言 为什么要加固 对APP进行加固&#xff0c;可以有效防止移动应用被破解、盗版、二次打包、注入、反编译等&#xff0c;保障程序的安全性、稳定性。 常见的加固方案有很多&#xff0c;本文主要介绍如果通过对dex文件进行加密来达到apk加固的目的&#xff1b; APK加固整体…

apk加固后再签名

目录 前言v1签名v1v2签名 前言 apk更新之前需要做安全检测&#xff0c;检测之前一版会做加固处理&#xff0c;加固后还需要重新进行签名。本文介绍一下v1签名和v1v2签名两种方式。 有文章说需要把apk原来的签名文件&#xff0c;即META-INF文件夹删除&#xff0c;实测不删好像也…

Android apk 加固混淆的作用之解决apk报毒

现在市面上对apk的安全合规管控越来越严格了&#xff0c;也就要求了apk在上架之前一定要做合规检测和加固处理。对apk就是加固的好处&#xff0c;可以提高apk的安全性&#xff0c;提高apk被逆向分析破解的门槛&#xff0c;同时通过加固保护可以提高过安全合规的检测。由于APP加…

简书 android 加固,Android apk加固(加壳)整理

一、Dex加壳由来 最近在学习apk加密&#xff0c;在网上看了一篇《Android中的Apk的加固(加壳)原理解析和实现》&#xff0c;我发现原文把整个apk都写入到dex文件中&#xff0c;如果apk小还好&#xff0c;当原APK大于200M&#xff0c;客户端解壳很费劲&#xff0c;打开后应用就卡…

019 Android加固之APK加固的原理和实现

文章目录 前言加载Activity遇到的问题APK的启动过程替换ClassLoader流程获取ActivityThread类对象获取AppBindData类对象mBoundApplication获取LoadedApk类对象info获取info对象中的ClassLoader 设计傀儡dex文件手工加固APK代码实现APK加固实现步骤 总结 前言 动态加载dex之后…

【Android 安全】Android 应用 APK 加固总结 ( 加固原理 | 应用加固完整的实现方案 | 源码资源 )

文章目录 一、 APK 加固原理1、 Android 应用反编译2、 ProGuard 混淆3、 多 dex 加载原理4、 代理 Application 开发5、Java 工具开发6、Application 替换 二、 应用加固完整的实现方案1、 代理 Application( 1 ) ProxyApplication( 2 ) OpenSSL 解码 Kotlin 类( 3 ) 反射工具…

android资源加固,Android apk加固实现原理

apk加固是每一个app发布之前必须要做的事情;如果一个apk没有加固那么别人就很容易被别人反编译&#xff0c;看到这其中的原码&#xff0c;虽然现在有代码混淆、把业务写到native层&#xff0c;但是这都是治标不治本。反编译的技术在更新&#xff0c;那么保护Apk的技术就不能停止…

Android中Apk加固代码实现

前言&#xff1a;上一篇博客已经把Apk加固的思路详细的介绍过了&#xff0c;也开始创建了一个空的demo进行&#xff0c;然后在项目中添加一个代理module&#xff08;解密&#xff0c;和系统源码交互功能&#xff09;和tools工具加密Java library 的module &#xff0c;这里开始…

Android APK加固原理

一、前言 Android作为开源框架&#xff0c;开放之余&#xff0c;所要面临的就是安全问题&#xff0c;世间之事&#xff0c;有正就有邪&#xff0c;有攻就有守&#xff0c;作为开发者虽然不需要进入专业安全领域&#xff0c;但还是需要掌握基本的安全常识和原理。 二、加壳 加…

APK加固原理详解

一、前言 之前使用的360加固&#xff0c;挺好用的&#xff0c;从2021年底的时候限制每天每个账号仅上传2次apk&#xff08;免费的&#xff0c;不知道VIP的是不是这样&#xff09;。通过这个事情&#xff0c;感觉技术还是掌握在自己手里稳妥点&#xff0c;不用受制于人&#xf…

Android中的Apk的加固(加壳)原理解析和实现

本文转载自&#xff1a;Android中的Apk的加固(加壳)原理解析和实现 - roccheung - 博客园 一、前言 今天又到周末了&#xff0c;憋了好久又要出博客了&#xff0c;今天来介绍一下Android中的如何对Apk进行加固的原理。现阶段。我们知道Android中的反编译工作越来越让人操作熟…

浅谈安卓apk加固原理和实现

转载本文需注明出处&#xff1a;微信公众号EAWorld&#xff0c;违者必究。 引言&#xff1a; 在安卓开发中&#xff0c;打包发布是开发的最后一个环节&#xff0c;apk是整个项目的源码和资源的结合体&#xff1b;对于懂点反编译原理的人可以轻松编译出apk的源码资源&#xff0c…

安卓逆向笔记--apk加固

安卓逆向笔记–apk加固 资料来源: 浅谈安卓apk加固原理和实现 Android中的Apk的加固(加壳)原理解析和实现 前两个太老了所以具体代码借鉴下面的 Android Apk加壳技术实战详解 一、apk常见加固方法 (1)代码层级加密–代码混淆 代码混淆是一种常见的加密方式。本质是把工程中原…

imx6ull uboot移植

以下内容来自&#xff1a;正点原子Linux驱动文档 一、简介 uboot移植主要是根据原厂的uboot移植&#xff1a;芯片厂商通常会做一块自己的评估板并发布BSP&#xff0c;当我们需要定制自己的开发板时可以根据自己的需求&#xff08;硬件上的不同&#xff09;&#xff0c;对原厂…

全志V3S嵌入式驱动开发(uboot移植)

【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing @163.com】 安装了ubuntu操作系统,有了开发板,下面就可以进行我们的开发工作了。第一步,我们要面临的问题就是uboot移植。一般来说,嵌入式的基础环境就是uboot、linux和rootfs。uboot完成一…

2021-09-14 uboot移植开发

引言&#xff1a;最近要改动uboot&#xff0c;实现像微软PC上&#xff0c;u盘一键刷机或手机上安全模式下刷机的操作 专门去好好研究了点uboot的启动过程&#xff1b;以下为总结&#xff1a; 嵌入式系统 微软-PC ——…

iTOP4412 uboot移植教程

好多刚开始学习uboot移植的同学总是觉得uboot好难&#xff0c;但是再难的问题如果把它一步步拆开&#xff0c;一个个解决&#xff0c;问题也就将迎刃而解。做uboot移植&#xff0c;我们首先就得了解uboot的编译流程&#xff0c;这里以在iTOP4412精英版2G内存的板子上移植u-boot…

<Linux开发> -之-系统移植 uboot移植过程详细记录(第二部分)

&#xff1c;Linux开发&#xff1e; -之-系统移植 uboot移植过程详细记录&#xff08;第二部分&#xff09; 第一部分链接&#xff1a;系统移植-之-uboot移植第一部分 第一部分主要讲解了&#xff0c;uboot移植过程中使用的一些工具的安装&#xff0c;以及测试nxp远程uboot&a…

X210开发板(S5PV210芯片)uboot移植DM9000驱动移植

前言 本文是介绍在uboot中如何移植DM9000的驱动&#xff0c;并不深入去讲解DM9000芯片的操作时序和内部寄存器&#xff0c;想要读懂驱动代码要仔细阅读DM9000芯片的数据手册。移植的基础是手里有DM9000芯片可以用的驱动代码&#xff0c;只需要根据开发板中DM9000芯片的接线方式…