首页
社区
课程
招聘
[原创]Art 虚拟机代码加载简析
发表于: 2021-2-27 21:43 10366

[原创]Art 虚拟机代码加载简析

2021-2-27 21:43
10366

最近在学加固,做了点笔记,前面分享过一篇Dalvik 虚拟机代码加载简析

这篇是Art版,基于android-5.0.0_r2

懒得画图了,art其他版本后续有空再更吧(逃

java层和android-4.4.4_r1好像区别不大

android5的mCookie 类型由int 变成了long

android4 native层和java层(好像?)是通过brige连接

android5 开始才是JNI标准

支持多multidex

其实这里可以看到关键脱壳点OpenMemory函数,Android6,Android7也是这个函数,通过源码代码执行的分析,可以帮助我们去更好地理解脱壳。

这里附上基于Android5的不落地加载代码:

注:仅学习笔记,如有理解错误的地方还望包涵~

 
 
 
 
 
 
xref: libcore/dalvik/src/main/java/dalvik/system/DexClassLoader.java
 
extends BaseDexClassLoader
xref: libcore/dalvik/src/main/java/dalvik/system/DexClassLoader.java
 
extends BaseDexClassLoader
dexPath:dex文件源码目录
optimizedDirectory:优化以后odex生成目录
librarySearchPath:需要的本地so库的搜索路径
parent:父加载器
 
public DexClassLoader(String dexPath, String optimizedDirectory,
        String libraryPath, ClassLoader parent) {
    super(dexPath, new File(optimizedDirectory), libraryPath, parent);
}
dexPath:dex文件源码目录
optimizedDirectory:优化以后odex生成目录
librarySearchPath:需要的本地so库的搜索路径
parent:父加载器
 
public DexClassLoader(String dexPath, String optimizedDirectory,
        String libraryPath, ClassLoader parent) {
    super(dexPath, new File(optimizedDirectory), libraryPath, parent);
}
xref: libcore/dalvik/src/main/java/dalvik/system/BaseDexClassLoader.java
 
extends ClassLoader
private final DexPathList pathList;
xref: libcore/dalvik/src/main/java/dalvik/system/BaseDexClassLoader.java
 
extends ClassLoader
private final DexPathList pathList;
public BaseDexClassLoader(String dexPath, File optimizedDirectory,
        String libraryPath, ClassLoader parent) {
    super(parent);
    this.pathList = new DexPathList(this, dexPath, libraryPath, optimizedDirectory);
}
public BaseDexClassLoader(String dexPath, File optimizedDirectory,
        String libraryPath, ClassLoader parent) {
    super(parent);
    this.pathList = new DexPathList(this, dexPath, libraryPath, optimizedDirectory);
}
xref: /libcore/dalvik/src/main/java/dalvik/system/DexPathList.java
 
private final Element[] dexElements;
xref: /libcore/dalvik/src/main/java/dalvik/system/DexPathList.java
 
private final Element[] dexElements;
public DexPathList(ClassLoader definingContext, String dexPath,
           String libraryPath, File optimizedDirectory) {
    ...
    this.dexElements = makeDexElements(splitDexPath(dexPath),
        optimizedDirectory,suppressedExceptions);
}
public DexPathList(ClassLoader definingContext, String dexPath,
           String libraryPath, File optimizedDirectory) {
    ...
    this.dexElements = makeDexElements(splitDexPath(dexPath),
        optimizedDirectory,suppressedExceptions);
}
private static Element[] makeDexElements(ArrayList<File> files, File optimizedDirectory,
        ArrayList<IOException> suppressedExceptions) {
    ArrayList<Element> elements = new ArrayList<Element>();
    ...
    for (File file : files) {
        DexFile dex = loadDexFile(file, optimizedDirectory);
    }
    if ((zip != null) || (dex != null)) {
        elements.add(new Element(file, false, zip, dex));
    }
    return elements.toArray(new Element[elements.size()]); //返回赋值给dexElements
}
private static Element[] makeDexElements(ArrayList<File> files, File optimizedDirectory,
        ArrayList<IOException> suppressedExceptions) {
    ArrayList<Element> elements = new ArrayList<Element>();
    ...
    for (File file : files) {
        DexFile dex = loadDexFile(file, optimizedDirectory);
    }
    if ((zip != null) || (dex != null)) {
        elements.add(new Element(file, false, zip, dex));
    }
    return elements.toArray(new Element[elements.size()]); //返回赋值给dexElements
}
private static DexFile loadDexFile(File file, File optimizedDirectory)
        throws IOException {
    ...
    return DexFile.loadDex(file.getPath(), optimizedPath, 0);
}
private static DexFile loadDexFile(File file, File optimizedDirectory)
        throws IOException {
    ...
    return DexFile.loadDex(file.getPath(), optimizedPath, 0);
}
xref: /libcore/dalvik/src/main/java/dalvik/system/DexFile.java
 
private long mCookie;
xref: /libcore/dalvik/src/main/java/dalvik/system/DexFile.java
 
private long mCookie;
static public DexFile loadDex(String sourcePathName, String outputPathName,
        int flags) throws IOException {
    return new DexFile(sourcePathName, outputPathName, flags);
}
static public DexFile loadDex(String sourcePathName, String outputPathName,
        int flags) throws IOException {
    return new DexFile(sourcePathName, outputPathName, flags);
}
private DexFile(String sourceName, String outputName, int flags) throws IOException {
    ...
    mCookie = openDexFile(sourceName, outputName, flags);
}
private DexFile(String sourceName, String outputName, int flags) throws IOException {
    ...
    mCookie = openDexFile(sourceName, outputName, flags);
}
private static long openDexFile(String sourceName, String outputName,
        int flags) throws IOException {
    return openDexFileNative(new File(sourceName).getCanonicalPath(),
        (outputName == null) ? null : new File(outputName).getCanonicalPath(),
        flags);
}
private static long 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 long openDexFileNative(String sourceName, String outputName,
        int flags) throws IOException;
native private static long openDexFileNative(String sourceName, String outputName,
        int flags) throws IOException;
DexPathList pathList
    Element[] dexElements
        DexFile dex // new Element(file, false, zip, dex)
            long mCookie
 
BaseDexClassLoader中有pathList变量
pathList中有dexElements变量,dexElements中每一个Element由dex初始化
每个DexFile中最关键的就是mCookie,也就是native层的dex_files指针
DexPathList pathList
    Element[] dexElements
        DexFile dex // new Element(file, false, zip, dex)
            long mCookie
 
BaseDexClassLoader中有pathList变量
pathList中有dexElements变量,dexElements中每一个Element由dex初始化
每个DexFile中最关键的就是mCookie,也就是native层的dex_files指针
xref: /art/runtime/native/dalvik_system_DexFile.cc
 
std::unique_ptr<std::vector<const DexFile*>> dex_files(new std::vector<const DexFile*>());
xref: /art/runtime/native/dalvik_system_DexFile.cc
 
std::unique_ptr<std::vector<const DexFile*>> dex_files(new std::vector<const DexFile*>());
static jlong DexFile_openDexFileNative(JNIEnv* env, jclass, jstring javaSourceName, jstring javaOutputName, jint) {
  ...
  ClassLinker* linker = Runtime::Current()->GetClassLinker();
  std::unique_ptr<std::vector<const DexFile*>> dex_files(new std::vector<const DexFile*>());
  bool success = linker->OpenDexFilesFromOat(sourceName.c_str(), outputName.c_str(), &error_msgs,dex_files.get());
  if (success || !dex_files->empty()) {
    // In the case of non-success, we have not found or could not generate the oat file.
    // But we may still have found a dex file that we can use.
    return static_cast<jlong>(reinterpret_cast<uintptr_t>(dex_files.release()));
  }
}
static jlong DexFile_openDexFileNative(JNIEnv* env, jclass, jstring javaSourceName, jstring javaOutputName, jint) {
  ...
  ClassLinker* linker = Runtime::Current()->GetClassLinker();
  std::unique_ptr<std::vector<const DexFile*>> dex_files(new std::vector<const DexFile*>());
  bool success = linker->OpenDexFilesFromOat(sourceName.c_str(), outputName.c_str(), &error_msgs,dex_files.get());
  if (success || !dex_files->empty()) {
    // In the case of non-success, we have not found or could not generate the oat file.
    // But we may still have found a dex file that we can use.
    return static_cast<jlong>(reinterpret_cast<uintptr_t>(dex_files.release()));
  }
}
xref: /art/runtime/class_linker.cc
xref: /art/runtime/class_linker.cc
bool ClassLinker::OpenDexFilesFromOat(const char* dex_location, const char* oat_location,
                                      std::vector<std::string>* error_msgs,
                                      std::vector<const DexFile*>* dex_files) {
  if (!DexFile::GetChecksum(dex_location, dex_location_checksum_pointer, &checksum_error_msg)) {
    ...
  }
  // 检查是否我们有一个已经打开的oatfile(内存中)
  const OatFile::OatDexFile* oat_dex_file = FindOpenedOatDexFile(oat_location, dex_location,dex_location_checksum_pointer);
  std::unique_ptr<const OatFile> open_oat_file(
      oat_dex_file != nullptr ? oat_dex_file->GetOatFile() : nullptr);
 
  // 检查是否我们有一个可以使用的的oatfile(磁盘上),通过oat_location字符串
  if (open_oat_file.get() == nullptr) {
      open_oat_file.reset(FindOatFileInOatLocationForDexFile(dex_location, dex_location_checksum,oat_location, &error_msg));
      ...
    needs_registering = true;
  }
 
  // 如果我们有一个oat文件,检查所有包含的multidex文件以确定我们的dex位置
  bool success = LoadMultiDexFilesFromOatFile(open_oat_file.get(), dex_location,
                                              dex_location_checksum_pointer,
                                              false, error_msgs, dex_files);
  if (success) {
    const OatFile* oat_file = open_oat_file.release();  // Avoid deleting it.
    if (needs_registering) {
      // We opened the oat file, so we must register it.
      RegisterOatFile(oat_file);
    }
    return oat_file->IsExecutable();
  }
 
  // 如果不是这样(要么没有oat文件,要么不匹配),重新生成并加载oat,通过dex_location字符串
  if (Runtime::Current()->IsDex2OatEnabled() && has_flock && scoped_flock.HasFile()) {
    // Create the oat file.
    open_oat_file.reset(CreateOatFileForDexLocation(dex_location, scoped_flock.GetFile()->Fd(),oat_location, error_msgs));
  }
 
  // Failed, bail.art模式下的解析模式,以上都是编译成oat的编译模式
  if (open_oat_file.get() == nullptr) {
    std::string error_msg;
    // dex2oat was disabled or crashed. Add the dex file in the list of dex_files to make progress.
    DexFile::Open(dex_location, dex_location, &error_msg, dex_files);
    error_msgs->push_back(error_msg);
    return false;
  }
 
  // Try to load again, but stronger checks.
  success = LoadMultiDexFilesFromOatFile(open_oat_file.get(), dex_location,
                                         dex_location_checksum_pointer,
                                         true, error_msgs, dex_files);
  if (success) {
    RegisterOatFile(open_oat_file.release());
    return true;
  }
}
bool ClassLinker::OpenDexFilesFromOat(const char* dex_location, const char* oat_location,
                                      std::vector<std::string>* error_msgs,
                                      std::vector<const DexFile*>* dex_files) {
  if (!DexFile::GetChecksum(dex_location, dex_location_checksum_pointer, &checksum_error_msg)) {
    ...
  }
  // 检查是否我们有一个已经打开的oatfile(内存中)
  const OatFile::OatDexFile* oat_dex_file = FindOpenedOatDexFile(oat_location, dex_location,dex_location_checksum_pointer);
  std::unique_ptr<const OatFile> open_oat_file(
      oat_dex_file != nullptr ? oat_dex_file->GetOatFile() : nullptr);
 
  // 检查是否我们有一个可以使用的的oatfile(磁盘上),通过oat_location字符串
  if (open_oat_file.get() == nullptr) {
      open_oat_file.reset(FindOatFileInOatLocationForDexFile(dex_location, dex_location_checksum,oat_location, &error_msg));
      ...
    needs_registering = true;
  }
 
  // 如果我们有一个oat文件,检查所有包含的multidex文件以确定我们的dex位置
  bool success = LoadMultiDexFilesFromOatFile(open_oat_file.get(), dex_location,
                                              dex_location_checksum_pointer,
                                              false, error_msgs, dex_files);
  if (success) {
    const OatFile* oat_file = open_oat_file.release();  // Avoid deleting it.
    if (needs_registering) {
      // We opened the oat file, so we must register it.
      RegisterOatFile(oat_file);
    }
    return oat_file->IsExecutable();
  }
 
  // 如果不是这样(要么没有oat文件,要么不匹配),重新生成并加载oat,通过dex_location字符串
  if (Runtime::Current()->IsDex2OatEnabled() && has_flock && scoped_flock.HasFile()) {
    // Create the oat file.
    open_oat_file.reset(CreateOatFileForDexLocation(dex_location, scoped_flock.GetFile()->Fd(),oat_location, error_msgs));
  }
 
  // Failed, bail.art模式下的解析模式,以上都是编译成oat的编译模式
  if (open_oat_file.get() == nullptr) {
    std::string error_msg;
    // dex2oat was disabled or crashed. Add the dex file in the list of dex_files to make progress.

[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

收藏
免费 5
支持
分享
最新回复 (3)
雪    币: 2089
活跃值: (3933)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
略老
https://github.com/WrBug/DeveloperHelper/blob/develop/xposedmodule/src/main/cpp/util/deviceutils.cpp
可以看看这个,安卓4.x到9脱壳点都有
2021-2-28 02:37
0
雪    币: 26399
活跃值: (63267)
能力值: (RANK:135 )
在线值:
发帖
回帖
粉丝
3
感谢分享!
2021-2-28 20:11
0
雪    币: 5330
活跃值: (5464)
能力值: ( LV9,RANK:170 )
在线值:
发帖
回帖
粉丝
4
2021-3-1 10:10
0
游客
登录 | 注册 方可回帖
返回
//