一招一式讲Android安全--【加固】运行时加载隐藏dex
本系列会把Android加固一系列的保护原理和思路讲解一遍,仅作为归档整理。
包括dex、so、反调试等。
本文主要以Android 9.0代码为蓝本进行研究。
希望把加载隐藏dex的思路和原理讲明白,详细的细节,各个步奏,等等。
如有错误的地方,请联系我改正,谢谢。
本文所有权益归chinamima@163.com所有,如需转载请发邮件。
昵称:chinamima
邮箱:chinamima@163.com
经验:从事Android行业10年,Android安全7年,网络安全3年
optimizedDirectory
为空,则会在默认位置生成.oat
、.odex
文件,因此源码里用PathClassLoader
作为ClassLoader
的实例化类。
BaseDexClassLoader
的构造函数并没有把optimizedDirectory
传递给DexPathList
。
调用createOrUpdateClassLoaderLocked
。
调用ApplicationLoaders.getClassLoader
获取ClassLoader
。
如mLoader
已存在,则直接返回。
如mLoader
不存在,则调用ClassLoaderFactory.createClassLoader
创建。
新建一个PathClassLoader实例。
java/dalvik/system/DexFile.java
/art/runtime/native/dalvik_system_DexFile.cc
cookie
通过ConvertJavaArrayToDexFiles(env, cookie, /*out*/ dex_files, /*out*/ oat_file)
转换成DexFile*
实例。
再通过class_linker->DefineClass
从DexFile*
里加载类。
可以看到DexFile_defineClassNative
里的ConvertJavaArrayToDexFiles
函数把cookie
和dex_files
、oat_file
关联了起来。
/art/runtime/native/dalvik_system_DexFile.cc
从这里可以猜测得出,cookie
和dex_files
、oat_file
是一对一关系的。
因此,只需要把cookie
替换成另一个dex的值,就可以加载另一个dex的类。
替换cookie
值在native层比较难操作,因此我们把目光放到java层。
java/dalvik/system/DexFile.java
在DexFile
里也有一个mCookie
,通过defineClassNative
传参到DexFile_defineClassNative
的。
也就是替换mCookie
即可达成目的--加载其他dex。
根据DexFile
的构造函数可知。
调用DexFile
的openDexFile
得到一个新的cookie
,用于替换原始的mCookie
。
由初始化ClassLoader
的调用链路可知,LoadedApk
保存了ClassLoader
的实例,实际上这个实例就是findClass
时用到的PathClassLoader
。
因此,新new一个ClassLoader
并替换掉LoadedApk
里的mClassLoader
即能实现替换dex效果。
从上面代码可知,ClassLoader
是从DexPathList pathList
里加载class的。
而DexPathList
是由Element[] dexElements
组成的,在findClass
最先从数组最前面取Element
。
因此,我们可以在DexPathList.dexElements
的前面插入隐藏dex的Element
,从而实现加载隐藏dex。
发现DexFile.openInMemoryDexFile
可以直接加载buffer,因此可以从内存中加载dex。
关键点在于ArtDexFileLoader::open
,此处传递了一个kNoOatDexFile
参数,明显是无oat
文件的意思。
dalvik_system_DexFile.cc
art_dex_file_loader.cc
/
/
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);
}
}
/
/
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);
}
}
/
/
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();
}
}
/
/
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();
}
}
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中
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中
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;
}
}
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;
}
}
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;
}
}
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;
}
}
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;
}
}
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;
}
}
package android.app;
public final
class
LoadedApk {
private ClassLoader mClassLoader;
public ClassLoader getClassLoader() {
synchronized (this) {
if
(mClassLoader
=
=
null) {
/
/
=
=
=
=
=
=
=
=
=
=
>>> 关键步奏 <<<
=
=
=
=
=
=
=
=
=
=
createOrUpdateClassLoaderLocked(null
/
*
addedPaths
*
/
);
}
return
mClassLoader;
}
}
}
package android.app;
public final
class
LoadedApk {
private ClassLoader mClassLoader;
public ClassLoader getClassLoader() {
synchronized (this) {
if
(mClassLoader
=
=
null) {
/
/
=
=
=
=
=
=
=
=
=
=
>>> 关键步奏 <<<
=
=
=
=
=
=
=
=
=
=
createOrUpdateClassLoaderLocked(null
/
*
addedPaths
*
/
);
}
return
mClassLoader;
}
}
}
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
}
}
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
}
}
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();
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();
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;
}
}
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;
}
}
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;
}
}
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;
}
}
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;
}
}
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;
}
}
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;
}
}
static
class
Element {
private final
File
path;
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)
最后于 2021-4-21 10:59
被chinamima编辑
,原因: 调整格式,提示关键步奏