Loading [MathJax]/jax/input/TeX/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >【Android 逆向】ART 函数抽取加壳 ⑥ ( 函数抽取后续操作 “ 还原被抽取的函数 “ | LoadClass 类加载 | LoadClassMembers 类成员加载 )

【Android 逆向】ART 函数抽取加壳 ⑥ ( 函数抽取后续操作 “ 还原被抽取的函数 “ | LoadClass 类加载 | LoadClassMembers 类成员加载 )

作者头像
韩曙亮
发布于 2023-03-30 09:23:29
发布于 2023-03-30 09:23:29
41300
代码可运行
举报
运行总次数:0
代码可运行

文章目录

两篇博客中 , 简单介绍了 禁用 dex2oat 机制 的原理 , 下面开始 实现 dex2oat 禁用功能 ;

【Android 逆向】ART 函数抽取加壳 ③ ( 禁用 dex2oat 操作 HOOK 点介绍 | 集成 InLineHook ) 博客中 , 介绍了 HOOK 点 , 以及 集成 HOOK C 代码的库 InLineHook ;

【Android 逆向】ART 函数抽取加壳 ④ ( 对 libc.so#execve 函数进行内联 HOOK 操作 ) 博客中 , 对 libc.so#execve 函数 进行了 内联 HOOK 操作 , 可以对该函数进行拦截 ;

【Android 逆向】ART 函数抽取加壳 ⑥ ( unistd.h#execve 函数分析 | 使用自定义的 myexecve 函数替换 libc.so#execve 函数 ) 博客实现 自定义的 myexecve 函数 替换 libc.so#execve 函数 ;

本篇博客开始分析 函数收取后续操作 , 查找还原被抽取函数的时机 ;

一、函数抽取后续操作 " 还原被抽取的函数 "


在上一篇博客 【Android 逆向】ART 函数抽取加壳 ⑥ ( unistd.h#execve 函数分析 | 使用自定义的 myexecve 函数替换 libc.so#execve 函数 ) 中 实现了 自定义的 myexecve 函数 替换 libc.so#execve 函数 ;

下面还需要 在源码中找到一个时机点 , 还原 被抽取的函数 ;

函数抽取加壳 操作 , 打包到 APK 应用中的 Dex 字节码文件中函数是被抽取出来的 , 执行前必须将函数还原 ,

  • 第一步 关闭 dex2oat 机制 ,
  • 第二步 还原被抽取的函数 ;

二、class_linker.cc#LoadClass 类加载操作


还原被抽取函数的 时机是 类加载器 ClassLoader 加载 Class 字节码类 流程中的一个时间点 , 该时间点必须是 类加载之后 , 函数调用之前 ;

在 ART 虚拟机中 , 调用函数前 , 需要对函数所在的类进行 加载 以及 链接 操作 ;

Android 源码中的 " art/runtime/class_linker.cc#LoadClass " 函数中 , 加载字节码类 ;

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
void ClassLinker::LoadClass(Thread* self,
                            const DexFile& dex_file,
                            const DexFile::ClassDef& dex_class_def,
                            Handle<mirror::Class> klass) {
  const uint8_t* class_data = dex_file.GetClassData(dex_class_def);
  if (class_data == nullptr) {
    return;  // no fields or methods - for example a marker interface
  }
  LoadClassMembers(self, dex_file, class_data, klass);
}

源码地址 : http://androidxref.com/8.0.0_r4/xref/art/runtime/class_linker.cc#3119

三、class_linker.cc#LoadClassMembers 类成员加载操作


在 " art/runtime/class_linker.cc#LoadClass " 函数 中调用 LoadClassMembers 函数 , 该函数的作用是加载 类的成员 , 包括 成员字段 和 成员变量 ;

在 LoadClassMembers 函数中 , 首先加载了静态字段 , 然后加载实例字段 , 最后加载 成员函数 ;

在加载函数的过程中 , 调用了 LoadMethod 方法 , 可以作为加载函数的时机点 ;

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
LoadMethod(dex_file, it, klass, method);

art/runtime/class_linker.cc#LoadClassMembers 函数源码如下 :

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
void ClassLinker::LoadClassMembers(Thread* self,
                                   const DexFile& dex_file,
                                   const uint8_t* class_data,
                                   Handle<mirror::Class> klass) {
  {
    //注意:在设置字段和方法数组之前,我们不能暂停线程,否则
	//Class::VisitFieldRoots可能缺少某些字段或方法。
    ScopedAssertNoThreadSuspension nts(__FUNCTION__);
    //加载静态字段。
	//我们允许class_data_item中相同字段的重复定义
	//但忽略此处的重复索引b/21868015。
    LinearAlloc* const allocator = GetAllocatorForClassLoader(klass->GetClassLoader());
    ClassDataItemIterator it(dex_file, class_data);
    LengthPrefixedArray<ArtField>* sfields = AllocArtFieldArray(self,
                                                                allocator,
                                                                it.NumStaticFields());
    size_t num_sfields = 0;
    uint32_t last_field_idx = 0u;
    for (; it.HasNextStaticField(); it.Next()) {
      uint32_t field_idx = it.GetMemberIndex();
      DCHECK_GE(field_idx, last_field_idx);  // Ordering enforced by DexFileVerifier.
      if (num_sfields == 0 || LIKELY(field_idx > last_field_idx)) {
        DCHECK_LT(num_sfields, it.NumStaticFields());
        LoadField(it, klass, &sfields->At(num_sfields));
        ++num_sfields;
        last_field_idx = field_idx;
      }
    }

    // 加载实例字段.
    LengthPrefixedArray<ArtField>* ifields = AllocArtFieldArray(self,
                                                                allocator,
                                                                it.NumInstanceFields());
    size_t num_ifields = 0u;
    last_field_idx = 0u;
    for (; it.HasNextInstanceField(); it.Next()) {
      uint32_t field_idx = it.GetMemberIndex();
      DCHECK_GE(field_idx, last_field_idx);  // Ordering enforced by DexFileVerifier.
      if (num_ifields == 0 || LIKELY(field_idx > last_field_idx)) {
        DCHECK_LT(num_ifields, it.NumInstanceFields());
        LoadField(it, klass, &ifields->At(num_ifields));
        ++num_ifields;
        last_field_idx = field_idx;
      }
    }

    if (UNLIKELY(num_sfields != it.NumStaticFields()) ||
        UNLIKELY(num_ifields != it.NumInstanceFields())) {
      LOG(WARNING) << "Duplicate fields in class " << klass->PrettyDescriptor()
          << " (unique static fields: " << num_sfields << "/" << it.NumStaticFields()
          << ", unique instance fields: " << num_ifields << "/" << it.NumInstanceFields() << ")";
      // 注意:不要缩小过度分配的sfields/ifield,只需设置大小即可。
      if (sfields != nullptr) {
        sfields->SetSize(num_sfields);
      }
      if (ifields != nullptr) {
        ifields->SetSize(num_ifields);
      }
    }
    // 设置字段数组。
    klass->SetSFieldsPtr(sfields);
    DCHECK_EQ(klass->NumStaticFields(), num_sfields);
    klass->SetIFieldsPtr(ifields);
    DCHECK_EQ(klass->NumInstanceFields(), num_ifields);
    // 加载方法.
    bool has_oat_class = false;
    const OatFile::OatClass oat_class =
        (Runtime::Current()->IsStarted() && !Runtime::Current()->IsAotCompiler())
            ? OatFile::FindOatClass(dex_file, klass->GetDexClassDefIndex(), &has_oat_class)
            : OatFile::OatClass::Invalid();
    const OatFile::OatClass* oat_class_ptr = has_oat_class ? &oat_class : nullptr;
    klass->SetMethodsPtr(
        AllocArtMethodArray(self, allocator, it.NumDirectMethods() + it.NumVirtualMethods()),
        it.NumDirectMethods(),
        it.NumVirtualMethods());
    size_t class_def_method_index = 0;
    uint32_t last_dex_method_index = DexFile::kDexNoIndex;
    size_t last_class_def_method_index = 0;
    // TODO 这些应该真正使用迭代器。
    for (size_t i = 0; it.HasNextDirectMethod(); i++, it.Next()) {
      // 新建 ArtMethod 对象 , 表示一个函数
      ArtMethod* method = klass->GetDirectMethodUnchecked(i, image_pointer_size_);
      LoadMethod(dex_file, it, klass, method);
      LinkCode(this, method, oat_class_ptr, class_def_method_index);
      uint32_t it_method_index = it.GetMemberIndex();
      if (last_dex_method_index == it_method_index) {
        // 重复案例
        method->SetMethodIndex(last_class_def_method_index);
      } else {
        method->SetMethodIndex(class_def_method_index);
        last_dex_method_index = it_method_index;
        last_class_def_method_index = class_def_method_index;
      }
      class_def_method_index++;
    }
    for (size_t i = 0; it.HasNextVirtualMethod(); i++, it.Next()) {
      ArtMethod* method = klass->GetVirtualMethodUnchecked(i, image_pointer_size_);
      LoadMethod(dex_file, it, klass, method);
      DCHECK_EQ(class_def_method_index, it.NumDirectMethods() + i);
      LinkCode(this, method, oat_class_ptr, class_def_method_index);
      class_def_method_index++;
    }
    DCHECK(!it.HasNext());
  }
  // 确保卡片上有标记,以便记住的套餐能够拾取本地根。
  Runtime::Current()->GetHeap()->WriteBarrierEveryFieldOf(klass.Get());
  self->AllowThreadSuspension();
}

源码地址 : http://androidxref.com/8.0.0_r4/xref/art/runtime/class_linker.cc#LoadClassMembers

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022-10-24,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
【胖虎的逆向之路】04——脱壳(一代壳)原理&脱壳相关概念详解
在上文中,我们讲解了关于Android脱壳的基本办法和实际操作,现在我们来针对脱壳(一代壳)的原理和脱壳相关的基础知识介绍,由于作者能力有限,会尽力的详细描述 一代壳脱壳 的流程及原理,如本文中有任何错误,烦请指正,感谢~
胖虎哥
2023/05/10
8900
【胖虎的逆向之路】04——脱壳(一代壳)原理&脱壳相关概念详解
ART 在 Android 安全攻防中的应用
在日常的 Android 应用安全分析中,经常会遇到一些对抗,比如目标应用加壳、混淆、加固,需要进行脱壳还原;又或者会有针对常用注入工具的检测,比如 frida、Xposed 等,这时候也会想知道这些工具的核心原理以及是否自己可以实现。
evilpan
2023/02/12
1.3K0
ART 在 Android 安全攻防中的应用
【Android开发高级系列】Dalvik虚拟机专题
三,JavaVM创建之后,我们就有了JNINativeInterface,里面包含了所有的Java接口,比如FindClass,NewObject,CallObjectMethod等
江中散人_Jun
2023/10/16
6460
【Android开发高级系列】Dalvik虚拟机专题
【Android 逆向】ART 脱壳 ( dex2oat 脱壳 | /art/dex2oat/dex2oat.cc#Dex2oat 函数源码 )
在上一篇博客 【Android 逆向】ART 脱壳 ( dex2oat 脱壳 | aosp 中搜索 dex2oat 源码 | dex2oat.cc#main 主函数源码 ) 中 , 分析到 dex2oat 工具源码中的主函数为 /art/dex2oat/dex2oat.cc#main , 在该函数中调用了 /art/dex2oat/dex2oat.cc#Dex2oat 函数 ;
韩曙亮
2023/03/30
3390
【Android 逆向】ART 函数抽取加壳 ④ ( 对 libc.so#execve 函数进行内联 HOOK 操作 )
两篇博客中 , 简单介绍了 禁用 dex2oat 机制 的原理 , 下面开始 实现 dex2oat 禁用功能 ;
韩曙亮
2023/03/30
6000
【Android 逆向】ART 函数抽取加壳 ③ ( 禁用 dex2oat 操作 HOOK 点介绍 | 集成 InLineHook )
两篇博客中 , 简单介绍了 禁用 dex2oat 机制 的原理 , 下面开始 实现 dex2oat 禁用功能 ;
韩曙亮
2023/03/30
5820
【Android 逆向】ART 脱壳 ( InMemoryDexClassLoader 脱壳 | InMemoryDexClassLoader 类加载器脱壳点总结 )
InMemoryDexClassLoader 类加载器脱壳点总结 : 在下面列举出的函数中 , 都可以获取到内存中 DEX 文件的起始地址 , 可以将 DEX 文件从内存中 dump 下来 ;
韩曙亮
2023/03/30
6370
Android 虚拟机:你需要掌握的基本知识
本文简要介绍 Android Runtime 虚拟机里的一些细节点,主要包括 dex file, oat file, mirror::Class, ArtField, ArtMethod, DexCache, ClassTable 等。
张拭心 shixinzhang
2022/01/13
1.1K0
Android 虚拟机:你需要掌握的基本知识
【Android 逆向】ART 函数抽取加壳 ② ( 禁用 dex2oat 简介 | TurboDex 中禁用 dex2oat 参考示例 )
在上一篇博客 【Android 逆向】ART 函数抽取加壳 ( ART 下的函数抽取恢复时机 | 禁用 dex2oat 机制源码分析 )
韩曙亮
2023/03/30
6270
【Android 逆向】ART 函数抽取加壳 ① ( ART 下的函数抽取恢复时机 | 禁用 dex2oat 机制源码分析 )
如果选择第一种方案 , 在 dex2oat 之前进行恢复 , 这没有任何意义 , dex2oat 编译后 , 生成的 oat 文件是完整的 , 此时 可以 完整的将 oat 文件 dump 到 SD 卡中 , 基本等于没有加固 , 还是一个一代壳 ;
韩曙亮
2023/03/30
5340
【Android 逆向】ART 函数抽取加壳 ⑤ ( unistd.h#execve 函数分析 | 使用自定义的 myexecve 函数替换 libc.so#execve 函数 )
两篇博客中 , 简单介绍了 禁用 dex2oat 机制 的原理 , 下面开始 实现 dex2oat 禁用功能 ;
韩曙亮
2023/03/30
4290
【Android 逆向】ART 脱壳 ( DexClassLoader 脱壳 | oat_file_assistant.cc 中涉及的 oat 文件生成流程 )
在上一篇博客 【Android 逆向】ART 脱壳 ( DexClassLoader 脱壳 | DexClassLoader 构造函数 | 参考 Dalvik 的 DexClassLoader 类加载流程 ) 中 , 分析了 ART 虚拟机下 DexClassLoader 类加载器加载 dex 文件的 Java 层流程 , 与 Dalvik 虚拟机下基本一致 , 从 native 层开始不一致 , 本篇博客开始分析 native 层的类加载流程 ;
韩曙亮
2023/03/30
8440
NDK--andfix热修复之art虚拟机
在so插件化原理,hook技术实现andfix热修复中,只实现了dalvik虚拟机中的热修复,安卓5.0后,谷歌彻底抛弃dalvik虚拟机,改用art虚拟机。 在dalvik虚拟机中,应用启动首先会加载dex成class字节码,然后采用JIT技术,字节码都需要通过即时编译器(just in time ,JIT)转换为机器码(CPU真正识别二进制),虽然转换时会利用缓存技术优化,但还是会造成应用运行速度。 在art虚拟机中,在应用安装时,就通过dex2oat工具把dex文件转换为oat文件,oat文件中同时存
aruba
2020/07/03
5860
面试必问的安卓虚拟机,你真的掌握了么?——安卓虚拟机基础知识回顾
21世纪,安卓虚拟机正在一步步的走入我们的生活,小到个人部分朋友在电脑上使用安卓虚拟机玩手游,大到安卓从业人员在虚拟机上面跑程序。不得不承认,对于每一位Androider 而言,安卓虚拟机是我们日常开发中不可或缺的一环,但是关于安卓虚拟机的一些知识点和小细节你真的完全掌握了么?本文将就主要包括 dex file, oat file, mirror::Class, ArtField, ArtMethod, DexCache, ClassTable,这一块内容进行一个简单的概述和讨论,希望新手们多多学习,老手们温故而知新。
BlueSocks
2022/03/22
6320
面试必问的安卓虚拟机,你真的掌握了么?——安卓虚拟机基础知识回顾
【Android 逆向】ART 脱壳 ( InMemoryDexClassLoader 脱壳 | dex_file.cc 中创建 DexFile 实例对象的相关函数分析 )
在上一篇博客 【Android 逆向】ART 脱壳 ( InMemoryDexClassLoader 脱壳 | DexFile.java 对应的 dalvik_system_DexFile.cc 本地函数分析 ) 中 , 分析了 DexFile.java 中的 createCookieWithDirectBuffer 和 createCookieWithArray 函数对应的 native 函数 ,
韩曙亮
2023/03/30
4900
PathClassLoader加载与查找类
PathClassLoader继承自BaseDexClassLoader , 主要是把dexPath传递给BaseDexClassLoader
None_Ling
2020/09/14
2.1K0
【Android 逆向】Dalvik 函数抽取加壳 ⑥ ( 函数抽取加壳实现 | 函数抽取 | 函数还原 )
在 Android中实现「类方法指令抽取方式」加固方案原理解析 博客中 , 首先对 Dex 字节码文件的结构进行了分析 , 函数抽取 , 主要是将 Dex 字节码文件中的函数进行抽取 , 然后在运行时再进行恢复操作 ;
韩曙亮
2023/03/30
1.1K0
【Android 逆向】Dalvik 函数抽取加壳 ⑥ ( 函数抽取加壳实现 | 函数抽取 | 函数还原 )
【Android 逆向】ART 脱壳 ( InMemoryDexClassLoader 脱壳 | DexFile.java 对应的 dalvik_system_DexFile.cc 本地函数分析 )
在上一篇博客 【Android 逆向】ART 脱壳 ( InMemoryDexClassLoader 脱壳 | DexFile 构造函数及相关调用函数 | Android 源码中查找 native 函数 ) 中 , 分析了 DexFile 构造函数 , 以及 makeInMemoryDexElements 函数 ; 并查找了 DexFile 中的 native 函数 createCookieWithDirectBuffer 和 createCookieWithArray 函数定义在 /art/runtime/native/dalvik_system_DexFile.cc 中 ;
韩曙亮
2023/03/30
4080
【Android 逆向】Dalvik 函数抽取加壳 ⑤ ( 类加载流程分析 | Class.cpp#findClassNoInit 函数 | DexFile.cpp#dexFindClass 函数 )
上一篇博客 【Android 逆向】Dalvik 函数抽取加壳 ( 类加载流程分析 | native 函数查询 | dalvik_system_DexFile.cpp#defineClassNative 函数 ) 中 , dalvik_system_DexFile.cpp#Dalvik_dalvik_system_DexFile_defineClassNative 函数中 , 调用了 Class.cpp#dvmDefineClass 函数 ;
韩曙亮
2023/03/30
2090
Android N 混合编译与对热补丁影响解析
大约在六月底,Tinker在微信全量上线了一个补丁版本,随即华为反馈在Android N上微信无法启动。冷汗冒一地,Android N又搞了什么东东?为什么与instant run保持一致的补丁方式也
张绍文
2017/07/18
3.6K0
Android N 混合编译与对热补丁影响解析
推荐阅读
【胖虎的逆向之路】04——脱壳(一代壳)原理&脱壳相关概念详解
8900
ART 在 Android 安全攻防中的应用
1.3K0
【Android开发高级系列】Dalvik虚拟机专题
6460
【Android 逆向】ART 脱壳 ( dex2oat 脱壳 | /art/dex2oat/dex2oat.cc#Dex2oat 函数源码 )
3390
【Android 逆向】ART 函数抽取加壳 ④ ( 对 libc.so#execve 函数进行内联 HOOK 操作 )
6000
【Android 逆向】ART 函数抽取加壳 ③ ( 禁用 dex2oat 操作 HOOK 点介绍 | 集成 InLineHook )
5820
【Android 逆向】ART 脱壳 ( InMemoryDexClassLoader 脱壳 | InMemoryDexClassLoader 类加载器脱壳点总结 )
6370
Android 虚拟机:你需要掌握的基本知识
1.1K0
【Android 逆向】ART 函数抽取加壳 ② ( 禁用 dex2oat 简介 | TurboDex 中禁用 dex2oat 参考示例 )
6270
【Android 逆向】ART 函数抽取加壳 ① ( ART 下的函数抽取恢复时机 | 禁用 dex2oat 机制源码分析 )
5340
【Android 逆向】ART 函数抽取加壳 ⑤ ( unistd.h#execve 函数分析 | 使用自定义的 myexecve 函数替换 libc.so#execve 函数 )
4290
【Android 逆向】ART 脱壳 ( DexClassLoader 脱壳 | oat_file_assistant.cc 中涉及的 oat 文件生成流程 )
8440
NDK--andfix热修复之art虚拟机
5860
面试必问的安卓虚拟机,你真的掌握了么?——安卓虚拟机基础知识回顾
6320
【Android 逆向】ART 脱壳 ( InMemoryDexClassLoader 脱壳 | dex_file.cc 中创建 DexFile 实例对象的相关函数分析 )
4900
PathClassLoader加载与查找类
2.1K0
【Android 逆向】Dalvik 函数抽取加壳 ⑥ ( 函数抽取加壳实现 | 函数抽取 | 函数还原 )
1.1K0
【Android 逆向】ART 脱壳 ( InMemoryDexClassLoader 脱壳 | DexFile.java 对应的 dalvik_system_DexFile.cc 本地函数分析 )
4080
【Android 逆向】Dalvik 函数抽取加壳 ⑤ ( 类加载流程分析 | Class.cpp#findClassNoInit 函数 | DexFile.cpp#dexFindClass 函数 )
2090
Android N 混合编译与对热补丁影响解析
3.6K0
相关推荐
【胖虎的逆向之路】04——脱壳(一代壳)原理&脱壳相关概念详解
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验