文章目录
参考博客 :
- 【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 加密 ( 支持多 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 ;
本博客中主要讲解 dex 文件加载操作 第二阶段 , 创建本应用的 dex 文件数组 Element[] dexElements ;
一、不同 Android 系统创建 dex 数组源码对比
A n d r o i d 4.4 ( K i t K a t A P I 19 ) \rm Android \ 4.4 \ ( KitKat \ API \ 19 ) Android 4.4 (KitKat API 19) 系统中创建 Element[] dexElements 的方法 :
/*package*/ final class DexPathList {
private Element[] dexElements;
public DexPathList(ClassLoader definingContext, String dexPath,
String libraryPath, File optimizedDirectory) {
this.dexElements = makeDexElements(splitDexPath(dexPath), optimizedDirectory,
suppressedExceptions);
}
/**
* 创建一个数组 , 每个数组元素都是 dex 路径名称 .
*/
private static Element[] makeDexElements(ArrayList<File> files, File optimizedDirectory,
ArrayList<IOException> suppressedExceptions) {
}
}
参考 : 4.4.4_r1/xref/libcore/dalvik/src/main/java/dalvik/system/DexPathList.java
A n d r o i d 4.4 W ( K i t K a t W a t c h A P I 20 ) \rm Android \ 4.4W \ ( KitKat Watch \ API \ 20 ) Android 4.4W (KitKatWatch API 20) 系统中创建 Element[] dexElements 的方法 :
/*package*/ final class DexPathList {
private Element[] dexElements;
public DexPathList(ClassLoader definingContext, String dexPath,
String libraryPath, File optimizedDirectory) {
this.dexElements = makeDexElements(splitDexPath(dexPath), optimizedDirectory,
suppressedExceptions);
}
/**
* 创建一个数组 , 每个数组元素都是 dex 路径名称 .
*/
private static Element[] makeDexElements(ArrayList<File> files, File optimizedDirectory,
ArrayList<IOException> suppressedExceptions){
}
}
参考 : 4.4w_r1/xref/libcore/dalvik/src/main/java/dalvik/system/DexPathList.java
A n d r o i d 5.0 ( L o l l i p o p A P I 21 ) \rm Android \ 5.0 \ ( Lollipop \ API \ 21 ) Android 5.0 (Lollipop API 21) 系统中创建 Element[] dexElements 的方法 :
/*package*/ final class DexPathList {
private Element[] dexElements;
public DexPathList(ClassLoader definingContext, String dexPath,
String libraryPath, File optimizedDirectory) {
this.dexElements = makeDexElements(splitDexPath(dexPath), optimizedDirectory,
suppressedExceptions);
}
/**
* 创建一个数组 , 每个数组元素都是 dex 路径名称 .
*/
private static Element[] makeDexElements(ArrayList<File> files, File optimizedDirectory,
ArrayList<IOException> suppressedExceptions){
}
}
参考 : 5.0.1_r1/xref/libcore/dalvik/src/main/java/dalvik/system/DexPathList.java
A n d r o i d 5.1 ( L o l l i p o p A P I 22 ) \rm Android \ 5.1 \ ( Lollipop \ API \ 22 ) Android 5.1 (Lollipop API 22) 系统中创建 Element[] dexElements 的方法 :
/*package*/ final class DexPathList {
private Element[] dexElements;
public DexPathList(ClassLoader definingContext, String dexPath,
String libraryPath, File optimizedDirectory) {
this.dexElements = makeDexElements(splitDexPath(dexPath), optimizedDirectory,
suppressedExceptions);
}
/**
* 创建一个数组 , 每个数组元素都是 dex 路径名称 .
*/
private static Element[] makeDexElements(ArrayList<File> files, File optimizedDirectory,
ArrayList<IOException> suppressedExceptions){
}
}
参考 : 5.1.0_r3/xref/libcore/dalvik/src/main/java/dalvik/system/DexPathList.java
A n d r o i d 6.0 ( M a r s h m a l l o w A P I 23 ) \rm Android \ 6.0 \ (Marshmallow \ API \ 23 ) Android 6.0 (Marshmallow API 23) 系统中创建 Element[] dexElements 的方法 :
/*package*/ final class DexPathList {
private Element[] dexElements;
public DexPathList(ClassLoader definingContext, String dexPath,
String libraryPath, File optimizedDirectory) {
// save dexPath for BaseDexClassLoader
this.dexElements = makePathElements(splitDexPath(dexPath), optimizedDirectory,
suppressedExceptions);
}
/**
* 创建一个数组 , 每个数组元素都是 dex 路径名称 .
*/
private static Element[] makePathElements(List<File> files, File optimizedDirectory,
List<IOException> suppressedExceptions) {
}
}
参考 : 6.0.1_r16/xref/libcore/dalvik/src/main/java/dalvik/system/DexPathList.java
A n d r o i d 7.0 ( N o u g a t A P I 24 ) \rm Android \ 7.0 \ ( Nougat \ API \ 24 ) Android 7.0 (Nougat API 24) 系统中创建 Element[] dexElements 的方法 :
/*package*/ final class DexPathList {
private Element[] dexElements;
public DexPathList(ClassLoader definingContext, String dexPath,
String librarySearchPath, File optimizedDirectory) {
// save dexPath for BaseDexClassLoader
this.dexElements = makeDexElements(splitDexPath(dexPath), optimizedDirectory,
suppressedExceptions, definingContext);
}
private static Element[] makeDexElements(List<File> files, File optimizedDirectory,
List<IOException> suppressedExceptions,
ClassLoader loader) {
}
/**
* Makes an array of directory/zip path elements, one per element of the given array.
*/
private static Element[] makePathElements(List<File> files,
List<IOException> suppressedExceptions,
ClassLoader loader) {
return makeElements(files, null, suppressedExceptions, true, loader);
}
/*
* TODO (dimitry): Revert after apps stops relying on the existence of this
* method (see http://b/21957414 and http://b/26317852 for details)
*/
private static Element[] makePathElements(List<File> files, File optimizedDirectory,
List<IOException> suppressedExceptions) {
return makeElements(files, optimizedDirectory, suppressedExceptions, false, null);
}
}
参考 : 7.0.0_r31/xref/libcore/dalvik/src/main/java/dalvik/system/DexPathList.java
A n d r o i d 7.1 ( N o u g a t A P I 25 ) \rm Android \ 7.1 \ ( Nougat \ API \ 25 ) Android 7.1 (Nougat API 25) 系统中创建 Element[] dexElements 的方法 :
/*package*/ final class DexPathList {
private Element[] dexElements;
public DexPathList(ClassLoader definingContext, String dexPath,
String librarySearchPath, File optimizedDirectory) {
// save dexPath for BaseDexClassLoader
this.dexElements = makeDexElements(splitDexPath(dexPath), optimizedDirectory,
suppressedExceptions, definingContext);
}
private static Element[] makeDexElements(List<File> files, File optimizedDirectory,
List<IOException> suppressedExceptions,
ClassLoader loader) {
}
/**
* Makes an array of directory/zip path elements, one per element of the given array.
*/
private static Element[] makePathElements(List<File> files,
List<IOException> suppressedExceptions,
ClassLoader loader) {
return makeElements(files, null, suppressedExceptions, true, loader);
}
/*
* TODO (dimitry): Revert after apps stops relying on the existence of this
* method (see http://b/21957414 and http://b/26317852 for details)
*/
private static Element[] makePathElements(List<File> files, File optimizedDirectory,
List<IOException> suppressedExceptions) {
return makeElements(files, optimizedDirectory, suppressedExceptions, false, null);
}
}
参考 : 7.1.1_r28/xref/libcore/dalvik/src/main/java/dalvik/system/DexPathList.java
A n d r o i d 8.0 ( O r e o A P I 25 ) \rm Android \ 8.0 \ ( Oreo \ API \ 25 ) Android 8.0 (Oreo API 25) 系统中创建 Element[] dexElements 的方法 :
/*package*/ final class DexPathList {
private Element[] dexElements;
public DexPathList(ClassLoader definingContext, String dexPath,
String librarySearchPath, File optimizedDirectory) {
// save dexPath for BaseDexClassLoader
this.dexElements = makeDexElements(splitDexPath(dexPath), optimizedDirectory,
suppressedExceptions, definingContext);
}
private static Element[] makeDexElements(List<File> files, File optimizedDirectory,
List<IOException> suppressedExceptions,
ClassLoader loader) {
}
/*
* TODO (dimitry): Revert after apps stops relying on the existence of this
* method (see http://b/21957414 and http://b/26317852 for details)
*/
@SuppressWarnings("unused")
private static Element[] makePathElements(List<File> files, File optimizedDirectory,
List<IOException> suppressedExceptions) {
return makeDexElements(files, optimizedDirectory, suppressedExceptions, null);
}
/**
* Makes an array of directory/zip path elements for the native library search path, one per
* element of the given array.
*/
private static NativeLibraryElement[] makePathElements(List<File> files) {
}
}
参考 : 8.0.0_r4/xref/libcore/dalvik/src/main/java/dalvik/system/DexPathList.java
A n d r o i d 9.0 ( P i e A P I 28 ) \rm Android \ 9.0 \ ( Pie \ API \ 28 ) Android 9.0 (Pie API 28) 系统中创建 Element[] dexElements 的方法 :
/*package*/ final class DexPathList {
private Element[] dexElements;
public DexPathList(ClassLoader definingContext, String dexPath,
String librarySearchPath, File optimizedDirectory) {
// save dexPath for BaseDexClassLoader
this.dexElements = makeDexElements(splitDexPath(dexPath), optimizedDirectory,
suppressedExceptions, definingContext, isTrusted);
}
/**
* Makes an array of dex/resource path elements, one per element of
* the given array.
*/
private static Element[] makeDexElements(List<File> files, File optimizedDirectory,
List<IOException> suppressedExceptions, ClassLoader loader) {
return makeDexElements(files, optimizedDirectory, suppressedExceptions, loader, false);
}
private static Element[] makeDexElements(List<File> files, File optimizedDirectory,
List<IOException> suppressedExceptions, ClassLoader loader, boolean isTrusted) {
}
/*
* TODO (dimitry): Revert after apps stops relying on the existence of this
* method (see http://b/21957414 and http://b/26317852 for details)
*/
@SuppressWarnings("unused")
private static Element[] makePathElements(List<File> files, File optimizedDirectory,
List<IOException> suppressedExceptions) {
return makeDexElements(files, optimizedDirectory, suppressedExceptions, null);
}
/**
* Makes an array of directory/zip path elements for the native library search path, one per
* element of the given array.
*/
private static NativeLibraryElement[] makePathElements(List<File> files) {
}
}
参考 : 9.0.0_r8/xref/libcore/dalvik/src/main/java/dalvik/system/DexPathList.java
A n d r o i d 10.0 ( Q A P I 29 ) \rm Android \ 10.0 \ ( Q \ API \ 29 ) Android 10.0 (Q API 29) 系统中创建 Element[] dexElements 的方法 :
/*package*/ final class DexPathList {
private Element[] dexElements;
DexPathList(ClassLoader definingContext, String dexPath,
String librarySearchPath, File optimizedDirectory, boolean isTrusted) {
// save dexPath for BaseDexClassLoader
this.dexElements = makeDexElements(splitDexPath(dexPath), optimizedDirectory,
suppressedExceptions, definingContext, isTrusted);
}
/**
* Makes an array of dex/resource path elements, one per element of
* the given array.
*/
@UnsupportedAppUsage
private static Element[] makeDexElements(List<File> files, File optimizedDirectory,
List<IOException> suppressedExceptions, ClassLoader loader) {
return makeDexElements(files, optimizedDirectory, suppressedExceptions, loader, false);
}
private static Element[] makeDexElements(List<File> files, File optimizedDirectory,
List<IOException> suppressedExceptions, ClassLoader loader, boolean isTrusted) {
}
/*
* TODO (dimitry): Revert after apps stops relying on the existence of this
* method (see http://b/21957414 and http://b/26317852 for details)
*/
@UnsupportedAppUsage
@SuppressWarnings("unused")
private static Element[] makePathElements(List<File> files, File optimizedDirectory,
List<IOException> suppressedExceptions) {
return makeDexElements(files, optimizedDirectory, suppressedExceptions, null);
}
/**
* Makes an array of directory/zip path elements for the native library search path, one per
* element of the given array.
*/
@UnsupportedAppUsage
private static NativeLibraryElement[] makePathElements(List<File> files) {
}
}
参考 : 10.0.0_r6/xref/libcore/dalvik/src/main/java/dalvik/system/DexPathList.java
二、不同 Android 系统创建 dex 数组源码对比
A n d r o i d 5.0 、 5.1 \rm Android \ 5.0 、 5.1 Android 5.0、5.1 系统需要反射如下 makeDexElements 方法 ;
private static Element[] makeDexElements(ArrayList<File> files, File optimizedDirectory,
ArrayList<IOException> suppressedExceptions){
}
A n d r o i d 6.0 、 7.1 、 7.1 、 8.0 、 9.0 、 10 \rm Android \ 6.0 、 7.1、7.1、8.0、9.0、10 Android 6.0、7.1、7.1、8.0、9.0、10 系统需要反射如下 makePathElements 方法 ;
@SuppressWarnings("unused")
private static Element[] makePathElements(List<File> files, File optimizedDirectory,
List<IOException> suppressedExceptions) {
return makeDexElements(files, optimizedDirectory, suppressedExceptions, null);
}
三、 Android 5.1 及以下系统反射方法并创建 Element[] dexElements
Android 5.1 及以下系统反射方法并创建 Element[] dexElements :
if(Build.VERSION.SDK_INT <=
Build.VERSION_CODES.LOLLIPOP_MR1){ // 5.0, 5.1 makeDexElements
// 反射 5.0, 5.1, 6.0 版本的 DexPathList 中的 makeDexElements 方法
makeDexElements = reflexMethod(pathList, "makeDexElements",
ArrayList::class.java, File::class.java, ArrayList::class.java)
var suppressedExceptions: ArrayList<IOException> = ArrayList<IOException>()
addElements = makeDexElements.invoke(pathList, dexFiles,
optimizedDirectory,
suppressedExceptions) as Array<Any>
}
四、 Android 6.0 及以下系统反射方法并创建 Element[] dexElements
Android 6.0 及以下系统反射方法并创建 Element[] dexElements :
}else if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M){ // 7.0 以上版本 makePathElements
// 反射 7.0 以上版本的 DexPathList 中的 makeDexElements 方法
makeDexElements = reflexMethod(pathList, "makePathElements",
ArrayList::class.java, File::class.java, ArrayList::class.java)
var suppressedExceptions: ArrayList<IOException> = ArrayList<IOException>()
addElements = makeDexElements.invoke(pathList, dexFiles,
optimizedDirectory,
suppressedExceptions) as Array<Any>
}
五、 完整代码示例
/*
2 . 在本应用中创建 Element[] dexElements 数组 , 用于存放解密后的 dex 文件
不同的 Android 版本中 , 创建 Element[] dexElements 数组的方法不同 , 这里需要做兼容
*/
var makeDexElements: Method
var addElements : Array<Any>
if(Build.VERSION.SDK_INT <=
Build.VERSION_CODES.LOLLIPOP_MR1){ // 5.0, 5.1 makeDexElements
// 反射 5.0, 5.1, 6.0 版本的 DexPathList 中的 makeDexElements 方法
makeDexElements = reflexMethod(pathList, "makeDexElements",
ArrayList::class.java, File::class.java, ArrayList::class.java)
var suppressedExceptions: ArrayList<IOException> = ArrayList<IOException>()
addElements = makeDexElements.invoke(pathList, dexFiles,
optimizedDirectory,
suppressedExceptions) as Array<Any>
}else if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M){ // 7.0 以上版本 makePathElements
// 反射 7.0 以上版本的 DexPathList 中的 makeDexElements 方法
makeDexElements = reflexMethod(pathList, "makePathElements",
ArrayList::class.java, File::class.java, ArrayList::class.java)
var suppressedExceptions: ArrayList<IOException> = ArrayList<IOException>()
addElements = makeDexElements.invoke(pathList, dexFiles,
optimizedDirectory,
suppressedExceptions) as Array<Any>
}