Fixed the hook of 64 bit getOatHeader
This commit is contained in:
parent
5f3dc9220d
commit
76f438f959
|
|
@ -9,21 +9,35 @@
|
||||||
#include <HookMain.h>
|
#include <HookMain.h>
|
||||||
|
|
||||||
namespace art {
|
namespace art {
|
||||||
|
namespace art_method {
|
||||||
|
|
||||||
class ArtMethod : public edxp::HookedObject {
|
|
||||||
|
|
||||||
private:
|
|
||||||
inline static size_t oat_header_length;
|
inline static size_t oat_header_length;
|
||||||
inline static int32_t oat_header_code_length_offset;
|
inline static int32_t oat_header_code_length_offset;
|
||||||
|
|
||||||
|
CREATE_FUNC_SYMBOL_ENTRY(std::string, PrettyMethod, void *thiz, bool with_signature) {
|
||||||
|
if (UNLIKELY(thiz == nullptr))
|
||||||
|
return "null";
|
||||||
|
if (LIKELY(PrettyMethodSym))
|
||||||
|
return PrettyMethodSym(thiz, with_signature);
|
||||||
|
else return "null sym";
|
||||||
|
}
|
||||||
|
|
||||||
|
inline static std::string PrettyMethod(void *thiz) {
|
||||||
|
return PrettyMethod(thiz, true);
|
||||||
|
}
|
||||||
|
|
||||||
CREATE_HOOK_STUB_ENTRIES(void *, GetOatQuickMethodHeader, void *thiz, uintptr_t pc) {
|
CREATE_HOOK_STUB_ENTRIES(void *, GetOatQuickMethodHeader, void *thiz, uintptr_t pc) {
|
||||||
// LOGD("GetOatQuickMethodHeader called, thiz=%p", thiz);
|
|
||||||
// This is a partial copy from AOSP. We only touch them if they are hooked.
|
// This is a partial copy from AOSP. We only touch them if they are hooked.
|
||||||
if (LIKELY(edxp::isHooked(thiz))) {
|
if (UNLIKELY(edxp::isHooked(thiz))) {
|
||||||
uintptr_t original_ep = reinterpret_cast<uintptr_t>(getOriginalEntryPointFromTargetMethod(thiz));
|
uintptr_t original_ep = reinterpret_cast<uintptr_t>(getOriginalEntryPointFromTargetMethod(
|
||||||
if(original_ep) {
|
thiz));
|
||||||
char* code_length_loc = reinterpret_cast<char *>(original_ep) + oat_header_code_length_offset;
|
if (original_ep) {
|
||||||
uint32_t code_length = *reinterpret_cast<uint32_t *>(code_length_loc) & ~0x80000000;
|
char *code_length_loc =
|
||||||
LOGD("GetOatQuickMethodHeader: isHooked=true, original_ep=0x%x, code_length=0x%x, pc=0x%x", original_ep, code_length, pc);
|
reinterpret_cast<char *>(original_ep) + oat_header_code_length_offset;
|
||||||
|
uint32_t code_length =
|
||||||
|
*reinterpret_cast<uint32_t *>(code_length_loc) & ~0x80000000;
|
||||||
|
LOGD("GetOatQuickMethodHeader: ArtMethod=%p (%s), isHooked=true, original_ep=0x%x, code_length=0x%x, pc=0x%x",
|
||||||
|
thiz, PrettyMethod(thiz).c_str(), original_ep, code_length, pc);
|
||||||
if (original_ep <= pc && pc <= original_ep + code_length)
|
if (original_ep <= pc && pc <= original_ep + code_length)
|
||||||
return reinterpret_cast<void *>(original_ep - oat_header_length);
|
return reinterpret_cast<void *>(original_ep - oat_header_length);
|
||||||
// If PC is not in range, we mark it as not found.
|
// If PC is not in range, we mark it as not found.
|
||||||
|
|
@ -36,28 +50,38 @@ namespace art {
|
||||||
return GetOatQuickMethodHeaderBackup(thiz, pc);
|
return GetOatQuickMethodHeaderBackup(thiz, pc);
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
|
||||||
// @ApiSensitive(Level.MIDDLE)
|
|
||||||
static void Setup(void *handle, HookFunType hook_func) {
|
static void Setup(void *handle, HookFunType hook_func) {
|
||||||
LOGD("Classlinker hook setup, handle=%p", handle);
|
LOGD("Classlinker hook setup, handle=%p", handle);
|
||||||
int api_level = edxp::GetAndroidApiLevel();
|
int api_level = edxp::GetAndroidApiLevel();
|
||||||
switch (api_level) {
|
switch (api_level) {
|
||||||
case __ANDROID_API_O__:
|
case __ANDROID_API_O__:
|
||||||
|
[[fallthrough]];
|
||||||
case __ANDROID_API_O_MR1__:
|
case __ANDROID_API_O_MR1__:
|
||||||
|
[[fallthrough]];
|
||||||
case __ANDROID_API_P__:
|
case __ANDROID_API_P__:
|
||||||
oat_header_length = 24;
|
oat_header_length = 24;
|
||||||
oat_header_code_length_offset = -4;
|
oat_header_code_length_offset = -4;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
LOGW("No valid offset in SDK %d for oatHeaderLen, using offset from Android R", api_level);
|
LOGW("No valid offset in SDK %d for oatHeaderLen, using offset from Android R",
|
||||||
|
api_level);
|
||||||
|
[[fallthrough]];
|
||||||
case __ANDROID_API_Q__:
|
case __ANDROID_API_Q__:
|
||||||
|
[[fallthrough]];
|
||||||
case __ANDROID_API_R__:
|
case __ANDROID_API_R__:
|
||||||
oat_header_length = 8;
|
oat_header_length = 8;
|
||||||
oat_header_code_length_offset = -4;
|
oat_header_code_length_offset = -4;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
HOOK_FUNC(GetOatQuickMethodHeader, "_ZN3art9ArtMethod23GetOatQuickMethodHeaderEj");
|
if constexpr (edxp::is64) {
|
||||||
|
HOOK_FUNC(GetOatQuickMethodHeader, "_ZN3art9ArtMethod23GetOatQuickMethodHeaderEm");
|
||||||
|
} else {
|
||||||
|
HOOK_FUNC(GetOatQuickMethodHeader, "_ZN3art9ArtMethod23GetOatQuickMethodHeaderEj");
|
||||||
|
}
|
||||||
|
|
||||||
|
RETRIEVE_FUNC_SYMBOL(PrettyMethod,
|
||||||
|
"_ZN3art9ArtMethod12PrettyMethodEb");
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
#endif //EDXPOSED_ART_METHOD_H
|
#endif //EDXPOSED_ART_METHOD_H
|
||||||
|
|
|
||||||
|
|
@ -35,13 +35,10 @@ namespace art {
|
||||||
}
|
}
|
||||||
|
|
||||||
CREATE_HOOK_STUB_ENTRIES(void, FixupStaticTrampolines, void *thiz, void *clazz_ptr) {
|
CREATE_HOOK_STUB_ENTRIES(void, FixupStaticTrampolines, void *thiz, void *clazz_ptr) {
|
||||||
art::mirror::Class clazz(clazz_ptr);
|
bool should_intercept = edxp::IsClassPending(clazz_ptr);
|
||||||
std::string storage;
|
|
||||||
const char *desc = clazz.GetDescriptor(&storage);
|
|
||||||
bool should_intercept =
|
|
||||||
edxp::IsClassPending(desc) || std::string(desc).rfind("LEdHooker_") == 0;
|
|
||||||
FixupStaticTrampolinesBackup(thiz, clazz_ptr);
|
FixupStaticTrampolinesBackup(thiz, clazz_ptr);
|
||||||
if (UNLIKELY(should_intercept)) {
|
if (UNLIKELY(should_intercept)) {
|
||||||
|
LOGD("Pending hook for %p (%s)", clazz_ptr, art::mirror::Class(clazz_ptr).GetDescriptor(nullptr));
|
||||||
edxp::Context::GetInstance()->CallOnPostFixupStaticTrampolines(clazz_ptr);
|
edxp::Context::GetInstance()->CallOnPostFixupStaticTrampolines(clazz_ptr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "base/object.h"
|
#include "base/object.h"
|
||||||
|
#include "art/runtime/art_method.h"
|
||||||
|
|
||||||
namespace art {
|
namespace art {
|
||||||
|
|
||||||
|
|
@ -9,7 +10,8 @@ namespace art {
|
||||||
CREATE_HOOK_STUB_ENTRIES(const void*, GetSavedEntryPointOfPreCompiledMethod, void *thiz,
|
CREATE_HOOK_STUB_ENTRIES(const void*, GetSavedEntryPointOfPreCompiledMethod, void *thiz,
|
||||||
void *art_method) {
|
void *art_method) {
|
||||||
if (UNLIKELY(edxp::isHooked(art_method))) {
|
if (UNLIKELY(edxp::isHooked(art_method))) {
|
||||||
LOGD("Found hooked method %p, return entrypoint as jit entrypoint", art_method);
|
LOGD("Found hooked method %p (%s), return entrypoint as jit entrypoint", art_method,
|
||||||
|
art::art_method::PrettyMethod(art_method).c_str());
|
||||||
return getEntryPoint(art_method);
|
return getEntryPoint(art_method);
|
||||||
}
|
}
|
||||||
return GetSavedEntryPointOfPreCompiledMethodBackup(thiz, art_method);
|
return GetSavedEntryPointOfPreCompiledMethodBackup(thiz, art_method);
|
||||||
|
|
@ -25,7 +27,7 @@ namespace art {
|
||||||
HOOK_FUNC(GetSavedEntryPointOfPreCompiledMethod,
|
HOOK_FUNC(GetSavedEntryPointOfPreCompiledMethod,
|
||||||
"_ZN3art3jit12JitCodeCache37GetSavedEntryPointOfPreCompiledMethodEPNS_9ArtMethodE");
|
"_ZN3art3jit12JitCodeCache37GetSavedEntryPointOfPreCompiledMethodEPNS_9ArtMethodE");
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -64,7 +64,12 @@ namespace art {
|
||||||
|
|
||||||
const char *GetDescriptor(std::string *storage) {
|
const char *GetDescriptor(std::string *storage) {
|
||||||
if (thiz_ && GetDescriptorSym) {
|
if (thiz_ && GetDescriptorSym) {
|
||||||
return GetDescriptor(thiz_, storage);
|
if (storage == nullptr) {
|
||||||
|
std::string str;
|
||||||
|
return GetDescriptor(thiz_, &str);
|
||||||
|
} else {
|
||||||
|
return GetDescriptor(thiz_, storage);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,10 +5,29 @@
|
||||||
|
|
||||||
namespace art {
|
namespace art {
|
||||||
|
|
||||||
class Thread : public edxp::HookedObject {
|
class Thread : public edxp::HookedObject {
|
||||||
|
|
||||||
|
CREATE_FUNC_SYMBOL_ENTRY(void *, DecodeJObject, void *thiz,
|
||||||
|
jobject obj) {
|
||||||
|
if (DecodeJObjectSym)
|
||||||
|
return DecodeJObjectSym(thiz, obj);
|
||||||
|
else
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Thread(void *thiz) : HookedObject(thiz) {}
|
Thread(void *thiz) : HookedObject(thiz) {}
|
||||||
|
|
||||||
|
static void Setup(void *handle, HookFunType hook_func) {
|
||||||
|
RETRIEVE_FUNC_SYMBOL(DecodeJObject,
|
||||||
|
"_ZNK3art6Thread13DecodeJObjectEP8_jobject");
|
||||||
|
}
|
||||||
|
|
||||||
|
void *DecodeJObject(jobject obj) {
|
||||||
|
if (thiz_ && DecodeJObjectSym) {
|
||||||
|
return DecodeJObject(thiz_, obj);
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,40 +1,44 @@
|
||||||
|
|
||||||
#include <nativehelper/jni_macros.h>
|
#include <nativehelper/jni_macros.h>
|
||||||
#include <set>
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <unordered_set>
|
||||||
#include "HookMain.h"
|
#include "HookMain.h"
|
||||||
#include "jni.h"
|
#include "jni.h"
|
||||||
#include "native_util.h"
|
#include "native_util.h"
|
||||||
#include "edxp_pending_hooks.h"
|
#include "edxp_pending_hooks.h"
|
||||||
|
#include "art/runtime/thread.h"
|
||||||
|
#include "art/runtime/mirror/class.h"
|
||||||
|
|
||||||
namespace edxp {
|
namespace edxp {
|
||||||
|
|
||||||
static std::set<std::string> class_descs_;
|
static std::unordered_set<const void *> pending_classes_;
|
||||||
|
|
||||||
static std::set<const void*> hooked_methods_;
|
static std::unordered_set<const void *> hooked_methods_;
|
||||||
|
|
||||||
bool IsClassPending(const char *class_desc) {
|
bool IsClassPending(void *clazz) {
|
||||||
return class_descs_.find(class_desc) != class_descs_.end();
|
return pending_classes_.count(clazz);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void PendingHooks_recordPendingMethodNative(JNI_START, jstring class_desc) {
|
static void PendingHooks_recordPendingMethodNative(JNI_START, jlong thread, jclass class_ref) {
|
||||||
const char *class_desc_chars = env->GetStringUTFChars(class_desc, JNI_FALSE);
|
art::Thread current_thread(reinterpret_cast<void *>(thread));
|
||||||
class_descs_.insert(class_desc_chars);
|
auto *class_ptr = current_thread.DecodeJObject(class_ref);
|
||||||
|
LOGD("record pending: %p (%s)", class_ptr, art::mirror::Class(class_ptr).GetDescriptor(nullptr));
|
||||||
|
pending_classes_.insert(class_ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
static JNINativeMethod gMethods[] = {
|
static JNINativeMethod gMethods[] = {
|
||||||
NATIVE_METHOD(PendingHooks, recordPendingMethodNative, "(Ljava/lang/String;)V"),
|
NATIVE_METHOD(PendingHooks, recordPendingMethodNative, "(JLjava/lang/Class;)V"),
|
||||||
};
|
};
|
||||||
|
|
||||||
void RegisterPendingHooks(JNIEnv *env) {
|
void RegisterPendingHooks(JNIEnv *env) {
|
||||||
REGISTER_EDXP_NATIVE_METHODS("de.robv.android.xposed.PendingHooks");
|
REGISTER_EDXP_NATIVE_METHODS("de.robv.android.xposed.PendingHooks");
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isHooked(void* art_method) {
|
bool isHooked(void *art_method) {
|
||||||
return hooked_methods_.count(art_method);
|
return hooked_methods_.count(art_method);
|
||||||
}
|
}
|
||||||
|
|
||||||
void recordHooked(void * art_method) {
|
void recordHooked(void *art_method) {
|
||||||
hooked_methods_.insert(art_method);
|
hooked_methods_.insert(art_method);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@
|
||||||
|
|
||||||
namespace edxp {
|
namespace edxp {
|
||||||
|
|
||||||
bool IsClassPending(const char *);
|
bool IsClassPending(void *);
|
||||||
|
|
||||||
void RegisterPendingHooks(JNIEnv *);
|
void RegisterPendingHooks(JNIEnv *);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@
|
||||||
#include "art/runtime/hidden_api.h"
|
#include "art/runtime/hidden_api.h"
|
||||||
#include "art/runtime/oat_file_manager.h"
|
#include "art/runtime/oat_file_manager.h"
|
||||||
#include "art/runtime/jit/jit_code_cache.h"
|
#include "art/runtime/jit/jit_code_cache.h"
|
||||||
|
#include "art/runtime/art_method.h"
|
||||||
|
|
||||||
std::vector<soinfo_t> linker_get_solist(); // Dobby but not in .h
|
std::vector<soinfo_t> linker_get_solist(); // Dobby but not in .h
|
||||||
|
|
||||||
|
|
@ -76,7 +77,8 @@ namespace edxp {
|
||||||
art::hidden_api::DisableHiddenApi(art_handle, hook_func);
|
art::hidden_api::DisableHiddenApi(art_handle, hook_func);
|
||||||
art::Runtime::Setup(art_handle, hook_func);
|
art::Runtime::Setup(art_handle, hook_func);
|
||||||
art::gc::Heap::Setup(art_handle, hook_func);
|
art::gc::Heap::Setup(art_handle, hook_func);
|
||||||
art::ArtMethod::Setup(art_handle, hook_func);
|
art::art_method::Setup(art_handle, hook_func);
|
||||||
|
art::Thread::Setup(art_handle, hook_func);
|
||||||
art::ClassLinker::Setup(art_handle, hook_func);
|
art::ClassLinker::Setup(art_handle, hook_func);
|
||||||
art::mirror::Class::Setup(art_handle, hook_func);
|
art::mirror::Class::Setup(art_handle, hook_func);
|
||||||
art::JNIEnvExt::Setup(art_handle, hook_func);
|
art::JNIEnvExt::Setup(art_handle, hook_func);
|
||||||
|
|
|
||||||
|
|
@ -157,7 +157,7 @@ fi
|
||||||
[[ -f "${MODDIR}/sepolicy.rule" ]] || livePatch
|
[[ -f "${MODDIR}/sepolicy.rule" ]] || livePatch
|
||||||
|
|
||||||
# start_verbose_log_catcher
|
# start_verbose_log_catcher
|
||||||
start_log_cather all "EdXposed:V XSharedPreferences:V EdXposed-Bridge:V EdXposedManager:V XposedInstaller:V" true ${LOG_VERBOSE}
|
start_log_cather all "EdXposed:V XSharedPreferences:V EdXposed-Bridge:V EdXposedManager:V XposedInstaller:V *:F" true ${LOG_VERBOSE}
|
||||||
|
|
||||||
# start_bridge_log_catcher
|
# start_bridge_log_catcher
|
||||||
start_log_cather error "XSharedPreferences:V EdXposed-Bridge:V" true true
|
start_log_cather error "XSharedPreferences:V EdXposed-Bridge:V" true true
|
||||||
|
|
|
||||||
|
|
@ -1,48 +1,52 @@
|
||||||
package de.robv.android.xposed;
|
package de.robv.android.xposed;
|
||||||
|
|
||||||
import com.elderdrivers.riru.edxp.config.EdXpConfigGlobal;
|
import com.elderdrivers.riru.edxp.config.EdXpConfigGlobal;
|
||||||
|
import com.jaredrummler.apkparser.utils.Utils;
|
||||||
|
|
||||||
import java.lang.reflect.Member;
|
import java.lang.reflect.Member;
|
||||||
import java.lang.reflect.Modifier;
|
import java.lang.reflect.Modifier;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
import static de.robv.android.xposed.XposedBridge.hookMethodNative;
|
import static de.robv.android.xposed.XposedBridge.hookMethodNative;
|
||||||
|
import static de.robv.android.xposed.XposedBridge.log;
|
||||||
|
|
||||||
public final class PendingHooks {
|
public final class PendingHooks {
|
||||||
|
|
||||||
// GuardedBy("PendingHooks.class")
|
// GuardedBy("PendingHooks.class")
|
||||||
private static final ConcurrentHashMap<Member, XposedBridge.AdditionalHookInfo>
|
private static final ConcurrentHashMap<Class<?>, ConcurrentHashMap<Member, XposedBridge.AdditionalHookInfo>>
|
||||||
sPendingHookMethods = new ConcurrentHashMap<>();
|
sPendingHooks = new ConcurrentHashMap<>();
|
||||||
// GuardedBy("PendingHooks.class")
|
|
||||||
private static final HashSet<Member> sNonNativeMethods = new HashSet<>();
|
|
||||||
|
|
||||||
public synchronized static void hookPendingMethod(Class clazz) {
|
public synchronized static void hookPendingMethod(Class<?> clazz) {
|
||||||
for (Member member : sPendingHookMethods.keySet()) {
|
if (sPendingHooks.containsKey(clazz)) {
|
||||||
if (member.getDeclaringClass().equals(clazz)) {
|
for (Map.Entry<Member, XposedBridge.AdditionalHookInfo> hook : sPendingHooks.get(clazz).entrySet()) {
|
||||||
hookMethodNative(member, clazz, 0, sPendingHookMethods.get(member));
|
hookMethodNative(hook.getKey(), clazz, 0, hook.getValue());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized static void recordPendingMethod(Member hookMethod,
|
public synchronized static void recordPendingMethod(Member hookMethod,
|
||||||
XposedBridge.AdditionalHookInfo additionalInfo) {
|
XposedBridge.AdditionalHookInfo additionalInfo) {
|
||||||
if (!Modifier.isNative(hookMethod.getModifiers())) {
|
ConcurrentHashMap<Member, XposedBridge.AdditionalHookInfo> pending =
|
||||||
// record non-native methods for later native flag temporary removing
|
sPendingHooks.computeIfAbsent(hookMethod.getDeclaringClass(),
|
||||||
sNonNativeMethods.add(hookMethod);
|
new Function<Class<?>, ConcurrentHashMap<Member, XposedBridge.AdditionalHookInfo>>() {
|
||||||
}
|
@Override
|
||||||
sPendingHookMethods.put(hookMethod, additionalInfo);
|
public ConcurrentHashMap<Member, XposedBridge.AdditionalHookInfo> apply(Class<?> aClass) {
|
||||||
recordPendingMethodNative("L" +
|
return new ConcurrentHashMap<>();
|
||||||
hookMethod.getDeclaringClass().getName().replace(".", "/") + ";");
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
pending.put(hookMethod, additionalInfo);
|
||||||
|
Thread currentThread = Thread.currentThread();
|
||||||
|
long nativePeer = XposedHelpers.getLongField(currentThread, "nativePeer");
|
||||||
|
recordPendingMethodNative(nativePeer, hookMethod.getDeclaringClass());
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized void cleanUp() {
|
public synchronized void cleanUp() {
|
||||||
sPendingHookMethods.clear();
|
sPendingHooks.clear();
|
||||||
// sNonNativeMethods should be cleared very carefully because their
|
|
||||||
// pre-set native flag have to be removed if its hooking is cancelled
|
|
||||||
// before its class is initialized
|
|
||||||
// sNonNativeMethods.clear();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static native void recordPendingMethodNative(String classDesc);
|
private static native void recordPendingMethodNative(long thread, Class clazz);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue