Fixed the hook of 64 bit getOatHeader

This commit is contained in:
LoveSy 2020-12-20 14:47:03 +08:00 committed by Jim Wu
parent 5f3dc9220d
commit 76f438f959
10 changed files with 116 additions and 59 deletions

View File

@ -9,21 +9,35 @@
#include <HookMain.h>
namespace art {
namespace art_method {
class ArtMethod : public edxp::HookedObject {
private:
inline static size_t oat_header_length;
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) {
// LOGD("GetOatQuickMethodHeader called, thiz=%p", thiz);
// This is a partial copy from AOSP. We only touch them if they are hooked.
if (LIKELY(edxp::isHooked(thiz))) {
uintptr_t original_ep = reinterpret_cast<uintptr_t>(getOriginalEntryPointFromTargetMethod(thiz));
if(original_ep) {
char* code_length_loc = reinterpret_cast<char *>(original_ep) + oat_header_code_length_offset;
uint32_t code_length = *reinterpret_cast<uint32_t *>(code_length_loc) & ~0x80000000;
LOGD("GetOatQuickMethodHeader: isHooked=true, original_ep=0x%x, code_length=0x%x, pc=0x%x", original_ep, code_length, pc);
if (UNLIKELY(edxp::isHooked(thiz))) {
uintptr_t original_ep = reinterpret_cast<uintptr_t>(getOriginalEntryPointFromTargetMethod(
thiz));
if (original_ep) {
char *code_length_loc =
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)
return reinterpret_cast<void *>(original_ep - oat_header_length);
// If PC is not in range, we mark it as not found.
@ -36,28 +50,38 @@ namespace art {
return GetOatQuickMethodHeaderBackup(thiz, pc);
}
public:
// @ApiSensitive(Level.MIDDLE)
static void Setup(void *handle, HookFunType hook_func) {
LOGD("Classlinker hook setup, handle=%p", handle);
int api_level = edxp::GetAndroidApiLevel();
switch (api_level) {
case __ANDROID_API_O__:
[[fallthrough]];
case __ANDROID_API_O_MR1__:
[[fallthrough]];
case __ANDROID_API_P__:
oat_header_length = 24;
oat_header_code_length_offset = -4;
break;
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__:
[[fallthrough]];
case __ANDROID_API_R__:
oat_header_length = 8;
oat_header_code_length_offset = -4;
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

View File

@ -35,13 +35,10 @@ namespace art {
}
CREATE_HOOK_STUB_ENTRIES(void, FixupStaticTrampolines, void *thiz, void *clazz_ptr) {
art::mirror::Class clazz(clazz_ptr);
std::string storage;
const char *desc = clazz.GetDescriptor(&storage);
bool should_intercept =
edxp::IsClassPending(desc) || std::string(desc).rfind("LEdHooker_") == 0;
bool should_intercept = edxp::IsClassPending(clazz_ptr);
FixupStaticTrampolinesBackup(thiz, clazz_ptr);
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);
}
}

View File

@ -1,6 +1,7 @@
#pragma once
#include "base/object.h"
#include "art/runtime/art_method.h"
namespace art {
@ -9,7 +10,8 @@ namespace art {
CREATE_HOOK_STUB_ENTRIES(const void*, GetSavedEntryPointOfPreCompiledMethod, void *thiz,
void *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 GetSavedEntryPointOfPreCompiledMethodBackup(thiz, art_method);
@ -25,7 +27,7 @@ namespace art {
HOOK_FUNC(GetSavedEntryPointOfPreCompiledMethod,
"_ZN3art3jit12JitCodeCache37GetSavedEntryPointOfPreCompiledMethodEPNS_9ArtMethodE");
}
};
}
}

View File

@ -64,7 +64,12 @@ namespace art {
const char *GetDescriptor(std::string *storage) {
if (thiz_ && GetDescriptorSym) {
return GetDescriptor(thiz_, storage);
if (storage == nullptr) {
std::string str;
return GetDescriptor(thiz_, &str);
} else {
return GetDescriptor(thiz_, storage);
}
}
return "";
}

View File

@ -5,10 +5,29 @@
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:
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;
}
};
}

View File

@ -1,40 +1,44 @@
#include <nativehelper/jni_macros.h>
#include <set>
#include <string>
#include <unordered_set>
#include "HookMain.h"
#include "jni.h"
#include "native_util.h"
#include "edxp_pending_hooks.h"
#include "art/runtime/thread.h"
#include "art/runtime/mirror/class.h"
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) {
return class_descs_.find(class_desc) != class_descs_.end();
bool IsClassPending(void *clazz) {
return pending_classes_.count(clazz);
}
static void PendingHooks_recordPendingMethodNative(JNI_START, jstring class_desc) {
const char *class_desc_chars = env->GetStringUTFChars(class_desc, JNI_FALSE);
class_descs_.insert(class_desc_chars);
static void PendingHooks_recordPendingMethodNative(JNI_START, jlong thread, jclass class_ref) {
art::Thread current_thread(reinterpret_cast<void *>(thread));
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[] = {
NATIVE_METHOD(PendingHooks, recordPendingMethodNative, "(Ljava/lang/String;)V"),
NATIVE_METHOD(PendingHooks, recordPendingMethodNative, "(JLjava/lang/Class;)V"),
};
void RegisterPendingHooks(JNIEnv *env) {
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);
}
void recordHooked(void * art_method) {
void recordHooked(void *art_method) {
hooked_methods_.insert(art_method);
}

View File

@ -5,7 +5,7 @@
namespace edxp {
bool IsClassPending(const char *);
bool IsClassPending(void *);
void RegisterPendingHooks(JNIEnv *);

View File

@ -19,6 +19,7 @@
#include "art/runtime/hidden_api.h"
#include "art/runtime/oat_file_manager.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
@ -76,7 +77,8 @@ namespace edxp {
art::hidden_api::DisableHiddenApi(art_handle, hook_func);
art::Runtime::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::mirror::Class::Setup(art_handle, hook_func);
art::JNIEnvExt::Setup(art_handle, hook_func);

View File

@ -157,7 +157,7 @@ fi
[[ -f "${MODDIR}/sepolicy.rule" ]] || livePatch
# 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_log_cather error "XSharedPreferences:V EdXposed-Bridge:V" true true

View File

@ -1,48 +1,52 @@
package de.robv.android.xposed;
import com.elderdrivers.riru.edxp.config.EdXpConfigGlobal;
import com.jaredrummler.apkparser.utils.Utils;
import java.lang.reflect.Member;
import java.lang.reflect.Modifier;
import java.util.HashSet;
import java.util.Map;
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.log;
public final class PendingHooks {
// GuardedBy("PendingHooks.class")
private static final ConcurrentHashMap<Member, XposedBridge.AdditionalHookInfo>
sPendingHookMethods = new ConcurrentHashMap<>();
// GuardedBy("PendingHooks.class")
private static final HashSet<Member> sNonNativeMethods = new HashSet<>();
private static final ConcurrentHashMap<Class<?>, ConcurrentHashMap<Member, XposedBridge.AdditionalHookInfo>>
sPendingHooks = new ConcurrentHashMap<>();
public synchronized static void hookPendingMethod(Class clazz) {
for (Member member : sPendingHookMethods.keySet()) {
if (member.getDeclaringClass().equals(clazz)) {
hookMethodNative(member, clazz, 0, sPendingHookMethods.get(member));
public synchronized static void hookPendingMethod(Class<?> clazz) {
if (sPendingHooks.containsKey(clazz)) {
for (Map.Entry<Member, XposedBridge.AdditionalHookInfo> hook : sPendingHooks.get(clazz).entrySet()) {
hookMethodNative(hook.getKey(), clazz, 0, hook.getValue());
}
}
}
public synchronized static void recordPendingMethod(Member hookMethod,
XposedBridge.AdditionalHookInfo additionalInfo) {
if (!Modifier.isNative(hookMethod.getModifiers())) {
// record non-native methods for later native flag temporary removing
sNonNativeMethods.add(hookMethod);
}
sPendingHookMethods.put(hookMethod, additionalInfo);
recordPendingMethodNative("L" +
hookMethod.getDeclaringClass().getName().replace(".", "/") + ";");
ConcurrentHashMap<Member, XposedBridge.AdditionalHookInfo> pending =
sPendingHooks.computeIfAbsent(hookMethod.getDeclaringClass(),
new Function<Class<?>, ConcurrentHashMap<Member, XposedBridge.AdditionalHookInfo>>() {
@Override
public ConcurrentHashMap<Member, XposedBridge.AdditionalHookInfo> apply(Class<?> aClass) {
return new ConcurrentHashMap<>();
}
});
pending.put(hookMethod, additionalInfo);
Thread currentThread = Thread.currentThread();
long nativePeer = XposedHelpers.getLongField(currentThread, "nativePeer");
recordPendingMethodNative(nativePeer, hookMethod.getDeclaringClass());
}
public synchronized void cleanUp() {
sPendingHookMethods.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();
sPendingHooks.clear();
}
private static native void recordPendingMethodNative(String classDesc);
private static native void recordPendingMethodNative(long thread, Class clazz);
}