Android 逆向整体加固脱壳 ( DexClassLoader 加载 dex 流程分析 | DexPathList 构造函数分析 | makeDexElements 函数分析 )
Posted 韩曙亮
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android 逆向整体加固脱壳 ( DexClassLoader 加载 dex 流程分析 | DexPathList 构造函数分析 | makeDexElements 函数分析 )相关的知识,希望对你有一定的参考价值。
前言
上一篇博客 【Android 逆向】整体加固脱壳 ( DexClassLoader 加载 dex 流程分析 | 类加载器构造函数分析 | DexPathList 引入 ) 中 , 分析了 DexClassLoader 构造函数的调用流程 , 在构造函数中执行的核心操作就是 在 BaseDexClassLoader 的构造函数中 初始化了 DexPathList 实例对象 ;
本篇博客中重点分析 DexPathList
;
一、DexPathList 构造函数分析
在 DexPathList 构造函数中 , 主要是调用了 makeDexElements()
方法 , 该方法返回 Element[]
数组元素 , 赋值给 private final Element[] dexElements
成员 ;
/*package*/ final class DexPathList
/**
* List of dex/resource (class path) elements.
* Should be called pathElements, but the Facebook app uses reflection
* to modify 'dexElements' (http://b/7726934).
*/
private final Element[] dexElements;
/**
* Constructs an instance.
*
* @param definingContext the context in which any as-yet unresolved
* classes should be defined
* @param dexPath list of dex/resource path elements, separated by
* @code File.pathSeparator
* @param libraryPath list of native library directory path elements,
* separated by @code File.pathSeparator
* @param optimizedDirectory directory where optimized @code .dex files
* should be found and written to, or @code null to use the default
* system directory for same
*/
public DexPathList(ClassLoader definingContext, String dexPath,
String libraryPath, File optimizedDirectory)
// 下面的代码 主要是对 参数合法性判断
if (definingContext == null)
throw new NullPointerException("definingContext == null");
if (dexPath == null)
throw new NullPointerException("dexPath == null");
if (optimizedDirectory != null)
if (!optimizedDirectory.exists())
throw new IllegalArgumentException(
"optimizedDirectory doesn't exist: "
+ optimizedDirectory);
if (!(optimizedDirectory.canRead()
&& optimizedDirectory.canWrite()))
throw new IllegalArgumentException(
"optimizedDirectory not readable/writable: "
+ optimizedDirectory);
// 上述代码是对参数合法性判断
this.definingContext = definingContext;
ArrayList<IOException> suppressedExceptions = new ArrayList<IOException>();
// 核心逻辑
// 调用 makeDexElements 方法 , 传入
this.dexElements = makeDexElements(splitDexPath(dexPath), optimizedDirectory,
suppressedExceptions);
if (suppressedExceptions.size() > 0)
this.dexElementsSuppressedExceptions =
suppressedExceptions.toArray(new IOException[suppressedExceptions.size()]);
else
dexElementsSuppressedExceptions = null;
this.nativeLibraryDirectories = splitLibraryPath(libraryPath);
源码路径 : /libcore/dalvik/src/main/java/dalvik/system/DexPathList.java
二、DexPathList.makeDexElements 函数分析
DexPathList.makeDexElements 函数中 , 主要返回了一个 Element[]
数组 ; Element
是 DexPathList
的内部类 ;
/*package*/ final class DexPathList
/**
* Makes an array of dex/resource path elements, one per element of
* the given array.
*/
private static Element[] makeDexElements(ArrayList<File> files, File optimizedDirectory,
ArrayList<IOException> suppressedExceptions)
// 创建要返回的 Element 数组对应的集合
ArrayList<Element> elements = new ArrayList<Element>();
/*
* 打开并加载 dex 文件
* up front.
*/
for (File file : files)
File zip = null;
DexFile dex = null;
String name = file.getName();
if (name.endsWith(DEX_SUFFIX)) // .dex 后缀
// dex 后缀是 .dex , 进入该分支
// Raw dex file (not inside a zip/jar).
try
// 从文件中加载 dex
dex = loadDexFile(file, optimizedDirectory);
catch (IOException ex)
System.logE("Unable to load dex file: " + file, ex);
else if (name.endsWith(APK_SUFFIX) || name.endsWith(JAR_SUFFIX)
|| name.endsWith(ZIP_SUFFIX))
// .apk , .jar , .zip 后缀 , 命中该分支
zip = file;
try
dex = loadDexFile(file, optimizedDirectory);
catch (IOException suppressed)
/*
* IOException might get thrown "legitimately" by the DexFile constructor if the
* zip file turns out to be resource-only (that is, no classes.dex file in it).
* Let dex == null and hang on to the exception to add to the tea-leaves for
* when findClass returns null.
*/
suppressedExceptions.add(suppressed);
else if (file.isDirectory())
// We support directories for looking up resources.
// This is only useful for running libcore tests.
elements.add(new Element(file, true, null, null));
else
System.logW("Unknown file type for: " + file);
if ((zip != null) || (dex != null))
// 调用完毕后 , 如果获取的 DexFile 不为空 , 创建 Element 对象 , 并加入到 ArrayList 集合中
elements.add(new Element(file, false, zip, dex));
return elements.toArray(new Element[elements.size()]);
源码路径 : /libcore/dalvik/src/main/java/dalvik/system/DexPathList.java
三、Element 类分析
Element 类是 DexPathList 的内部类 , 其第一个成员变量就是 private final File file
, 这个就是 dex 文件类 ;
/*package*/ final class DexPathList
/**
* Element of the dex/resource file path
*/
/*package*/ static class Element
private final File file;
private final boolean isDirectory;
private final File zip;
private final DexFile dexFile;
private ZipFile zipFile;
private boolean initialized;
public Element(File file, boolean isDirectory, File zip, DexFile dexFile)
this.file = file;
this.isDirectory = isDirectory;
this.zip = zip;
this.dexFile = dexFile;
以上是关于Android 逆向整体加固脱壳 ( DexClassLoader 加载 dex 流程分析 | DexPathList 构造函数分析 | makeDexElements 函数分析 )的主要内容,如果未能解决你的问题,请参考以下文章
Android 逆向整体加固脱壳 ( DEX 优化流程分析 | DexPrepare.cpp 中 dvmContinueOptimizati() 函数分析 )
Android 逆向整体加固脱壳 ( DEX 优化流程分析 | dvmDexFileOpenPartial | dexFileParse | 脱壳点 | 获取 dex 文件在内存中的首地址 )(代码片
Android 逆向整体加固脱壳 ( DexClassLoader 加载 dex 流程分析 | DexPathList 构造函数分析 | makeDexElements 函数分析 )
Android 逆向整体加固脱壳 ( DexClassLoader 加载 dex 流程分析 | DexFile loadDexFile 函数 | 构造函数 | openDexFile 函数 )(代码片
Android 逆向整体加固脱壳 ( DexClassLoader 加载 dex 流程分析 | DexPathList 中根据 File 加载 DexFile | loadDexFile 分析 )(代
Android 逆向整体加固脱壳 ( DexClassLoader 加载 dex 流程分析 | RawDexFile.cpp 分析 | dvmRawDexFileOpen函数读取 DEX 文件 )(代