常见的 DEX 加载方式包括 DexClassLoader
、PathClassLoader
和 BaseDexClassLoader
,可以通过 Hook 这些类的方法来劫持 DEX 加载过程。
1. 使用 Xposed/LSPosed Hook DexClassLoader
在 Android 设备上,如果目标 App 使用 DexClassLoader
进行动态加载 DEX,可以用 Xposed Hook 其 loadClass
方法:
XposedHelpers.findAndHookMethod(
"dalvik.system.DexClassLoader",
lpparam.classLoader,
"loadClass",
String.class,
new XC_MethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
String className = (String) param.args[0];
XposedBridge.log("Loading class: " + className);
}
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
Class<?> loadedClass = (Class<?>) param.getResult();
XposedBridge.log("Loaded class: " + (loadedClass != null ? loadedClass.getName() : "null"));
}
}
);
✅ 适用场景:
- 目标 App 通过
DexClassLoader
动态加载 DEX。 - 可以使用 Xposed/LSPosed。
2. Hook BaseDexClassLoader
以拦截所有 DEX 加载
Android 5.0 以上,DexClassLoader
和 PathClassLoader
继承自 BaseDexClassLoader
,可以直接 Hook BaseDexClassLoader
构造函数:
XposedHelpers.findAndHookConstructor(
"dalvik.system.BaseDexClassLoader",
lpparam.classLoader,
String.class, String.class, String.class, ClassLoader.class,
new XC_MethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) {
String dexPath = (String) param.args[0];
XposedBridge.log("Loading DEX file: " + dexPath);
}
}
);
✅ 适用场景:
- 适用于
DexClassLoader
、PathClassLoader
,通用性更强。
3. Hook dalvik.system.InMemoryDexClassLoader
从 Android 8.0 (API 26) 开始,可以使用 InMemoryDexClassLoader
直接从字节数组加载 DEX:
XposedHelpers.findAndHookConstructor(
"dalvik.system.InMemoryDexClassLoader",
lpparam.classLoader,
ByteBuffer.class, ClassLoader.class,
new XC_MethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) {
XposedBridge.log("Loading DEX from memory!");
}
}
);
✅ 适用场景:
- 适用于 Android 8.0 及以上,目标 App 可能使用
InMemoryDexClassLoader
加载 DEX。
4. Inline Hook DexFile.loadDex
(适用于非 Xposed 场景)
如果你无法使用 Xposed,可以使用 Inline Hook(如 Frida、Inline Hook 框架)直接 Hook DexFile.loadDex()
:
void* (*orig_loadDex)(const char*, const char*, int);
void* my_loadDex(const char* dexPath, const char* odexPath, int flags) {
LOGD("Hooked loadDex: %s", dexPath);
return orig_loadDex(dexPath, odexPath, flags);
}
void hook_loadDex() {
void* addr = dlsym(RTLD_DEFAULT, "DexFile_loadDex");
if (addr) {
HOOK_FUNCTION(addr, my_loadDex, orig_loadDex);
}
}
✅ 适用场景:
- 目标 App 可能调用
DexFile.loadDex()
直接加载 DEX。
5. 使用 Frida 动态 Hook DexClassLoader
如果没有 Xposed,可以用 Frida 进行动态 Hook:
Java.perform(function() {
var DexClassLoader = Java.use("dalvik.system.DexClassLoader");
DexClassLoader.$init.implementation = function(dexPath, optimizedDirectory, libraryPath, parent) {
console.log("Loading DEX: " + dexPath);
return this.$init(dexPath, optimizedDirectory, libraryPath, parent);
};
});
✅ 适用场景:
- 目标设备已 Root,可以使用 Frida 进行动态 Hook。
总结
方法 | 适用场景 | 适用工具 |
---|---|---|
Hook DexClassLoader.loadClass() | 目标 App 使用 DexClassLoader 加载 DEX | Xposed/LSPosed |
Hook BaseDexClassLoader 构造方法 | 拦截所有 DEX 加载方式 | Xposed/LSPosed |
Hook InMemoryDexClassLoader | 适用于 Android 8+ | Xposed/LSPosed |
Inline Hook DexFile.loadDex() | 低级拦截 DEX 加载 | Inline Hook |
Frida Hook DexClassLoader | 目标设备已 Root | Frida |
function hookTest9(){
Java.perform(function(){
Java.enumerateClassLoaders({
onMatch:function(loader){
try{
if(loader.loadClass("com.alexw.app")){
Java.classFactory.loader=loader;
var app=Java.use("com.alexw.app");
console.log(app);
app.sayHello.implementation=function(){
return "bye";
}
}catch(error){
}
},
onComplete:function(){
}
}
});
});
}
https://bbs.kanxue.com/thread-229657.htm
高质量文章