Fix native crashes in R
This commit is contained in:
parent
1cc8751c8c
commit
b577d4c2b3
|
|
@ -2,6 +2,8 @@ package com.elderdrivers.riru.edxp._hooker.yahfa;
|
|||
|
||||
import com.elderdrivers.riru.common.KeepMembers;
|
||||
import com.elderdrivers.riru.edxp._hooker.impl.HandleBindApp;
|
||||
import com.elderdrivers.riru.edxp.core.Yahfa;
|
||||
import com.elderdrivers.riru.edxp.util.Hookers;
|
||||
|
||||
import de.robv.android.xposed.XC_MethodHook;
|
||||
import de.robv.android.xposed.annotation.ApiSensitive;
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import com.elderdrivers.riru.edxp.deopt.PrebuiltMethodsDeopter;
|
|||
import com.elderdrivers.riru.edxp.hook.HookProvider;
|
||||
|
||||
import java.lang.reflect.Member;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
public abstract class BaseHookProvider implements HookProvider {
|
||||
|
||||
|
|
@ -47,7 +48,7 @@ public abstract class BaseHookProvider implements HookProvider {
|
|||
|
||||
@Override
|
||||
public boolean methodHooked(Member target) {
|
||||
return HookMain.hooked(target);
|
||||
return Yahfa.isHooked((Method)target);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -8,11 +8,15 @@ public class Yahfa {
|
|||
public static native boolean backupAndHookNative(Object target, Method hook, Method backup);
|
||||
|
||||
// JNI.ToReflectedMethod() could return either Method or Constructor
|
||||
public static native Object findMethodNative(Class targetClass, String methodName, String methodSig);
|
||||
public static native Member findMethodNative(Class targetClass, String methodName, String methodSig);
|
||||
|
||||
public static native void init(int sdkVersion);
|
||||
|
||||
public static native void setMethodNonCompilable(Member member);
|
||||
|
||||
public static native boolean setNativeFlag(Member member, boolean isNative);
|
||||
|
||||
public static native void recordHooked(Member member);
|
||||
|
||||
public static native boolean isHooked(Member member);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,8 @@
|
|||
package com.elderdrivers.riru.edxp.core.yahfa;
|
||||
|
||||
import android.os.Build;
|
||||
|
||||
import com.elderdrivers.riru.edxp.art.ClassLinker;
|
||||
import com.elderdrivers.riru.edxp.art.Heap;
|
||||
import com.elderdrivers.riru.edxp.core.Yahfa;
|
||||
import com.elderdrivers.riru.edxp.util.Utils;
|
||||
|
|
@ -15,6 +18,8 @@ import java.util.List;
|
|||
import java.util.Set;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
|
||||
import de.robv.android.xposed.PendingHooks;
|
||||
import de.robv.android.xposed.XposedBridge;
|
||||
import de.robv.android.xposed.XposedHelpers;
|
||||
|
||||
public class HookMain {
|
||||
|
|
@ -25,12 +30,6 @@ public class HookMain {
|
|||
hookItemWhiteList.add(className);
|
||||
}
|
||||
|
||||
private static List<Object> hookedList = new CopyOnWriteArrayList();
|
||||
|
||||
public static boolean hooked(Member target) {
|
||||
return hookedList.contains(target);
|
||||
}
|
||||
|
||||
public static void doHookDefault(ClassLoader patchClassLoader, ClassLoader originClassLoader, String hookInfoClassName) {
|
||||
try {
|
||||
Class<?> hookInfoClass = Class.forName(hookInfoClassName, true, patchClassLoader);
|
||||
|
|
@ -97,11 +96,11 @@ public class HookMain {
|
|||
backupAndHook(findMethod(targetClass, methodName, methodSig), hook, backup);
|
||||
}
|
||||
|
||||
public static void hook(Object target, Method hook) {
|
||||
public static void hook(Member target, Method hook) {
|
||||
backupAndHook(target, hook, null);
|
||||
}
|
||||
|
||||
public static void backupAndHook(Object target, Method hook, Method backup) {
|
||||
public static void backupAndHook(Member target, Method hook, Method backup) {
|
||||
Utils.logD(String.format("target=%s, hook=%s, backup=%s", target, hook, backup));
|
||||
if (target == null) {
|
||||
throw new IllegalArgumentException("null target method");
|
||||
|
|
@ -132,11 +131,12 @@ public class HookMain {
|
|||
if (!Yahfa.backupAndHookNative(target, hook, backup)) {
|
||||
throw new RuntimeException("Failed to hook " + target + " with " + hook);
|
||||
} else {
|
||||
hookedList.add(target);
|
||||
Yahfa.recordHooked(target);
|
||||
Yahfa.recordHooked(backup);
|
||||
}
|
||||
}
|
||||
|
||||
public static Object findMethod(Class cls, String methodName, String methodSig) {
|
||||
public static Member findMethod(Class cls, String methodName, String methodSig) {
|
||||
if (cls == null) {
|
||||
throw new IllegalArgumentException("null class");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,10 +13,10 @@ static int OFFSET_entry_point_from_interpreter_in_ArtMethod;
|
|||
static int OFFSET_entry_point_from_quick_compiled_code_in_ArtMethod;
|
||||
static int OFFSET_ArtMehod_in_Object;
|
||||
static int OFFSET_access_flags_in_ArtMethod;
|
||||
static int kAccNative = 0x0100;
|
||||
static int kAccCompileDontBother = 0x01000000;
|
||||
static int kAccFastInterpreterToInterpreterInvoke = 0x40000000;
|
||||
static int kAccPreCompiled = 0x00200000;
|
||||
static uint32_t kAccNative = 0x0100;
|
||||
static uint32_t kAccCompileDontBother = 0x01000000;
|
||||
static uint32_t kAccFastInterpreterToInterpreterInvoke = 0x40000000;
|
||||
static uint32_t kAccPreCompiled = 0x00200000;
|
||||
|
||||
static jfieldID fieldArtMethod = NULL;
|
||||
|
||||
|
|
@ -107,30 +107,26 @@ void setNonCompilable(void *method) {
|
|||
if (SDKVersion < __ANDROID_API_N__) {
|
||||
return;
|
||||
}
|
||||
int access_flags = getFlags(method);
|
||||
int old_flags = access_flags;
|
||||
uint32_t access_flags = getFlags(method);
|
||||
uint32_t old_flags = access_flags;
|
||||
access_flags |= kAccCompileDontBother;
|
||||
setFlags(method, access_flags);
|
||||
LOGI("setNonCompilable: change access flags from 0x%x to 0x%x", old_flags, access_flags);
|
||||
}
|
||||
|
||||
bool setNativeFlag(void *method, bool isNative) {
|
||||
int access_flags = getFlags(method);
|
||||
int old_flags = access_flags;
|
||||
uint32_t access_flags = getFlags(method);
|
||||
uint32_t old_flags = access_flags;
|
||||
LOGI("setNativeFlag: access flags is 0x%x", access_flags);
|
||||
int old_access_flags = access_flags;
|
||||
uint32_t old_access_flags = access_flags;
|
||||
if (isNative) {
|
||||
// TODO: Temporally disable native for compatible with Android R,
|
||||
// but we should keep this and MarkInitializedClassVisiblyInitialized
|
||||
if (SDKVersion < __ANDROID_API_R__)
|
||||
access_flags |= kAccNative;
|
||||
access_flags |= kAccNative;
|
||||
if (SDKVersion >= __ANDROID_API_Q__) {
|
||||
// On API 29 whether to use the fast path or not is cached in the ART method structure
|
||||
access_flags &= ~kAccFastInterpreterToInterpreterInvoke;
|
||||
}
|
||||
} else {
|
||||
if (SDKVersion < __ANDROID_API_R__)
|
||||
access_flags &= ~kAccNative;
|
||||
access_flags &= ~kAccNative;
|
||||
}
|
||||
if (access_flags != old_access_flags) {
|
||||
setFlags(method, access_flags);
|
||||
|
|
@ -184,7 +180,8 @@ static int replaceMethod(void *fromMethod, void *toMethod, int isBackup) {
|
|||
}
|
||||
|
||||
// set the target method to native so that Android O wouldn't invoke it with interpreter
|
||||
if (SDKVersion >= __ANDROID_API_O__) {
|
||||
// for Q or above, we use ShouldUseInterpreterEntrypoint
|
||||
if (SDKVersion >= __ANDROID_API_O__ && SDKVersion < __ANDROID_API_Q__) {
|
||||
setNativeFlag(fromMethod, true);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ namespace art {
|
|||
art::mirror::Class clazz(clazz_ptr);
|
||||
std::string storage;
|
||||
const char *desc = clazz.GetDescriptor(&storage);
|
||||
bool should_intercept = edxp::IsClassPending(desc);
|
||||
bool should_intercept = edxp::IsClassPending(desc) || std::string(desc).rfind("LEdHooker_") == 0;
|
||||
if (UNLIKELY(should_intercept)) {
|
||||
edxp::Context::GetInstance()->CallOnPreFixupStaticTrampolines(clazz_ptr);
|
||||
}
|
||||
|
|
@ -49,9 +49,8 @@ namespace art {
|
|||
|
||||
CREATE_HOOK_STUB_ENTRIES(bool, ShouldUseInterpreterEntrypoint, void *art_method,
|
||||
const void *quick_code) {
|
||||
// TODO check hooked
|
||||
bool hooked = false;
|
||||
if (hooked && quick_code != nullptr) {
|
||||
if (UNLIKELY(edxp::isHooked(art_method) && quick_code != nullptr)) {
|
||||
LOGD("Hooked method %p, no use interpreter", art_method);
|
||||
return false;
|
||||
}
|
||||
return ShouldUseInterpreterEntrypointBackup(art_method, quick_code);
|
||||
|
|
@ -122,8 +121,8 @@ namespace art {
|
|||
|
||||
// Sandhook will hook ShouldUseInterpreterEntrypoint, so we just skip
|
||||
// edxp::Context::GetInstance()->GetVariant() will not work here, so we use smh dirty hack
|
||||
if (api_level >= __ANDROID_API_R__ &&
|
||||
access(edxp::kLibSandHookNativePath.c_str(), F_OK) == -1) {
|
||||
if (api_level >= __ANDROID_API_Q__ &&
|
||||
edxp::path_exists(edxp::kLibSandHookNativePath)) {
|
||||
LOGD("Not sandhook, installing _ZN3art11ClassLinker30ShouldUseInterpreterEntrypointEPNS_9ArtMethodEPKv");
|
||||
HOOK_FUNC(ShouldUseInterpreterEntrypoint,
|
||||
"_ZN3art11ClassLinker30ShouldUseInterpreterEntrypointEPNS_9ArtMethodEPKv");
|
||||
|
|
|
|||
|
|
@ -10,6 +10,8 @@ namespace edxp {
|
|||
|
||||
static std::set<std::string> class_descs_;
|
||||
|
||||
static std::set<void*> hooked_methods_;
|
||||
|
||||
bool IsClassPending(const char *class_desc) {
|
||||
return class_descs_.find(class_desc) != class_descs_.end();
|
||||
}
|
||||
|
|
@ -27,4 +29,12 @@ namespace edxp {
|
|||
REGISTER_EDXP_NATIVE_METHODS("de.robv.android.xposed.PendingHooks");
|
||||
}
|
||||
|
||||
bool isHooked(void* art_method) {
|
||||
return hooked_methods_.count(art_method);
|
||||
}
|
||||
|
||||
void recordHooked(void * art_method) {
|
||||
hooked_methods_.insert(art_method);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -9,4 +9,8 @@ namespace edxp {
|
|||
|
||||
void RegisterPendingHooks(JNIEnv *);
|
||||
|
||||
bool isHooked(void* art_method);
|
||||
|
||||
void recordHooked(void* art_method);
|
||||
|
||||
} // namespace edxp
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
#include "jni.h"
|
||||
#include "native_util.h"
|
||||
#include "edxp_yahfa.h"
|
||||
#include "edxp_pending_hooks.h"
|
||||
|
||||
namespace edxp {
|
||||
|
||||
|
|
@ -49,14 +50,24 @@ namespace edxp {
|
|||
return (jboolean) setNativeFlag(art_method, is_native);
|
||||
}
|
||||
|
||||
static void Yahfa_recordHooked(JNI_START, jobject member) {
|
||||
edxp::recordHooked(getArtMethod(env, member));
|
||||
}
|
||||
|
||||
static jboolean Yahfa_isHooked(JNI_START, jobject member) {
|
||||
return edxp::isHooked(getArtMethod(env, member));
|
||||
}
|
||||
|
||||
static JNINativeMethod gMethods[] = {
|
||||
NATIVE_METHOD(Yahfa, init, "(I)V"),
|
||||
NATIVE_METHOD(Yahfa, findMethodNative,
|
||||
"(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;)Ljava/lang/Object;"),
|
||||
"(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;)Ljava/lang/reflect/Member;"),
|
||||
NATIVE_METHOD(Yahfa, backupAndHookNative,
|
||||
"(Ljava/lang/Object;Ljava/lang/reflect/Method;Ljava/lang/reflect/Method;)Z"),
|
||||
NATIVE_METHOD(Yahfa, setMethodNonCompilable, "(Ljava/lang/reflect/Member;)V"),
|
||||
NATIVE_METHOD(Yahfa, setNativeFlag, "(Ljava/lang/reflect/Member;Z)Z"),
|
||||
NATIVE_METHOD(Yahfa, recordHooked, "(Ljava/lang/reflect/Member;)V"),
|
||||
NATIVE_METHOD(Yahfa, isHooked, "(Ljava/lang/reflect/Member;)Z"),
|
||||
};
|
||||
|
||||
void RegisterEdxpYahfa(JNIEnv *env) {
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import android.text.TextUtils;
|
|||
import com.elderdrivers.riru.edxp.core.Yahfa;
|
||||
import com.elderdrivers.riru.edxp.core.yahfa.HookMain;
|
||||
import com.elderdrivers.riru.edxp.util.ProxyClassLoader;
|
||||
import com.elderdrivers.riru.edxp.yahfa.BuildConfig;
|
||||
|
||||
import java.io.File;
|
||||
import java.lang.reflect.Constructor;
|
||||
|
|
@ -183,11 +184,11 @@ public class HookerDexMaker {
|
|||
mAppClassLoader = appClassLoader;
|
||||
mAppClassLoader = new ProxyClassLoader(mAppClassLoader, getClass().getClassLoader());
|
||||
}
|
||||
doMake();
|
||||
doMake(member.getDeclaringClass().getName());
|
||||
}
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.O)
|
||||
private void doMake() throws Exception {
|
||||
private void doMake(String hookedClassName) throws Exception {
|
||||
final boolean useInMemoryCl = TextUtils.isEmpty(mDexDirPath);
|
||||
mDexMaker = new DexMaker();
|
||||
ClassLoader loader;
|
||||
|
|
@ -209,6 +210,8 @@ public class HookerDexMaker {
|
|||
loader = mDexMaker.generateAndLoad(mAppClassLoader, new File(mDexDirPath), className);
|
||||
} else {
|
||||
// do everything in memory
|
||||
if(BuildConfig.DEBUG)
|
||||
className = className + hookedClassName.replace(".", "/");
|
||||
doGenerate(className);
|
||||
byte[] dexBytes = mDexMaker.generate();
|
||||
loader = new InMemoryDexClassLoader(ByteBuffer.wrap(dexBytes), mAppClassLoader);
|
||||
|
|
|
|||
Loading…
Reference in New Issue