文章目录

  • 一、解压 apk 文件
  • 二、加密生成 dex 文件
  • 三、打包未签名 apk 文件
  • 四、完整代码示例
  • 五、文件解压缩相关代码
  • 六、执行结果

参考博客 :

  • 【Android 安全】DEX 加密 ( 常用 Android 反编译工具 | apktool | dex2jar | enjarify | jd-gui | jadx )
  • 【Android 安全】DEX 加密 ( Proguard 简介 | Proguard 相关网址 | Proguard 混淆配置 )
  • 【Android 安全】DEX 加密 ( Proguard 简介 | 默认 ProGuard 分析 )
  • 【Android 安全】DEX 加密 ( Proguard keep 用法 | Proguard 默认混淆结果 | 保留类及成员混淆结果 | 保留注解以及被注解修饰的类/成员/方法 )
  • 【Android 安全】DEX 加密 ( Proguard 混淆 | 混淆后的报错信息 | Proguard 混淆映射文件 mapping.txt )
  • 【Android 安全】DEX 加密 ( Proguard 混淆 | 将混淆后的报错信息转为原始报错信息 | retrace.bat 命令执行目录 | 暴露更少信息 )
  • 【Android 安全】DEX 加密 ( DEX 加密原理 | DEX 加密简介 | APK 文件分析 | DEX 分割 )
  • 【Android 安全】DEX 加密 ( 多 DEX 加载 | 65535 方法数限制和 MultiDex 配置 | PathClassLoader 类加载源码分析 | DexPathList )
  • 【Android 安全】DEX 加密 ( 不同 Android 版本的 DEX 加载 | Android 8.0 版本 DEX 加载分析 | Android 5.0 版本 DEX 加载分析 )
  • 【Android 安全】DEX 加密 ( DEX 加密使用到的相关工具 | dx 工具 | zipalign 对齐工具 | apksigner 签名工具 )
  • 【Android 安全】DEX 加密 ( 支持多 DEX 的 Android 工程结构 )
  • 【Android 安全】DEX 加密 ( 代理 Application 开发 | multiple-dex-core 依赖库开发 | 配置元数据 | 获取 apk 文件并准备相关目录 )
  • 【Android 安全】DEX 加密 ( 代理 Application 开发 | 解压 apk 文件 | 判定是否是第一次启动 | 递归删除文件操作 | 解压 Zip 文件操作 )
  • 【Android 安全】DEX 加密 ( 代理 Application 开发 | 加载 dex 文件 | 反射获取系统的 Element[] dexElements )
  • 【Android 安全】DEX 加密 ( 代理 Application 开发 | 加载 dex 文件 | 使用反射获取方法创建本应用的 dexElements | 各版本创建 dex 数组源码对比 )
  • 【Android 安全】DEX 加密 ( Java 加密工具开发 | 加密解密算法 API | 编译代理 Application 依赖库 | 解压依赖库 aar 文件 ) )
  • 【Android 安全】DEX 加密 ( Java 加密工具开发 | 生成 dex 文件 | Java 命令行执行 )

在 【Android 安全】DEX 加密 ( 支持多 DEX 的 Android 工程结构 ) 博客中介绍了 DEX 加密工程的基本结构 ,

app 是主应用 , 其 Module 类型是 “Phone & Tablet Module” ,

multiple-dex-core 是 Android 依赖库 , 其作用是解密并加载多 DEX 文件 , 其 Module 类型是 “Android Library” ,

multiple-dex-tools 是 Java 依赖库 , 其类型是 “Java or Kotlin Library” , 其作用是用于生成主 DEX ( 主 DEX 的作用就是用于解密与加载多 DEX ) , 并且还要为修改后的 APK 进行签名 ;

在 【Android 安全】DEX 加密 ( 代理 Application 开发 | multiple-dex-core 依赖库开发 | 配置元数据 | 获取 apk 文件并准备相关目录 ) 博客中讲解了 multiple-dex-core 依赖库开发 , 每次启动都要解密与加载 dex 文件 , 在该博客中讲解到了 获取 apk 文件 , 并准备解压目录 ;

在 【Android 安全】DEX 加密 ( 代理 Application 开发 | 解压 apk 文件 | 判定是否是第一次启动 | 递归删除文件操作 | 解压 Zip 文件操作 ) 博客中讲解了 apk 文件解压操作 ;

在 【Android 安全】DEX 加密 ( 代理 Application 开发 | 加载 dex 文件 | 反射获取系统的 Element[] dexElements )博客中讲解了 dex 文件加载第一阶段 , 获取系统中的 Element[] dexElements ;

在 【Android 安全】DEX 加密 ( 代理 Application 开发 | 加载 dex 文件 | 使用反射获取方法创建本应用的 dexElements | 各版本创建 dex 数组源码对比 ) 博客中讲解了讲解 dex 文件加载操作 第二阶段 , 创建本应用的 dex 文件数组 Element[] dexElements ;

在 【Android 安全】DEX 加密 ( 代理 Application 开发 | 加载 dex 文件 | 将系统的 dexElements 与 应用的 dexElements 合并 | 替换操作 ) 博客中讲解了剩余的两个操作 :

  • 将 系统加载的 Element[] dexElements 数组 与 我们 自己的 Element[] dexElements 数组 进行合并操作 ;
  • 替换 ClassLoader 加载过程中的 Element[] dexElements 数组 ( 封装在 DexPathList 中 )

在 【Android 安全】DEX 加密 ( Java 加密工具开发 | 加密解密算法 API | 编译代理 Application 依赖库 | 解压依赖库 aar 文件 ) ) 博客中介绍 加密解密算法 API , 编译代理 Application 依赖库 , 解压依赖库 aar 文件 ;

在 【Android 安全】DEX 加密 ( Java 加密工具开发 | 生成 dex 文件 | Java 命令行执行 ) 博客中介绍 使用 SDK 中的 dx 工具生成 dex 文件 ;

本博客中讲解 将 app 主应用的 apk 文件解压 , 加密其中的 classes.dex 文件 , 并将代理 Application 依赖库中的 classes.dex 打包到未签名的 apk 文件中 ;

一、解压 apk 文件


被解压的 apk 文件位置 app/build/outputs/apk/debug/app-debug.apk ,

将该 apk 文件解压到 app/build/outputs/apk/debug/unZipFile 目录中 ;

    // 解压 apk 文件 , 获取所有的 dex 文件// 被解压的 apk 文件var apkFile = File("app/build/outputs/apk/debug/app-debug.apk")// 解压的目标文件夹var apkUnZipFile = File("app/build/outputs/apk/debug/unZipFile")// 解压文件unZip(apkFile, apkUnZipFile)

unZip 方法中的代码在最后一节中 ;

二、加密生成 dex 文件


将 app-debug.apk 中的 dex 文件进行加密 , 使用上篇博客中的 AES 类进行加密 ,

加密后 的 dex 文件重命名为 secret-classes.dex ,

放到 app/build/outputs/apk/debug/unZipFile 目录中 ,

然后删除原来的文件 ;

    // 加密找到的 dex 文件var aes = AES(AES.DEFAULT_PWD)// 遍历 dex 文件for(dexFile: File in dexFiles){// 读取文件数据var bytes = getBytes(dexFile)// 加密文件数据var encryptedBytes = aes.encrypt(bytes)// 将加密后的数据写出到指定目录var outputFile = File(apkUnZipFile, "secret-${dexFile.name}")// 创建对应输出流var fileOutputStream = FileOutputStream(outputFile)// 将加密后的 dex 文件写出, 然后刷写 , 关闭该输出流fileOutputStream.write(encryptedBytes)fileOutputStream.flush()fileOutputStream.close()// 删除原来的文件dexFile.delete()}

三、打包未签名 apk 文件


将代理 Application 所在的 Android 依赖库的 dex 文件拷贝到 app/build/outputs/apk/debug/unZipFile 目录中 ,

将上述目录打包文件重命名为 app-unsigned.apk ,

存放路径为 app/build/outputs/apk/debug/app-unsigned.apk ;

    /*3 . 将代理 Application 中的 classes.dex 解压到上述app/build/outputs/apk/debug/unZipFile 目录中*/// 拷贝文件到 app/build/outputs/apk/debug/unZipFile 目录中classesDexFile.renameTo(File(apkUnZipFile, "classes.dex"))// 压缩打包 , 该压缩包是未签名的压缩包var unSignedApk = File("app/build/outputs/apk/debug/app-unsigned.apk")// 压缩打包操作zip(apkUnZipFile, unSignedApk)

四、完整代码示例


@ExperimentalStdlibApi
fun main() {/*1 . 生成 dex 文件 , 该 dex 文件中只包含解密 其它 dex 的功能编译工程会生成 Android 依赖库的 aar 文件生成目录是 module/build/outputs/aar/ 目录下前提是需要在 菜单栏 / File / Setting / Build, Execution, Deployment / Compiler设置界面中 , 勾选 Compile independent modules in parallel (may require larger )将 D:\002_Project\002_Android_Learn\DexEncryption\multiple-dex-core\build\outputs\aar路径下的 multiple-dex-core-debug.aar 文件后缀修改为 .zip解压上述文件拿到 classes.jar 文件即可 ;*/// 获取 multiple-dex-core-debug.aar 文件对象var aarFile = File("multiple-dex-core/build/outputs/aar/multiple-dex-core-debug.aar")// 解压上述 multiple-dex-core-debug.aar 文件到 aarUnzip 目录中// 创建解压目录var aarUnzip = File("multiple-dex-tools/aarUnzip")// 解压操作unZip(aarFile, aarUnzip)// 拿到 multiple-dex-core-debug.aar 中解压出来的 classes.jar 文件var classesJarFile = File(aarUnzip, "classes.jar")// 创建转换后的 dex 目的文件, 下面会开始创建该 dex 文件var classesDexFile = File(aarUnzip, "classes.dex")// 打印要执行的命令println("cmd /c D:/001_Programs/001_Android/002_Sdk/Sdk/build-tools/30.0.2/dx.bat --dex --output ${classesDexFile.absolutePath} ${classesJarFile.absolutePath}")/*将 jar 包变成 dex 文件 使用 dx 工具命令注意 : Windows 命令行命令之前需要加上 "cmd /c " 信息 , Linux 与 MAC 命令行不用添加*/var process = Runtime.getRuntime().exec("cmd /c D:/001_Programs/001_Android/002_Sdk/Sdk/build-tools/30.0.2/dx.bat --dex --output ${classesDexFile.absolutePath} ${classesJarFile.absolutePath}")// 等待上述命令执行完毕process.waitFor()// 执行结果提示if(process.exitValue() == 0){println("执行成功");} else {println("执行失败");}/*2 . 加密 apk 中的 dex 文件*/// 解压 apk 文件 , 获取所有的 dex 文件// 被解压的 apk 文件var apkFile = File("app/build/outputs/apk/debug/app-debug.apk")// 解压的目标文件夹var apkUnZipFile = File("app/build/outputs/apk/debug/unZipFile")// 解压文件unZip(apkFile, apkUnZipFile)// 从被解压的 apk 文件中找到所有的 dex 文件, 小项目只有 1 个, 大项目可能有多个// 使用文件过滤器获取后缀是 .dex 的文件var dexFiles : Array<File> = apkUnZipFile.listFiles({ file: File, s: String ->s.endsWith(".dex")})// 加密找到的 dex 文件var aes = AES(AES.DEFAULT_PWD)// 遍历 dex 文件for(dexFile: File in dexFiles){// 读取文件数据var bytes = getBytes(dexFile)// 加密文件数据var encryptedBytes = aes.encrypt(bytes)// 将加密后的数据写出到指定目录var outputFile = File(apkUnZipFile, "secret-${dexFile.name}")// 创建对应输出流var fileOutputStream = FileOutputStream(outputFile)// 将加密后的 dex 文件写出, 然后刷写 , 关闭该输出流fileOutputStream.write(encryptedBytes)fileOutputStream.flush()fileOutputStream.close()// 删除原来的文件dexFile.delete()}/*3 . 将代理 Application 中的 classes.dex 解压到上述app/build/outputs/apk/debug/unZipFile 目录中*/// 拷贝文件到 app/build/outputs/apk/debug/unZipFile 目录中classesDexFile.renameTo(File(apkUnZipFile, "classes.dex"))// 压缩打包 , 该压缩包是未签名的压缩包var unSignedApk = File("app/build/outputs/apk/debug/app-unsigned.apk")// 压缩打包操作zip(apkUnZipFile, unSignedApk)}

五、文件解压缩相关代码


/*** 删除文件, 如果有目录, 则递归删除*/
private fun deleteFile(file: File) {if (file.isDirectory) {val files = file.listFiles()for (f in files) {deleteFile(f)}} else {file.delete()}
}/*** 解压文件* @param zip 被解压的压缩包文件* @param dir 解压后的文件存放目录*/
fun unZip(zip: File, dir: File) {try {// 如果存放文件目录存在, 删除该目录deleteFile(dir)// 获取 zip 压缩包文件val zipFile = ZipFile(zip)// 获取 zip 压缩包中每一个文件条目val entries = zipFile.entries()// 遍历压缩包中的文件while (entries.hasMoreElements()) {val zipEntry = entries.nextElement()// zip 压缩包中的文件名称 或 目录名称val name = zipEntry.name// 如果 apk 压缩包中含有以下文件 , 这些文件是 V1 签名文件保存目录 , 不需要解压 , 跳过即可if (name == "META-INF/CERT.RSA" || name == "META-INF/CERT.SF" || (name== "META-INF/MANIFEST.MF")) {continue}// 如果该文件条目 , 不是目录 , 说明就是文件if (!zipEntry.isDirectory) {val file = File(dir, name)// 创建目录if (!file.parentFile.exists()) {file.parentFile.mkdirs()}// 向刚才创建的目录中写出文件val fileOutputStream = FileOutputStream(file)val inputStream = zipFile.getInputStream(zipEntry)val buffer = ByteArray(1024)var len: Intwhile (inputStream.read(buffer).also { len = it } != -1) {fileOutputStream.write(buffer, 0, len)}inputStream.close()fileOutputStream.close()}}// 关闭 zip 文件zipFile.close()} catch (e: Exception) {e.printStackTrace()}
}fun zip(dir: File, zip: File) {// 如果目标压缩包存在 , 删除该压缩包zip.delete()// 对输出文件做 CRC32 校验val cos = CheckedOutputStream(FileOutputStream(zip), CRC32())val zos = ZipOutputStream(cos)// 压缩文件compress(dir, zos, "")zos.flush()zos.close()
}private fun compress(srcFile: File, zos: ZipOutputStream, basePath: String) {if (srcFile.isDirectory) {val files = srcFile.listFiles()for (file in files) {// zip 递归添加目录中的文件compress(file, zos, basePath + srcFile.name + "/")}} else {compressFile(srcFile, zos, basePath)}
}private fun compressFile(file: File, zos: ZipOutputStream, dir: String) {// 拼接完整的文件路径名称val fullName = dir + file.name// app/build/outputs/apk/debug/unZipFile 路径val fileNames = fullName.split("/").toTypedArray()// 正确的文件目录名 val sb = StringBuffer()if (fileNames.size > 1) {for (i in 1 until fileNames.size) {sb.append("/")sb.append(fileNames[i])}} else {sb.append("/")}// 添加 zip 条目val entry = ZipEntry(sb.substring(1))zos.putNextEntry(entry)// 读取 zip 条目输出到文件中val fis = FileInputStream(file)var len: Intval data = ByteArray(2048)while (fis.read(data, 0, 2048).also { len = it } != -1) {zos.write(data, 0, len)}fis.close()zos.closeEntry()
}

六、执行结果


下图中 红色矩形框 中是 解压后的 apk 文件 ,

紫色矩形框 中的 secret-classes.dex 文件是加密后的 dex 文件 ,

蓝色矩形框 中是生成的 未签名的 apk 文件 ;

【Android 安全】DEX 加密 ( Java 工具开发 | 解压 apk 文件 | 加密生成 dex 文件 | 打包未签名 apk 文件 | 文件解压缩相关代码 )相关推荐

  1. 【Android 安全】DEX 加密 ( Java 工具开发 | apk 文件签名 )

    文章目录 一.生成 jks 文件 二.签名命令 三.执行结果 四.处理 Unsupported major.minor version 52.0 错误 参考博客 : [Android 安全]DEX 加 ...

  2. 【Android 安全】DEX 加密 ( Java 工具开发 | apk 文件对齐 )

    文章目录 一.apk 对齐操作 二.apk 对齐命令 三.apk 对齐操作代码示例 四.apk 对齐执行结果 参考博客 : [Android 安全]DEX 加密 ( 常用 Android 反编译工具 ...

  3. 【Android 安全】DEX 加密 ( Java 工具开发 | 加密解密算法 API | 编译代理 Application 依赖库 | 解压依赖库 aar 文件 )

    文章目录 一.加密解密算法 API 二.编译代理 Application 依赖库 三.解压代理 Application 依赖库 aar 文件 参考博客 : [Android 安全]DEX 加密 ( 常 ...

  4. 【Android 安全】DEX 加密 ( Java 工具开发 | 生成 dex 文件 | Java 命令行执行 )

    文章目录 一.生成 dex 文件 二.生成 dex 文件代码示例 三.生成 dex 结果 参考博客 : [Android 安全]DEX 加密 ( 常用 Android 反编译工具 | apktool ...

  5. 【Android 安全】DEX 加密 ( 代理 Application 开发 | 解压 apk 文件 | 判定是否是第一次启动 | 递归删除文件操作 | 解压 Zip 文件操作 )

    文章目录 一.判定是否是第一次启动 二.递归删除文件操作 三.解压 Zip 文件操作 四.解压操作相关代码 参考博客 : [Android 安全]DEX 加密 ( 常用 Android 反编译工具 | ...

  6. Linux之zip加密压缩与解密解压(一百二十一)

    Linux之zip加密压缩与解密解压 1.zip加密压缩目录 # zip -rP Abc#123 tmp.zip test/2.unzip解密解压缩 # unzip -P Abc#123 tmp.zi ...

  7. [原创]Android Monkey 在线日志分析工具开发

    [原创]Android Monkey 在线日志分析工具开发 在移动App测试过程中,Monkey测试是我们发现潜在问题的一种非常有效手段,但是Android原生的Monkey有其天然的不足,数据不能有 ...

  8. 工具类:(一) java压缩与解压

    工具类:(一) java压缩与解压 本工具类采用的是java.util包下的Deflater进行压缩,以及Inflater进行解压, 适用于程序中需要通过远程接口调用发送或接收数据时: /*** 压缩 ...

  9. Jva编解码,加密工具类大全(Base64编解码,URL 编解码,sha56_Hmac加密,MD5对字符串进行加密,java自带类实现SHA-256方式加密)

    Base64编解码 /*** Base64编码.*/public static String encodeBase64(byte[] input) {return new String(Base64. ...

最新文章

  1. java中利用反射创建对象,利用java反射机制动态创建对象
  2. mxnet基础到提高(4)-- Dense层基础
  3. python判断题题库大数据技术_智慧树_大数据分析的python基础_搜题公众号
  4. dbname, instance, sid
  5. java怎么从数据库中查询_java – 从数据库中检索的实体与查询中的情况相同
  6. C#中的Json的序列化和反序列化
  7. Windows C盘格式化或者同平台迁移oracle数据库
  8. 2022考研-高等数学教程
  9. CTF攻防世界刷题51-
  10. 关闭计算机主机还亮着,计算机关闭后,主机电源指示灯仍然亮起
  11. linux img工具,线刷包img提取工具(simg2img win)
  12. ASP.NET 安全认证(一)—— 如何运用 Form 表单认证 (摘自 http://blog.csdn.net/cityhunter172)
  13. html采集电脑信息,网页数据采集入门词汇介绍 - 八爪鱼采集器
  14. excel相乘再相加_excel现乘积再求和如何自动生成
  15. C语言例题5: 三角形周长面积
  16. 无尘间手把手教你西数开盘
  17. Guid的生成和数据修整(去除空格和小写字符)
  18. Javascript中undefined和not defined有什么区别?
  19. 应届生和往届生,谁更容易考研成功?
  20. Android系统 应用图标显示未读消息数(BadgeNumber) 桌面app图标的角标显示

热门文章

  1. 第21章:MongoDB-聚合操作--聚合管道--$geoNear
  2. win7+centos7.2双系统安装
  3. SQL Server - 使用 Merge 语句实现表数据之间的对比同步
  4. oracle数据库访问order by不起作用分析
  5. Android 透明度百分比对应的 十六进制
  6. Django中载入js和css文件
  7. 产品经理提升修炼的方法
  8. U盘安装Linux CentOS 6.5 64位操作系统(来自互联网)
  9. Javascript、Jquery获取浏览器和屏幕各种高度宽度[mark]
  10. python--输出spwm的数组