【Android 逆向】整体加固脱壳 ( 脱壳起点 : 整体加固脱壳 | Dalvik 脱壳机制 : 利用 DexClassLoader 加载过程进行脱壳 | 相关源码分析 )

简介: 【Android 逆向】整体加固脱壳 ( 脱壳起点 : 整体加固脱壳 | Dalvik 脱壳机制 : 利用 DexClassLoader 加载过程进行脱壳 | 相关源码分析 )

文章目录

一、脱壳起点 : 整体加固脱壳

二、Dalvik 脱壳机制 : 利用 DexClassLoader 加载过程进行脱壳

1、DexClassLoader 源码

2、DexClassLoader 加载 dex 字节码示例





一、脱壳起点 : 整体加固脱壳


一代壳 即 DEX 整体加固 , 所有类型的加固 , 都会在最外围加上一层 整体加固的 壳 , 即使进行了 VMP / Dex2C 高级防护 , 最后也会在高级加壳的外层基础上 , 进行 DEX 进行整体加固 ;



拿到应用后 , 先从内存中 , 将 dex 文件 dump 下来 , 拿到 dex 文件 , 然后进行进一步分析 ; 这个 dex 文件 可能是 Java 源码 , 也可能是使用了其它加壳技术 ;



拿到 dex 文件后 , 开始进行后续分析 , 分为以下几种情况 :


直接获取 Java 代码 : 如果该加壳只是一代壳 , 那么就可以看到 混淆后的 Java 代码 ;

函数抽取 脱壳 : 如果拿到 DEX 文件后 , 发现是空函数 , 则说明在 整体加固 的基础上 还进行了 函数抽取 加壳 ; 下一步针对 函数抽取 脱壳 ;

VMP 或 Dex2C 脱壳 : 如果拿到 DEX 文件后 , 发现是 Native 函数 , 说明在 整体加固 的基础上进行了 VMP 或者 Dex2C 加壳 ; 下一步 针对 Native 化的函数脱壳 ;





二、Dalvik 脱壳机制 : 利用 DexClassLoader 加载过程进行脱壳


Dalvik 脱壳机制 : 在 Dalvik 下 , 使用自定义 DexClassLoader 加载 dex 字节码文件中的类 , 通过分析 DexClassLoader 源码 , 查找 hook 点 , 进而找到 dex 文件被 加载到内存 中的 起始地址 ;



下面分析 DexClassLoader 加载 dex 文件的流程 ;



1、DexClassLoader 源码


DexClassLoader 继承了 BaseDexClassLoader 类 , 类中没有实现任何业务逻辑 , 只是提供了一个构造函数 ;



DexClassLoader 源码 :


/**
 * 从{@code.jar}和{@code.apk}文件加载类的类加载器
 * 包含{@code classes.dex}项。这可用于执行未作为应用程序一部分安装的代码。
 *
 * <p>这个类加载器需要一个应用程序私有的可写目录来缓存优化的类。
 * 使用{@code Context.getCodeCacheDir()}创建
 * 这样一个目录:<pre>{@code
 * File dexOutputDir = context.getCodeCacheDir();
 * }</pre>
 *
 * <p><strong>不要在外部存储上缓存优化的类。</strong>
 * 外部存储不提供保护您的计算机所需的访问控制
 * 防止代码注入攻击的应用程序。
 */
public class DexClassLoader extends BaseDexClassLoader {
    /**
     * 创建一个{@code-DexClassLoader}来查找解释的和本机的
     * 密码解释类可以在包含的一组DEX文件中找到
     * 在Jar或APK文件中。
     *
     * <p>使用指定的字符分隔路径列表
     * {@code path.separator}系统属性,默认为{@code:}。
     *
     * @param dexPath 包含类和
     * 资源,由{@code File.pathSeparator}分隔,其中
     * Android上的默认值为{@code”:“}
     * @param optimizedDirectory 目录,其中包含优化的dex文件
     * 应该是书面的;不能为{@code null}
     * @param librarySearchPath 包含本机
     * 库,由{@code File.pathSeparator}分隔;可能是
     * {@code null}
     * @param parent 父类加载器
     */
    public DexClassLoader(String dexPath, String optimizedDirectory,
                          String librarySearchPath, ClassLoader parent) {
        super(dexPath, new File(optimizedDirectory), librarySearchPath, parent);
    }
}


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



2、DexClassLoader 加载 dex 字节码示例


在 【Android 逆向】类加载器 ClassLoader ( 使用 DexClassLoader 动态加载字节码文件 | 拷贝 DEX 文件到内置存储 | 加载并执行 DEX 字节码文件 ) 博客中 , 使用了 DexClassLoader 类加载器 , 加载了内置存储空间的 dex 文件 , 并成功执行了其中的方法 ;


主要的使用流程源码如下 :

/**
     * 测试调用 Dex 字节码文件中的方法
     * @param context
     * @param dexFilePath
     */
    private void testDex(Context context, String dexFilePath) {
        // 优化目录
        File optFile = new File(getFilesDir(), "opt_dex");
        // 依赖库目录 , 用于存放 so 文件
        File libFile = new File(getFilesDir(), "lib_path");
        // 初始化 DexClassLoader
        DexClassLoader dexClassLoader = new DexClassLoader(
                dexFilePath,                    // Dex 字节码文件路径
                optFile.getAbsolutePath(),      // 优化目录
                libFile.getAbsolutePath(),      // 依赖库目录
                context.getClassLoader()        // 父节点类加载器
        );
        // 加载 com.example.dex_demo.DexTest 类
        // 该类中有可执行方法 test()
        Class<?> clazz = null;
        try {
            clazz = dexClassLoader.loadClass("com.example.dex_demo.DexTest");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        // 获取 com.example.dex_demo.DexTest 类 中的 test() 方法
        if (clazz != null) {
            try {
                // 获取 test 方法
                Method method = clazz.getDeclaredMethod("test");
                // 获取 Object 对象
                Object object = clazz.newInstance();
                // 调用 test() 方法
                method.invoke(object);
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InstantiationException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            }
        }
    }




目录
相关文章
|
4月前
|
Java Android开发
Android面试题经典之Glide取消加载以及线程池优化
Glide通过生命周期管理在`onStop`时暂停请求,`onDestroy`时取消请求,减少资源浪费。在`EngineJob`和`DecodeJob`中使用`cancel`方法标记任务并中断数据获取。当网络请求被取消时,`HttpUrlFetcher`的`cancel`方法设置标志,之后的数据获取会返回`null`,中断加载流程。Glide还使用定制的线程池,如AnimationExecutor、diskCacheExecutor、sourceExecutor和newUnlimitedSourceExecutor,其中某些禁止网络访问,并根据CPU核心数动态调整线程数。
138 2
|
26天前
|
Android开发 UED
Android 中加载 Gif 动画
【10月更文挑战第20天】加载 Gif 动画是 Android 开发中的一项重要技能。通过使用第三方库或自定义实现,可以方便地在应用中展示生动的 Gif 动画。在实际应用中,需要根据具体情况进行合理选择和优化,以确保用户体验和性能的平衡。可以通过不断的实践和探索,进一步掌握在 Android 中加载 Gif 动画的技巧和方法,为开发高质量的 Android 应用提供支持。
|
3月前
|
存储 缓存 Java
Android项目架构设计问题之优化业务接口数据的加载效率如何解决
Android项目架构设计问题之优化业务接口数据的加载效率如何解决
45 0
|
3月前
|
Java Android开发 Kotlin
Android项目架构设计问题之要在Glide库中加载网络图片到ImageView如何解决
Android项目架构设计问题之要在Glide库中加载网络图片到ImageView如何解决
37 0
|
Java Android开发
【Android 启动过程】Activity 启动源码分析 ( ActivityThread 流程分析 二 )
【Android 启动过程】Activity 启动源码分析 ( ActivityThread 流程分析 二 )
241 0
|
Java Android开发
【Android 启动过程】Activity 启动源码分析 ( ActivityThread 流程分析 一 )(二)
【Android 启动过程】Activity 启动源码分析 ( ActivityThread 流程分析 一 )(二)
289 0
|
Java Android开发
【Android 启动过程】Activity 启动源码分析 ( ActivityThread 流程分析 一 )(一)
【Android 启动过程】Activity 启动源码分析 ( ActivityThread 流程分析 一 )(一)
158 0
下一篇
无影云桌面