【Android 逆向】Dalvik 函数抽取加壳 ( 类加载流程分析 | DexPathList#findClass 函数分析 | DexFile#loadClassBinaryName 函数 )

简介: 【Android 逆向】Dalvik 函数抽取加壳 ( 类加载流程分析 | DexPathList#findClass 函数分析 | DexFile#loadClassBinaryName 函数 )

文章目录

前言

一、DexPathList.java#findClass 类加载函数源码分析

二、DexFile.java#loadClassBinaryName 函数源码分析

前言


上一篇博客 【Android 逆向】Dalvik 函数抽取加壳 ( 类加载流程分析 | ClassLoader#loadClass 函数分析 | BaseDexClassLoader#findClass 分析 ) 分析到 , 类加载流程中 , 在 BaseDexClassLoader 中的 findClass 方法中 , 主要调用 DexPathList pathList 成员的 findClass 函数查找类 ;






一、DexPathList.java#findClass 类加载函数源码分析


在 DexPathList.java#findClass 方法中 ,


首先 , 遍历 Element[] dexElements 成员 , 每个 Element 元素都封装了一个 DexFile , 即 dex 文件 ;


DexFile dex = element.dexFile;


然后尝试从 dex 文件中加载 Java 类 ;


Class clazz = dex.loadClassBinaryName(name, definingContext, suppressed);



DexPathList.java#findClass 类加载函数源码 :


/**
 * 一对条目列表,与{@code ClassLoader}关联。
 * 其中一个列表是索引/资源路径—通常提及
 * 作为“类路径”—列表和其他名称目录
 * 包含本机代码库。类路径条目可以是以下任一项:
 * 一个{@code.jar}或{@code.zip}文件,其中包含一个可选的
 * 顶级{@code classes.dex}文件以及任意资源,
 * 或者是一个普通的{@code.dex}文件(不可能与
 * 资源)。
 * 
 * <p>此类还包含使用这些列表进行查找的方法
 * 课程和资源</p>
 */
/*package*/ final class DexPathList {
  /**
  * 索引/资源(类路径)元素的列表。
  * 应该称为pathElements,但Facebook应用程序使用反射
  * 要修改“dexElements”(http://b/7726934).
  */
    private final Element[] dexElements;
  /**
  * 在所指向的某个dex文件中查找命名类
  * 这个例子。这将在最早的列表中找到一个
  * 路径元素。如果已找到类但尚未找到
  * 已定义,则此方法将在定义中定义它
  * 构造此实例时使用的上下文。
  * 
  * @param要查找的类的名称
  * @param查找类时遇到抑制异常
  * @返回已命名的类或{@code null}(如果该类不是空的)
  * 在任何dex文件中找到
  */
    public Class findClass(String name, List<Throwable> suppressed) {
      // 对 DexPathList 中的 Element 数组进行遍历 
        for (Element element : dexElements) {
          // 每个 Element 元素都封装了一个 DexFile , 即 dex 文件
            DexFile dex = element.dexFile;
            if (dex != null) {
              // 尝试从 dex 文件中加载 Java 类 
              // ★ 核心跳转
                Class clazz = dex.loadClassBinaryName(name, definingContext, suppressed);
                if (clazz != null) {
                    return clazz;
                }
            }
        }
        if (dexElementsSuppressedExceptions != null) {
            suppressed.addAll(Arrays.asList(dexElementsSuppressedExceptions));
        }
        return null;
    }
}


源码路径 : /libcore/dalvik/src/main/java/dalvik/system/DexPathList.java#findClass






二、DexFile.java#loadClassBinaryName 函数源码分析


在 DexFile.java#loadClassBinaryName 函数中 , 调用了 defineClass 方法 , 在 defineClass 方法中 , 调用了 native 函数 defineClassNative ;



在 DexFile.java 的 loadClass 函数中 , 也会调用 DexFile.java#loadClassBinaryName 函数 , 进行类的加载 ;



DexFile.java#loadClassBinaryName 函数源码 :


/**
 * 操纵DEX文件。这门课在原则上与我们的课相似
 * {@link java.util.zip.ZipFile}。它主要由类装入器使用。
 * <p>
 * 注意,我们不直接打开并读取这里的DEX文件。它们是内存映射的
 * 由VM只读。
 */
public final class DexFile {
  /**
  * 加载一个类。成功返回类或{@code null}引用
  * 一旦失败。
  * <p>
  * 如果不是从类加载器调用此函数,则很可能不是
  * 去做你想做的事。改用{@link Class#forName(String)}。
  * <p>
  * 如果类
  * 找不到,因为在每个
  * 在我们查看的第一个DEX文件中找不到类的时间。
  * 
  * @param name
  * 类名,看起来应该像“java/lang/String”
  * 
  * @param装载机
  * 尝试加载类的类加载器(在大多数情况下
  * 方法的调用方
  * 
  * @返回表示类的{@link Class}对象,或{@code null}
  * 如果无法加载该类
  */
    public Class loadClass(String name, ClassLoader loader) {
        String slashName = name.replace('.', '/');
        return loadClassBinaryName(slashName, loader, null);
    }
  /**
  * 请参阅{@link#loadClass(String,ClassLoader)}。
  * 
  * 这需要一个“二进制”类名来更好地匹配类加载器语义。
  * 
  * @隐藏
  */
    public Class loadClassBinaryName(String name, ClassLoader loader, List<Throwable> suppressed) {
        return defineClass(name, loader, mCookie, suppressed);
    }
    private static Class defineClass(String name, ClassLoader loader, int cookie,
                                     List<Throwable> suppressed) {
        Class result = null;
        try {
            result = defineClassNative(name, loader, cookie);
        } catch (NoClassDefFoundError e) {
            if (suppressed != null) {
                suppressed.add(e);
            }
        } catch (ClassNotFoundException e) {
            if (suppressed != null) {
                suppressed.add(e);
            }
        }
        return result;
    }
  // ★ 核心跳转
    private static native Class defineClassNative(String name, ClassLoader loader, int cookie)
        throws ClassNotFoundException, NoClassDefFoundError;
}


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


目录
相关文章
|
19天前
|
安全 Android开发 数据安全/隐私保护
深入探讨iOS与Android系统安全性对比分析
在移动操作系统领域,iOS和Android无疑是两大巨头。本文从技术角度出发,对这两个系统的架构、安全机制以及用户隐私保护等方面进行了详细的比较分析。通过深入探讨,我们旨在揭示两个系统在安全性方面的差异,并为用户提供一些实用的安全建议。
|
27天前
|
缓存 Java Shell
Android 系统缓存扫描与清理方法分析
Android 系统缓存从原理探索到实现。
52 15
Android 系统缓存扫描与清理方法分析
|
30天前
|
Android开发
Android面试之Activity启动流程简述
Android面试之Activity启动流程简述
76 6
|
28天前
|
XML 前端开发 Android开发
Android面试高频知识点(3) 详解Android View的绘制流程
Android面试高频知识点(3) 详解Android View的绘制流程
Android面试高频知识点(3) 详解Android View的绘制流程
|
1月前
|
消息中间件 Android开发 索引
Android面试高频知识点(4) 详解Activity的启动流程
Android面试高频知识点(4) 详解Activity的启动流程
26 3
|
1月前
|
Android开发
Android面试之Activity启动流程简述
Android面试之Activity启动流程简述
18 0
|
4天前
|
开发框架 前端开发 Android开发
安卓与iOS开发中的跨平台策略
在移动应用开发的战场上,安卓和iOS两大阵营各据一方。随着技术的演进,跨平台开发框架成为开发者的新宠,旨在实现一次编码、多平台部署的梦想。本文将探讨跨平台开发的优势与挑战,并分享实用的开发技巧,帮助开发者在安卓和iOS的世界中游刃有余。
|
10天前
|
搜索推荐 Android开发 开发者
探索安卓开发中的自定义视图:打造个性化UI组件
【10月更文挑战第39天】在安卓开发的世界中,自定义视图是实现独特界面设计的关键。本文将引导你理解自定义视图的概念、创建流程,以及如何通过它们增强应用的用户体验。我们将从基础出发,逐步深入,最终让你能够自信地设计和实现专属的UI组件。
|
11天前
|
Android开发 Swift iOS开发
探索安卓与iOS开发的差异和挑战
【10月更文挑战第37天】在移动应用开发的广阔舞台上,安卓和iOS这两大操作系统扮演着主角。它们各自拥有独特的特性、优势以及面临的开发挑战。本文将深入探讨这两个平台在开发过程中的主要差异,从编程语言到用户界面设计,再到市场分布的不同影响,旨在为开发者提供一个全面的视角,帮助他们更好地理解并应对在不同平台上进行应用开发时可能遇到的难题和机遇。
|
14天前
|
XML 存储 Java
探索安卓开发之旅:从新手到专家
【10月更文挑战第35天】在数字化时代,安卓应用的开发成为了一个热门话题。本文旨在通过浅显易懂的语言,带领初学者了解安卓开发的基础知识,同时为有一定经验的开发者提供进阶技巧。我们将一起探讨如何从零开始构建第一个安卓应用,并逐步深入到性能优化和高级功能的实现。无论你是编程新手还是希望提升技能的开发者,这篇文章都将为你提供有价值的指导和灵感。