【Android 逆向】Dalvik 函数抽取加壳 ( 类加载流程分析 | ClassLoader#loadClass 函数分析 | BaseDexClassLoader#findClass 分析 )

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

文章目录

一、ClassLoader.java#loadClass 类加载函数源码分析

二、BaseDexClassLoader.java#findClass 函数源码分析





一、ClassLoader.java#loadClass 类加载函数源码分析


分析类加载器的 双亲委派机制 ; 在 ClassLoader.java 类加载器中 , 双亲委托机制如下 :



首先 , 查看要加载的 Java 类是否已经被加载了 , 如果已经被加载 , 直接返回 ;


// 如果已经被加载了 , 则直接返回
  Class<?> clazz = findLoadedClass(className);


如果没有被加载过 , 则开始进行双亲委派 , 让父节点类加载器加载该类 ;


// 如果还没有进行加载 , 则开始双亲委派 
  if (clazz == null) {
    try {
    // 让父节点类加载器加载该类 
    clazz = parent.loadClass(className, false);
    } catch (ClassNotFoundException e) {
    // Don't want to see this.
    }


如果父类没有加载成功 , 返回空 , 这是双亲委派轮完一轮之后 , 发现父节点都没有加载成功 , 则自己开始加载 , 如果自己加载不了 , 则继续委托给子节点执行加载 ;


// 这是双亲委派轮完一轮之后 , 发现父节点都没有加载成功 
    // 则自己开始加载 
    // 如果自己加载不了 , 则继续委托给子节点执行加载
    if (clazz == null) {
    clazz = findClass(className);
    }


实际上加载类的方法是 findClass 函数 , 这是类加载过程的核心业务 ;



ClassLoader.java#loadClass 类加载函数源码 :


public abstract class ClassLoader {
  /**
  * 加载具有指定名称的类,可以选择在
  * 装载。执行以下步骤:
  * <ol>
  * <li>调用{@link#findLoadedClass(String)}以确定请求的
  * 类已加载</li>
  * <li>如果类尚未加载:在
  * 父类加载器</li>
  * <li>如果类尚未加载:调用
  * {@link#findClass(String)}查找类</li>
  * </ol>
  * <p>
  * <strong>注意:</strong>在Android参考实现中
  * {@code resolve}参数被忽略;类从不链接。
  * </p>
  * 
  * @返回{@code Class}对象。
  * @param className
  * 要查找的类的名称。
  * @param-resolve
  * 指示加载后是否应解析该类。这
  * 参数在Android参考实现中被忽略;
  * 未解析类。
  * @ClassNotFoundException
  * 如果找不到该类。
  */
  protected Class<?> loadClass(String className, boolean resolve) throws ClassNotFoundException {
  // 如果已经被加载了 , 则直接返回
  Class<?> clazz = findLoadedClass(className);
  // 如果还没有进行加载 , 则开始双亲委派 
  if (clazz == null) {
    try {
    // 让父节点类加载器加载该类 
    clazz = parent.loadClass(className, false);
    } catch (ClassNotFoundException e) {
    // Don't want to see this.
    }
    // 这是双亲委派轮完一轮之后 , 发现父节点都没有加载成功 
    // 则自己开始加载 
    // 如果自己加载不了 , 则继续委托给子节点执行加载
    if (clazz == null) {
    // ★ 核心跳转
    clazz = findClass(className);
    }
  }
  return clazz;
  }
}


源码路径 : /libcore/libdvm/src/main/java/java/lang/ClassLoader.java#loadClass






二、BaseDexClassLoader.java#findClass 函数源码分析


在类加载器中 , findClass 函数是核心业务 , 加固厂商在 Dalvik 虚拟机下 , 使用的类加载器是 DexClassLoader , 该类加载器只定义了构造函数 , findClass 函数定义在其父类 BaseDexClassLoader 中 ;


下面分析 BaseDexClassLoader 中的 findClass 方法 ;



在 BaseDexClassLoader 中的 findClass 函数中 , 主要调用了 DexPathList pathList 成员的 findClass 函数 ;


Class c = pathList.findClass(name, suppressedExceptions);



DexPathList pathList 成员在 BaseDexClassLoader 构造函数 , 即实例化时 ,


public BaseDexClassLoader(String dexPath, File optimizedDirectory,
    String libraryPath, ClassLoader parent) {
  super(parent);
  this.pathList = new DexPathList(this, dexPath, libraryPath, optimizedDirectory);
  }


就已经构造完毕 , 其中包含了所有的字节码类信息 ,



BaseDexClassLoader.java#findClass 函数源码 :


/**
 * 用于各种基于dex的数据库之间的通用功能的基类
 * {@link ClassLoader}实现。
 */
public class BaseDexClassLoader extends ClassLoader {
    private final DexPathList pathList;
  /**
  * 构造一个实例。
  * 
  * @param dexPath 包含类和
  * 资源,由{@code File.pathSeparator}分隔,其中
  * Android上的默认值为{@code”:“}
  * @param optimizedDirectory 目录,其中包含优化的dex文件
  * 应该是书面的;可能是{@code null}
  * @param libraryPath 包含本机
  * 库,由{@code File.pathSeparator}分隔;可能是
  * {@code null}
  * @param parent 父类加载器
  */
  public BaseDexClassLoader(String dexPath, File optimizedDirectory,
    String libraryPath, ClassLoader parent) {
  super(parent);
  this.pathList = new DexPathList(this, dexPath, libraryPath, optimizedDirectory);
  }
    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        List<Throwable> suppressedExceptions = new ArrayList<Throwable>();
  // ★ 核心跳转
        Class c = pathList.findClass(name, suppressedExceptions);
        if (c == null) {
            ClassNotFoundException cnfe = new ClassNotFoundException("Didn't find class \"" + name + "\" on path: " + pathList);
            for (Throwable t : suppressedExceptions) {
                cnfe.addSuppressed(t);
            }
            throw cnfe;
        }
        return c;
    }
}


目录
相关文章
|
2月前
|
开发工具 Android开发 Swift
安卓与iOS开发环境对比分析
在移动应用开发的广阔舞台上,安卓和iOS这两大操作系统无疑是主角。它们各自拥有独特的特点和优势,为开发者提供了不同的开发环境和工具。本文将深入浅出地探讨安卓和iOS开发环境的主要差异,包括开发工具、编程语言、用户界面设计、性能优化以及市场覆盖等方面,旨在帮助初学者更好地理解两大平台的开发特点,并为他们选择合适的开发路径提供参考。通过比较分析,我们将揭示不同环境下的开发实践,以及如何根据项目需求和目标受众来选择最合适的开发平台。
45 2
|
7天前
|
缓存 Java Shell
Android 系统缓存扫描与清理方法分析
Android 系统缓存从原理探索到实现。
33 15
Android 系统缓存扫描与清理方法分析
|
21天前
|
存储 Linux Android开发
Android底层:通熟易懂分析binder:1.binder准备工作
本文详细介绍了Android Binder机制的准备工作,包括打开Binder驱动、内存映射(mmap)、启动Binder主线程等内容。通过分析系统调用和进程与驱动层的通信,解释了Binder如何实现进程间通信。文章还探讨了Binder主线程的启动流程及其在进程通信中的作用,最后总结了Binder准备工作的调用时机和重要性。
Android底层:通熟易懂分析binder:1.binder准备工作
|
2月前
|
安全 Android开发 数据安全/隐私保护
探索安卓与iOS的安全性差异:技术深度分析与实践建议
本文旨在深入探讨并比较Android和iOS两大移动操作系统在安全性方面的不同之处。通过详细的技术分析,揭示两者在架构设计、权限管理、应用生态及更新机制等方面的安全特性。同时,针对这些差异提出针对性的实践建议,旨在为开发者和用户提供增强移动设备安全性的参考。
111 3
|
20天前
|
开发工具 Android开发 Swift
安卓与iOS开发环境的差异性分析
【10月更文挑战第8天】 本文旨在探讨Android和iOS两大移动操作系统在开发环境上的不同,包括开发语言、工具、平台特性等方面。通过对这些差异性的分析,帮助开发者更好地理解两大平台,以便在项目开发中做出更合适的技术选择。
|
2月前
|
安全 Linux Android开发
探索安卓与iOS的安全性差异:技术深度分析
本文深入探讨了安卓(Android)和iOS两个主流操作系统平台在安全性方面的不同之处。通过比较它们在架构设计、系统更新机制、应用程序生态和隐私保护策略等方面的差异,揭示了每个平台独特的安全优势及潜在风险。此外,文章还讨论了用户在使用这些设备时可以采取的一些最佳实践,以增强个人数据的安全。
|
2月前
|
IDE 开发工具 Android开发
安卓与iOS开发环境对比分析
本文将探讨安卓和iOS这两大移动操作系统在开发环境上的差异,从工具、语言、框架到生态系统等多个角度进行比较。我们将深入了解各自的优势和劣势,并尝试为开发者提供一些实用的建议,以帮助他们根据自己的需求选择最适合的开发平台。
40 1
|
前端开发 Java Android开发
|
1天前
|
编解码 Java Android开发
通义灵码:在安卓开发中提升工作效率的真实应用案例
本文介绍了通义灵码在安卓开发中的应用。作为一名97年的聋人开发者,我在2024年Google Gemma竞赛中获得了冠军,拿下了很多项目竞赛奖励,通义灵码成为我的得力助手。文章详细展示了如何安装通义灵码插件,并通过多个实例说明其在适配国际语言、多种分辨率、业务逻辑开发和编程语言转换等方面的应用,显著提高了开发效率和准确性。
|
2天前
|
存储 IDE 开发工具
探索Android开发之旅:从新手到专家
【10月更文挑战第26天】在这篇文章中,我们将一起踏上一段激动人心的旅程,探索如何在Android平台上从零开始,最终成为一名熟练的开发者。通过简单易懂的语言和实际代码示例,本文将引导你了解Android开发的基础知识、关键概念以及如何实现一个基本的应用程序。无论你是编程新手还是希望扩展你的技术栈,这篇文章都将为你提供价值和启发。让我们开始吧!