文章目录

前言一、DexFile.loadDexFile 函数分析二、DexFile 构造函数分析三、DexFile.openDexFile 函数分析

前言


上一篇博客 【Android 逆向】整体加固脱壳 ( DexClassLoader 加载 dex 流程分析 | DexPathList 中根据 File 加载 DexFile | loadDexFile 分析 )​ 中 , 介绍了 DexPathList 中通过 File 生成 DexFile 的源码 , 在 makeDexElements 中调用了 loadDexFile 方法 , 在 loadDexFile 又有调用了 DexFile.loadDexFile 函数 , 用于生成 DexFile 实例对象 ;

本博客中介绍 DexFile 相关源码 ;

一、DexFile.loadDexFile 函数分析


在 DexPathList.loadDexFile​ 方法中 , 调用 DexFile​ 构造函数创建了 DexFile 实例对象 ;

下面的代码中 , 列出了 loadDexFile 方法 ;

传入的参数分别是 Dex 文件的路径 , 优化后的 Dex 文件路径 , 标志位 , 一般是 0 ;

/**
* 操纵DEX文件。这门课在原则上与我们的课相似
* {@link java.util.zip.ZipFile}。它主要由类装入器使用。
* <p>
* 注意,我们不直接打开并读取这里的DEX文件。它们是内存映射的
* 由VM只读。
*/
public final class DexFile {

/**
* 打开一个DEX文件,指定优化的DEX所在的文件
* 数据应该是书面的。如果优化表单存在并出现
* 要成为最新版本,将使用它;如果没有,VM将尝试
* 再生它。
*
* 这是供希望下载的应用程序使用的
* 并在通常的应用程序安装之外执行DEX文件
* 机制。此函数不应由
* 应用;相反,使用类加载器,例如
* 达尔维克。系统DexClassLoader。
*
* @param sourcePathName
* 带有“classes.dex”的Jar或APK文件。(可将此扩展为包括
* 未来的“原始索引”。)
* @param outputPathName
* 保存优化形式的DEX数据的文件。
* @param标志
* 启用可选功能。(当前未定义任何内容。)
* @返回
* 新的或以前打开的文件。
* @抛出异常
* 如果无法打开源文件或输出文件。
*/
static public DexFile loadDex(String sourcePathName, String outputPathName,
int flags) throws IOException {

/*
* TODO:我们可能希望缓存以前打开的DexFile对象。
* 缓存将与close()同步。这会有帮助的
* 我们避免在应用程序运行时多次映射同一个索引
* 决定多次打开它。实际上,这可能不是
* 这是一个真正的问题。
*/
return new DexFile(sourcePathName, outputPathName, flags);
}
}

​源码路径 :​ /libcore/dalvik/src/main/java/dalvik/system/DexFile.java

二、DexFile 构造函数分析


在 loadDexFile​ 方法 , 调用到 DexFile 构造方法 ;

在 DexFile​ 构造方法中 , 调用了 mCookie = openDexFile(sourceName, outputName, flags); 方法打开 Dex 文件 ;

/**
* 操纵DEX文件。这门课在原则上与我们的课相似
* {@link java.util.zip.ZipFile}。它主要由类装入器使用。
* <p>
* 注意,我们不直接打开并读取这里的DEX文件。它们是内存映射的
* 由VM只读。
*/
public final class DexFile {
/**
* 使用指定文件从给定文件名打开DEX文件
* 保存优化的数据。
*
* @param sourceName
* 带有“classes.dex”的Jar或APK文件。
* @param outputName
* 保存优化形式的DEX数据的文件。
* @param标志
* 启用可选功能。
*/
private DexFile(String sourceName, String outputName, int flags) throws IOException {
if (outputName != null) {
try {
String parent = new File(outputName).getParent();
if (Libcore.os.getuid() != Libcore.os.stat(parent).st_uid) {
throw new IllegalArgumentException("Optimized data directory " + parent
+ " is not owned by the current user. Shared storage cannot protect"
+ " your application from code injection attacks.");
}
} catch (ErrnoException ignored) {
// assume we'll fail with a more contextual error later
}
}

mCookie = openDexFile(sourceName, outputName, flags);
mFileName = sourceName;
guard.open("close");
//System.out.println("DEX FILE cookie is " + mCookie);
}
}

​源码路径 :​ /libcore/dalvik/src/main/java/dalvik/system/DexFile.java

三、DexFile.openDexFile 函数分析


在 DexFile 的 openDexFile 函数中 , 调用了 native 函数 openDexFileNative , 打开 Dex 文件 , 该函数是使用 C 代码生成的 ;

/**
* 操纵DEX文件。这门课在原则上与我们的课相似
* {@link java.util.zip.ZipFile}。它主要由类装入器使用。
* <p>
* 注意,我们不直接打开并读取这里的DEX文件。它们是内存映射的
* 由VM只读。
*/
public final class DexFile {
/*
* 打开一个DEX文件。返回的值是一个神奇的VM cookie。在…上
* 失败时,将引发IOException。
*/
private static int openDexFile(String sourceName, String outputName,
int flags) throws IOException {
return openDexFileNative(new File(sourceName).getCanonicalPath(),
(outputName == null) ? null : new File(outputName).getCanonicalPath(),
flags);
}
native private static int openDexFileNative(String sourceName, String outputName,
int flags) throws IOException;
}

​源码路径 :​ /libcore/dalvik/src/main/java/dalvik/system/DexFile.java