首页
论坛
课程
招聘
[基础理论] [混淆加固] [源码分析] 一招一式讲Android安全--【加固】运行时加载隐藏dex
2021-4-14 21:54 6564

[基础理论] [混淆加固] [源码分析] 一招一式讲Android安全--【加固】运行时加载隐藏dex

2021-4-14 21:54
6564

一招一式讲Android安全--【加固】运行时加载隐藏dex

 

目录

1. 概述

1.1. 背景

本系列会把Android加固一系列的保护原理和思路讲解一遍,仅作为归档整理。
包括dex、so、反调试等。

1.2. 目的

本文主要以Android 9.0代码为蓝本进行研究。
希望把加载隐藏dex的思路和原理讲明白,详细的细节,各个步奏,等等。
如有错误的地方,请联系我改正,谢谢。

1.3. 作者

本文所有权益归chinamima@163.com所有,如需转载请发邮件。
昵称:chinamima
邮箱:chinamima@163.com
经验:从事Android行业10年,Android安全7年,网络安全3年

2. ClassLoader机制介绍

2.1. ClassLoader类关系

ClassLoader类关系
ClassLoader类关系

2.2. ClassLoader部分源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// DexClassLoader.java
public class DexClassLoader extends BaseDexClassLoader {
    public DexClassLoader(String dexPath, String optimizedDirectory,
            String libraryPath, ClassLoader parent) {
        super(dexPath, new File(optimizedDirectory), libraryPath, parent);
    }
}
 
// PathClassLoader.java
public class PathClassLoader extends BaseDexClassLoader {
    public PathClassLoader(String dexPath, ClassLoader parent) {
        super(dexPath, null, null, parent);
    }
 
    public PathClassLoader(String dexPath, String libraryPath,
            ClassLoader parent) {
        super(dexPath, null, libraryPath, parent);
    }
}
  • DexClassLoaderPathClassLoader都可以加载外部dex。
  • 两个类的区别在于DexClassLoader可以指定optimizedDirectory,但在android 8.0以后optimizedDirectory已经废弃掉了。
  • optimizedDirectorydex2oat生成的.oat.odex文件存放位置。
  • optimizedDirectory为空,则会在默认位置生成.oat.odex文件,因此源码里用PathClassLoader作为ClassLoader的实例化类。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    //android 8.0
    public BaseDexClassLoader(String dexPath, File optimizedDirectory,
            String librarySearchPath, ClassLoader parent) {
        this(dexPath, optimizedDirectory, librarySearchPath, parent, false);
    }
     
    public BaseDexClassLoader(String dexPath, File optimizedDirectory,
            String librarySearchPath, ClassLoader parent, boolean isTrusted) {
        super(parent);
        this.pathList = new DexPathList(this, dexPath, librarySearchPath, null, isTrusted);
     
        if (reporter != null) {
            reportClassLoaderChain();
        }
    }

    BaseDexClassLoader的构造函数并没有把optimizedDirectory传递给DexPathList

3. 初始化ClassLoader

3.1. 调用链路

1
2
3
4
5
6
7
8
9
ActivityThread.performLaunchActivity //启动activity
 ├─ ActivityThread.createBaseContextForActivity //创建ContextImpl,并作为app的Context实现
 │    └─ ContextImpl.createActivityContext //从LoadedApk获取ClassLoader,并创建ContextImpl
 │        └─ LoadedApk.getClassLoader //判断是否已有ClassLoader,如无则调用createOrUpdateClassLoaderLocked
 │            └─ LoadedApk.createOrUpdateClassLoaderLocked
 │                └─ ApplicationLoaders.getClassLoader
 │                    └─ ClassLoaderFactory.createClassLoader
 │                        └─ new PathClassLoader
 └─ ContextImpl.getClassLoader //LoadedApk.getClassLoader已经生成了ClassLoader,并存于ContextImpl的mClassLoader中

3.2. 详细源码

3.2.1. ActivityThread.performLaunchActivity

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
package android.app;
 
public final class ActivityThread extends ClientTransactionHandler {
    /**  Core implementation of activity launch. */
    private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
        //...省略,chinamima
        // ==========>>> 创建ContextImpl <<<==========
        ContextImpl appContext = createBaseContextForActivity(r);
        Activity activity = null;
        try {
            //从ContextImpl里获取ClassLoader
            java.lang.ClassLoader cl = appContext.getClassLoader();
            activity = mInstrumentation.newActivity(
                    cl, component.getClassName(), r.intent);
             //...省略,chinamima
        } catch (Exception e) {
            //...省略,chinamima
        }
 
        try {
            Application app = r.packageInfo.makeApplication(false, mInstrumentation);
            //...省略,chinamima
            if (activity != null) {
                //...省略,chinamima
                appContext.setOuterContext(activity);
                activity.attach(appContext, this, getInstrumentation(), r.token,
                        r.ident, app, r.intent, r.activityInfo, title, r.parent,
                        r.embeddedID, r.lastNonConfigurationInstances, config,
                        r.referrer, r.voiceInteractor, window, r.configCallback);
                //...省略,chinamima
                if (r.isPersistable()) {
                    mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
                } else {
                    mInstrumentation.callActivityOnCreate(activity, r.state);
                }
                //...省略,chinamima
                r.activity = activity;
            }
            mActivities.put(r.token, r);
        } catch (SuperNotCalledException e) {
            throw e;
        } catch (Exception e) {
            //...省略,chinamima
        }
 
        return activity;
    }
}

3.2.2. ActivityThread.createBaseContextForActivity

1
2
3
4
5
6
7
8
9
10
11
12
13
14
package android.app;
 
public final class ActivityThread extends ClientTransactionHandler {
 
    private ContextImpl createBaseContextForActivity(ActivityClientRecord r) {
        int displayId = ActivityManager.getService().getActivityDisplayId(r.token);
        //...省略,chinamima
        // ==========>>> 生成ContextImpl实例,里面会生成一个默认ClassLoader成员变量 <<<==========
        ContextImpl appContext = ContextImpl.createActivityContext(
                this, r.packageInfo, r.activityInfo, r.token, displayId, r.overrideConfig);
        //...省略,chinamima
        return appContext;
    }
}

3.2.3. ContextImpl.createActivityContext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package android.app;
 
class ContextImpl extends Context {
    static ContextImpl createActivityContext(ActivityThread mainThread,
            LoadedApk packageInfo, ActivityInfo activityInfo, IBinder activityToken, int displayId,
            Configuration overrideConfiguration) {
        //...省略,chinamima
        // ==========>>> 从LoadedApk里获取ClassLoader <<<==========
        ClassLoader classLoader = packageInfo.getClassLoader();
        //...省略,chinamima
        //创建一个ContextImpl实例
        ContextImpl context = new ContextImpl(null, mainThread, packageInfo, activityInfo.splitName,
                activityToken, null, 0, classLoader);
        //...省略,chinamima
        return context;
    }
}

3.2.4. LoadedApk.getClassLoader

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package android.app;
public final class LoadedApk {
 
    private ClassLoader mClassLoader;
 
    public ClassLoader getClassLoader() {
        synchronized (this) {
            if (mClassLoader == null) {
                // ==========>>> 关键步奏 <<<==========
                createOrUpdateClassLoaderLocked(null /*addedPaths*/);
            }
            return mClassLoader;
        }
    }
}

调用createOrUpdateClassLoaderLocked

3.2.5. LoadedApk.createOrUpdateClassLoaderLocked

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
package android.app;
public final class LoadedApk {
 
    private void createOrUpdateClassLoaderLocked(List<String> addedPaths) {
        //...省略,chinamima
 
        // If we're not asked to include code, we construct a classloader that has
        // no code path included. We still need to set up the library search paths
        // and permitted path because NativeActivity relies on it (it attempts to
        // call System.loadLibrary() on a classloader from a LoadedApk with
        // mIncludeCode == false).
        if (!mIncludeCode) {
            if (mClassLoader == null) {
                //...省略,chinamima
                // ==========>>> 关键步奏 <<<==========
                mClassLoader = ApplicationLoaders.getDefault().getClassLoader(
                        "" /* codePath */, mApplicationInfo.targetSdkVersion, isBundledApp,
                        librarySearchPath, libraryPermittedPath, mBaseClassLoader,
                        null /* classLoaderName */);
                //...省略,chinamima
            }
 
            return;
        }
        //...省略,chinamima
    }
}

调用ApplicationLoaders.getClassLoader获取ClassLoader

3.2.6. ApplicationLoaders.getClassLoader

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
package android.app;
 
public class ApplicationLoaders {
    public static ApplicationLoaders getDefault() {
        return gApplicationLoaders;
    }
 
    ClassLoader getClassLoader(String zip, int targetSdkVersion, boolean isBundled,
                               String librarySearchPath, String libraryPermittedPath,
                               ClassLoader parent, String classLoaderName) {
        // For normal usage the cache key used is the same as the zip path.
        // ==========>>> 调用另一个getClassLoader <<<==========
        return getClassLoader(zip, targetSdkVersion, isBundled, librarySearchPath,
                              libraryPermittedPath, parent, zip, classLoaderName);
    }
 
    private ClassLoader getClassLoader(String zip, int targetSdkVersion, boolean isBundled,
                                       String librarySearchPath, String libraryPermittedPath,
                                       ClassLoader parent, String cacheKey,
                                       String classLoaderName) {
        /*
         * This is the parent we use if they pass "null" in.  In theory
         * this should be the "system" class loader; in practice we
         * don't use that and can happily (and more efficiently) use the
         * bootstrap class loader.
         */
        ClassLoader baseParent = ClassLoader.getSystemClassLoader().getParent();
 
        synchronized (mLoaders) {
            if (parent == null) {
                parent = baseParent;
            }
 
            /*
             * If we're one step up from the base class loader, find
             * something in our cache.  Otherwise, we create a whole
             * new ClassLoader for the zip archive.
             */
            if (parent == baseParent) {
                ClassLoader loader = mLoaders.get(cacheKey);
                if (loader != null) {
                    return loader;
                }
                //...省略,chinamima
                // ==========>>> 工厂模式生成PathClassLoader实例 <<<==========
                ClassLoader classloader = ClassLoaderFactory.createClassLoader(
                        zip,  librarySearchPath, libraryPermittedPath, parent,
                        targetSdkVersion, isBundled, classLoaderName);
                //...省略,chinamima
                mLoaders.put(cacheKey, classloader);
                return classloader;
            }
 
            // ==========>>> 工厂模式生成PathClassLoader实例 <<<==========
            ClassLoader loader = ClassLoaderFactory.createClassLoader(
                    zip, null, parent, classLoaderName);
            return loader;
        }
    }
 
    private final ArrayMap<String, ClassLoader> mLoaders = new ArrayMap<>();
 
    private static final ApplicationLoaders gApplicationLoaders = new ApplicationLoaders();

mLoader已存在,则直接返回。
mLoader不存在,则调用ClassLoaderFactory.createClassLoader创建。

3.2.7. ClassLoaderFactory.createClassLoader

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
package com.android.internal.os;
 
public class ClassLoaderFactory {
 
    public static ClassLoader createClassLoader(String dexPath,
            String librarySearchPath, ClassLoader parent, String classloaderName) {
        if (isPathClassLoaderName(classloaderName)) {
            // ==========>>> 新建PathClassLoader实例 <<<==========
            return new PathClassLoader(dexPath, librarySearchPath, parent);
        } else if (isDelegateLastClassLoaderName(classloaderName)) {
            return new DelegateLastClassLoader(dexPath, librarySearchPath, parent);
        }
 
        throw new AssertionError("Invalid classLoaderName: " + classloaderName);
    }
 
    public static ClassLoader createClassLoader(String dexPath,
            String librarySearchPath, String libraryPermittedPath, ClassLoader parent,
            int targetSdkVersion, boolean isNamespaceShared, String classloaderName) {
 
        // ==========>>> 调用另一个createClassLoader <<<==========
        final ClassLoader classLoader = createClassLoader(dexPath, librarySearchPath, parent,
                classloaderName);
        //...省略,chinamima
        return classLoader;
    }
}

新建一个PathClassLoader实例。

4. findClass源码路径

4.1. BaseDexClassLoader

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package dalvik.system;
public class BaseDexClassLoader extends ClassLoader {
    private final DexPathList pathList;
 
    public BaseDexClassLoader(String dexPath, File optimizedDirectory,
            String librarySearchPath, ClassLoader parent, boolean isTrusted) {
        super(parent);
        this.pathList = new DexPathList(this, dexPath, librarySearchPath, null, isTrusted);
        //...省略,chinamima
    }
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        // ==========>>> 从DexPathList里找类 <<<==========
        Class c = pathList.findClass(name, suppressedExceptions);
        //...省略,chinamima
        return c;
    }   
 
}

4.2. DexPathList

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package dalvik.system;
final class DexPathList {
    private Element[] dexElements;
 
    public Class<?> findClass(String name, List<Throwable> suppressed) {
        for (Element element : dexElements) {
            // ==========>>> 从Element里找类 <<<==========
            Class<?> clazz = element.findClass(name, definingContext, suppressed);
            if (clazz != null) {
                return clazz;
            }
        }
        //...省略,chinamima
        return null;
    }
}

4.3. Element

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
static class Element {
    private final File path;
    private final DexFile dexFile;
 
    public Element(DexFile dexFile, File dexZipPath) {
        this.dexFile = dexFile;
        this.path = dexZipPath;
    }
 
    public Class<?> findClass(String name, ClassLoader definingContext,
            List<Throwable> suppressed) {
        // ==========>>> 从DexFile里找类 <<<==========
        return dexFile != null ? dexFile.loadClassBinaryName(name, definingContext, suppressed)
                : null;
    }
}

4.4. DexFile

java/dalvik/system/DexFile.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public final class DexFile {
    private Object mCookie;
 
    public Class loadClassBinaryName(String name, ClassLoader loader, List<Throwable> suppressed) {
        return defineClass(name, loader, mCookie, this, suppressed);
    }
 
    private static Class defineClass(String name, ClassLoader loader, Object cookie,
                                     DexFile dexFile, List<Throwable> suppressed) {
        Class result = null;
        try {
            // ==========>>> 关键步奏 <<<==========
            result = defineClassNative(name, loader, cookie, dexFile);
        } catch (NoClassDefFoundError e) {
        } catch (ClassNotFoundException e) {
        }
        return result;
    }
 
    private static native Class defineClassNative(String name, ClassLoader loader, Object cookie,
                                                  DexFile dexFile);
}

4.5. dalvik_system_DexFile

/art/runtime/native/dalvik_system_DexFile.cc

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
static jclass DexFile_defineClassNative(JNIEnv* env,
                                        jclass,
                                        jstring javaName,
                                        jobject javaLoader,
                                        jobject cookie,
                                        jobject dexFile) {
  std::vector<const DexFile*> dex_files;
  const OatFile* oat_file;
  if (!ConvertJavaArrayToDexFiles(env, cookie, /*out*/ dex_files, /*out*/ oat_file)) {
    //...省略,chinamima
    return nullptr;
  }
 
  ScopedUtfChars class_name(env, javaName);
  //...省略,chinamima
  const std::string descriptor(DotToDescriptor(class_name.c_str()));
  const size_t hash(ComputeModifiedUtf8Hash(descriptor.c_str()));
  for (auto& dex_file : dex_files) {
    const DexFile::ClassDef* dex_class_def =
        OatDexFile::FindClassDef(*dex_file, descriptor.c_str(), hash);
    if (dex_class_def != nullptr) {
      ScopedObjectAccess soa(env);
      ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
      StackHandleScope<1> hs(soa.Self());
      Handle<mirror::ClassLoader> class_loader(
          hs.NewHandle(soa.Decode<mirror::ClassLoader>(javaLoader)));
      ObjPtr<mirror::DexCache> dex_cache =
          class_linker->RegisterDexFile(*dex_file, class_loader.Get());
      //...省略,chinamima
      // ==========>>> 关键步奏 <<<==========
      ObjPtr<mirror::Class> result = class_linker->DefineClass(soa.Self(),
                                                               descriptor.c_str(),
                                                               hash,
                                                               class_loader,
                                                               *dex_file,
                                                               *dex_class_def);
      class_linker->InsertDexFileInToClassLoader(soa.Decode<mirror::Object>(dexFile),
                                                 class_loader.Get());
      if (result != nullptr) {
        VLOG(class_linker) << "DexFile_defineClassNative returning " << result
                           << " for " << class_name.c_str();
        return soa.AddLocalReference<jclass>(result);
      }
    }
  }
  VLOG(class_linker) << "Failed to find dex_class_def " << class_name.c_str();
  return nullptr;
}

cookie通过ConvertJavaArrayToDexFiles(env, cookie, /*out*/ dex_files, /*out*/ oat_file)转换成DexFile*实例。
再通过class_linker->DefineClassDexFile*里加载类。

5. 替换mCookie

5.1. 关键点

可以看到DexFile_defineClassNative里的ConvertJavaArrayToDexFiles函数把cookiedex_filesoat_file关联了起来。

/art/runtime/native/dalvik_system_DexFile.cc

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
static jclass DexFile_defineClassNative(JNIEnv* env,
                                        jclass,
                                        jstring javaName,
                                        jobject javaLoader,
                                        jobject cookie,
                                        jobject dexFile) {
  std::vector<const DexFile*> dex_files;
  const OatFile* oat_file;
  if (!ConvertJavaArrayToDexFiles(env, cookie, /*out*/ dex_files, /*out*/ oat_file)) {
    VLOG(class_linker) << "Failed to find dex_file";
    DCHECK(env->ExceptionCheck());
    return nullptr;
  }
  //...省略,chinamima
}

从这里可以猜测得出,cookiedex_filesoat_file是一对一关系的。
因此,只需要把cookie替换成另一个dex的值,就可以加载另一个dex的类。

5.2. 思路

替换cookie值在native层比较难操作,因此我们把目光放到java层。

java/dalvik/system/DexFile.java

1
2
3
4
5
6
7
8
9
10
public final class DexFile {
    private Object mCookie;
 
    DexFile(String fileName, ClassLoader loader, DexPathList.Element[] elements) throws IOException {
        mCookie = openDexFile(fileName, null, 0, loader, elements);
        mInternalCookie = mCookie;
        mFileName = fileName;
    }
    //...省略,chinamima
}

DexFile里也有一个mCookie,通过defineClassNative传参到DexFile_defineClassNative的。
也就是替换mCookie即可达成目的--加载其他dex。

5.3. 实现

根据DexFile的构造函数可知。
调用DexFileopenDexFile得到一个新的cookie,用于替换原始的mCookie

5.4. 思考

  • openDexFile需要一个dex的路径,也就是dex需要作为文件释放到某处,容易被截获。
  • art模式下,openDexFile会调用dex2oat生成oat文件,造成一定的性能损耗。

6. 替换ClassLoader

6.1. 覆盖ClassLoader成员变量

RePlugin的全局只hook一处的方案

6.2. 替换LoadedApk里ClassLoader

初始化ClassLoader的调用链路可知,LoadedApk保存了ClassLoader的实例,实际上这个实例就是findClass时用到的PathClassLoader
因此,新new一个ClassLoader并替换掉LoadedApk里的mClassLoader即能实现替换dex效果。

7. 添加到DexPathList

1
2
3
4
5
6
7
8
9
10
11
12
package dalvik.system;
public class BaseDexClassLoader extends ClassLoader {
    private final DexPathList pathList;
 
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        Class c = pathList.findClass(name, suppressedExceptions);
        if (c == null) {
            //...省略,chinamima
        }
        return c;
    }       
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package dalvik.system;
final class DexPathList {
    private Element[] dexElements;
 
    public Class<?> findClass(String name, List<Throwable> suppressed) {
        for (Element element : dexElements) {
            Class<?> clazz = element.findClass(name, definingContext, suppressed);
            if (clazz != null) {
                return clazz;
            }
        }
        //...省略,chinamima
        return null;
    }
}

从上面代码可知,ClassLoader是从DexPathList pathList里加载class的。
DexPathList是由Element[] dexElements组成的,在findClass最先从数组最前面取Element
因此,我们可以在DexPathList.dexElements的前面插入隐藏dex的Element,从而实现加载隐藏dex。

8. 直接加载dex byte

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public final class DexFile {
    private Object mCookie;
 
    DexFile(ByteBuffer buf) throws IOException {
        mCookie = openInMemoryDexFile(buf);
        mInternalCookie = mCookie;
        mFileName = null;
    }
 
    private static Object openInMemoryDexFile(ByteBuffer buf) throws IOException {
        if (buf.isDirect()) {
            return createCookieWithDirectBuffer(buf, buf.position(), buf.limit());
        } else {
            return createCookieWithArray(buf.array(), buf.position(), buf.limit());
        }
    }
}

发现DexFile.openInMemoryDexFile可以直接加载buffer,因此可以从内存中加载dex。

8.1. 从内存中加载dex,避免生成oat

8.1.1. 调用链路

1
2
3
4
5
6
7
DexFile.openInMemoryDexFile
 ├─ DexFile_createCookieWithDirectBuffer
 │  └─ CreateSingleDexFileCookie
 │      └─ CreateDexFile
 │          └─ ArtDexFileLoader::open
 │              └─ ArtDexFileLoader::OpenCommon
 └──────── ConvertDexFilesToJavaArray

关键点在于ArtDexFileLoader::open,此处传递了一个kNoOatDexFile参数,明显是无oat文件的意思。

8.1.2. 详细源码

dalvik_system_DexFile.cc

1
2
3
4
5
6
7
8
9
10
11
static jobject DexFile_createCookieWithDirectBuffer(JNIEnv* env,
                                                    jclass,
                                                    jobject buffer,
                                                    jint start,
                                                    jint end) {
  //...省略,chinamima
  std::unique_ptr<MemMap> dex_mem_map(AllocateDexMemoryMap(env, start, end));
  //...省略,chinamima
  //创建单个DexFile实例,并转成cookie
  return CreateSingleDexFileCookie(env, std::move(dex_mem_map));
}
1
2
3
4
5
6
7
8
9
10
11
12
static jobject CreateSingleDexFileCookie(JNIEnv* env, std::unique_ptr<MemMap> data) {
  //创建DexFile
  std::unique_ptr<const DexFile> dex_file(CreateDexFile(env, std::move(data)));
  if (dex_file.get() == nullptr) {
    DCHECK(env->ExceptionCheck());
    return nullptr;
  }
  std::vector<std::unique_ptr<const DexFile>> dex_files;
  dex_files.push_back(std::move(dex_file));
  //转成cookie
  return ConvertDexFilesToJavaArray(env, nullptr, dex_files);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
static const DexFile* CreateDexFile(JNIEnv* env, std::unique_ptr<MemMap> dex_mem_map) {
  std::string location = StringPrintf("Anonymous-DexFile@%p-%p",
                                      dex_mem_map->Begin(),
                                      dex_mem_map->End());
  std::string error_message;
  const ArtDexFileLoader dex_file_loader;
  //打开DexFile
  std::unique_ptr<const DexFile> dex_file(dex_file_loader.Open(location, //Anonymous-DexFile@0xaabbccdd-0xeeff0011
                                                               0,
                                                               std::move(dex_mem_map),
                                                               /* verify */ true,
                                                               /* verify_location */ true,
                                                               &error_message));
  //...省略,chinamima
  return dex_file.release();
}

art_dex_file_loader.cc

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
static constexpr OatDexFile* kNoOatDexFile = nullptr;
 
std::unique_ptr<const DexFile> ArtDexFileLoader::Open(const uint8_t* base,
                                                      size_t size,
                                                      const std::string& location,
                                                      uint32_t location_checksum,
                                                      const OatDexFile* oat_dex_file,
                                                      bool verify,
                                                      bool verify_checksum,
                                                      std::string* error_msg) const {
  ScopedTrace trace(std::string("Open dex file from RAM ") + location);
  return OpenCommon(base,
                    size,
                    /*data_base*/ nullptr,
                    /*data_size*/ 0u,
                    location,
                    location_checksum,
                    oat_dex_file,         //有oat文件
                    verify,
                    verify_checksum,
                    error_msg,
                    /*container*/ nullptr,
                    /*verify_result*/ nullptr);
}
 
std::unique_ptr<const DexFile> ArtDexFileLoader::Open(const std::string& location,
                                                      uint32_t location_checksum,
                                                      std::unique_ptr<MemMap> map,
                                                      bool verify,
                                                      bool verify_checksum,
                                                      std::string* error_msg) const {
  //...省略,chinamima
  std::unique_ptr<DexFile> dex_file = OpenCommon(map->Begin(),
                                                 map->Size(),
                                                 /*data_base*/ nullptr,
                                                 /*data_size*/ 0u,
                                                 location,
                                                 location_checksum,
                                                 kNoOatDexFile,           //无oat文件!
                                                 verify,
                                                 verify_checksum,
                                                 error_msg,
                                                 std::make_unique<MemMapContainer>(std::move(map)),
                                                 /*verify_result*/ nullptr);
  //...省略,chinamima
  return dex_file;
}

第五届安全开发者峰会(SDC 2021)议题征集正式开启!

最后于 2021-4-21 10:59 被chinamima编辑 ,原因: 调整格式,提示关键步奏
收藏
点赞8
打赏
分享
最新回复 (13)
雪    币: 739
活跃值: 活跃值 (207)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
至尊小仙侠 活跃值 2021-4-15 11:06
2
0
写的很不错  哥哥 
雪    币: 8284
活跃值: 活跃值 (2269)
能力值: (RANK:200 )
在线值:
发帖
回帖
粉丝
LowRebSwrd 活跃值 4 2021-4-15 11:11
3
0
整理的真好
雪    币: 513
活跃值: 活跃值 (334)
能力值: (RANK:400 )
在线值:
发帖
回帖
粉丝
莫灰灰 活跃值 9 2021-4-16 10:16
4
0
学习了。
雪    币: 214
活跃值: 活跃值 (119)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
tea9 活跃值 2021-4-16 10:24
5
0
哥哥 写的真好!
雪    币: 871
活跃值: 活跃值 (635)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
Youlor 活跃值 2021-4-16 18:01
6
0
写的挺好的一篇文章
雪    币: 8
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
万里星河 活跃值 2021-4-17 01:12
7
0
优秀
雪    币: 190
活跃值: 活跃值 (51)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
wsgaoshou 活跃值 2021-4-17 17:37
8
0
想努力看懂
雪    币: 8
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
huangbof 活跃值 2021-4-19 13:59
9
0
我想知道这有用吗?全部载入内存后一下子dump出来了
雪    币: 214
活跃值: 活跃值 (421)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
chinamima 活跃值 2021-4-21 09:47
10
0
huangbof 我想知道这有用吗?全部载入内存后一下子dump出来了
防dump那是下一步的加固方案了,只要是在内存中还是完整的dex,就能dump
雪    币: 5955
活跃值: 活跃值 (2545)
能力值: ( LV9,RANK:170 )
在线值:
发帖
回帖
粉丝
GitRoy 活跃值 3 2021-4-23 11:19
11
0
学习了!!
雪    币: 50
活跃值: 活跃值 (20)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
卡卡超人 活跃值 2021-4-23 19:34
12
0
加载内存里的 dex 直接 InMemoryDexClassLoader 不就好?再者,mCookie 和 DexFile 等接口已经被加入隐藏 API 列表了,要用还得考虑绕过隐藏 API 限制呢。
雪    币: 1262
活跃值: 活跃值 (320)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
残页 活跃值 2021-4-23 19:43
13
0
加载内存里的 dex 直接 InMemoryDexClassLoader 不就好?再者,mCookie 和 DexFile 等接口已经被加入隐藏 API 列表了,要用还得考虑绕过隐藏 API 限制呢。
雪    币: 203
活跃值: 活跃值 (123)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
yujincheng08 活跃值 2021-4-25 18:54
14
0
加载内存里的 dex 直接 InMemoryDexClassLoader 不就好?再者,mCookie 和 DexFile 等接口已经被加入隐藏 API 列表了,要用还得考虑绕过隐藏 API 限制呢。
游客
登录 | 注册 方可回帖
返回