Move inline hooks to post fork
This commit is contained in:
parent
51dfa6b19f
commit
d6c7570588
|
|
@ -41,67 +41,67 @@ ALWAYS_INLINE static int ClearException(JNIEnv *env) {
|
|||
|
||||
#define JNI_FindClass(env, name) \
|
||||
env->FindClass(name); \
|
||||
if (ClearException(env)) LOGE("FindClass " #name);
|
||||
if (ClearException(env)) LOGE("FindClass " #name)
|
||||
|
||||
#define JNI_GetObjectClass(env, obj) \
|
||||
env->GetObjectClass(obj); \
|
||||
if (ClearException(env)) LOGE("GetObjectClass " #obj);
|
||||
if (ClearException(env)) LOGE("GetObjectClass " #obj)
|
||||
|
||||
#define JNI_GetFieldID(env, class, name, sig) \
|
||||
env->GetFieldID(class, name, sig); \
|
||||
if (ClearException(env)) LOGE("GetFieldID " #name);
|
||||
if (ClearException(env)) LOGE("GetFieldID " #name)
|
||||
|
||||
#define JNI_GetObjectField(env, class, fieldId) \
|
||||
env->GetObjectField(class, fieldId); \
|
||||
if (ClearException(env)) LOGE("GetObjectField " #fieldId);
|
||||
if (ClearException(env)) LOGE("GetObjectField " #fieldId)
|
||||
|
||||
#define JNI_GetMethodID(env, class, name, sig) \
|
||||
env->GetMethodID(class, name, sig); \
|
||||
if (ClearException(env)) LOGE("GetMethodID " #name);
|
||||
if (ClearException(env)) LOGE("GetMethodID " #name)
|
||||
|
||||
#define JNI_CallObjectMethod(env, obj, ...) \
|
||||
env->CallObjectMethod(obj, __VA_ARGS__); \
|
||||
if (ClearException(env)) LOGE("CallObjectMethod " #obj " " #__VA_ARGS__);
|
||||
if (ClearException(env)) LOGE("CallObjectMethod " #obj " " #__VA_ARGS__)
|
||||
|
||||
#define JNI_CallVoidMethod(env, obj, ...) \
|
||||
env->CallVoidMethod(obj, __VA_ARGS__); \
|
||||
if (ClearException(env)) LOGE("CallVoidMethod " #obj " " #__VA_ARGS__);
|
||||
if (ClearException(env)) LOGE("CallVoidMethod " #obj " " #__VA_ARGS__)
|
||||
|
||||
#define JNI_GetStaticFieldID(env, class, name, sig) \
|
||||
env->GetStaticFieldID(class, name, sig); \
|
||||
if (ClearException(env)) LOGE("GetStaticFieldID " #name " " #sig);
|
||||
if (ClearException(env)) LOGE("GetStaticFieldID " #name " " #sig)
|
||||
|
||||
#define JNI_GetStaticObjectField(env, class, fieldId) \
|
||||
env->GetStaticObjectField(class, fieldId); \
|
||||
if (ClearException(env)) LOGE("GetStaticObjectField " #fieldId);
|
||||
if (ClearException(env)) LOGE("GetStaticObjectField " #fieldId)
|
||||
|
||||
#define JNI_GetStaticMethodID(env, class, name, sig) \
|
||||
env->GetStaticMethodID(class, name, sig); \
|
||||
if (ClearException(env)) LOGE("GetStaticMethodID " #name);
|
||||
if (ClearException(env)) LOGE("GetStaticMethodID " #name)
|
||||
|
||||
#define JNI_CallStaticVoidMethod(env, obj, ...) \
|
||||
env->CallStaticVoidMethod(obj, __VA_ARGS__); \
|
||||
if (ClearException(env)) LOGE("CallStaticVoidMethod " #obj " " #__VA_ARGS__);
|
||||
if (ClearException(env)) LOGE("CallStaticVoidMethod " #obj " " #__VA_ARGS__)
|
||||
|
||||
#define JNI_CallStaticObjectMethod(env, obj, ...) \
|
||||
env->CallStaticObjectMethod(obj, __VA_ARGS__); \
|
||||
if (ClearException(env)) LOGE("CallStaticObjectMethod " #obj " " #__VA_ARGS__);
|
||||
if (ClearException(env)) LOGE("CallStaticObjectMethod " #obj " " #__VA_ARGS__)
|
||||
|
||||
#define JNI_CallStaticIntMethod(env, obj, ...) \
|
||||
env->CallStaticIntMethod(obj, __VA_ARGS__); \
|
||||
if (ClearException(env)) LOGE("CallStaticIntMethod " #obj " " #__VA_ARGS__);
|
||||
if (ClearException(env)) LOGE("CallStaticIntMethod " #obj " " #__VA_ARGS__)
|
||||
|
||||
#define JNI_GetArrayLength(env, array) \
|
||||
env->GetArrayLength(array); \
|
||||
if (ClearException(env)) LOGE("GetArrayLength " #array);
|
||||
if (ClearException(env)) LOGE("GetArrayLength " #array)
|
||||
|
||||
#define JNI_NewObject(env, class, ...) \
|
||||
env->NewObject(class, __VA_ARGS__); \
|
||||
if (ClearException(env)) LOGE("NewObject " #class " " #__VA_ARGS__);
|
||||
if (ClearException(env)) LOGE("NewObject " #class " " #__VA_ARGS__)
|
||||
|
||||
#define JNI_RegisterNatives(env, class, methods, size) \
|
||||
env->RegisterNatives(class, methods, size); \
|
||||
if (ClearException(env)) LOGE("RegisterNatives " #class);
|
||||
if (ClearException(env)) LOGE("RegisterNatives " #class)
|
||||
|
||||
class JUTFString {
|
||||
public:
|
||||
|
|
|
|||
|
|
@ -46,7 +46,8 @@ namespace art {
|
|||
}
|
||||
}
|
||||
|
||||
CREATE_HOOK_STUB_ENTRIES(bool, ShouldUseInterpreterEntrypoint, void *art_method, const void* quick_code) {
|
||||
CREATE_HOOK_STUB_ENTRIES(bool, ShouldUseInterpreterEntrypoint, void *art_method,
|
||||
const void *quick_code) {
|
||||
// TODO check hooked
|
||||
bool hooked = false;
|
||||
if (hooked && quick_code != nullptr) {
|
||||
|
|
@ -68,46 +69,47 @@ namespace art {
|
|||
// TODO: Maybe not compatible with Android 10-
|
||||
int api_level = edxp::GetAndroidApiLevel();
|
||||
size_t OFFSET_classlinker; // Get offset from art::Runtime::RunRootClinits() call in IDA
|
||||
switch(api_level) {
|
||||
switch (api_level) {
|
||||
case __ANDROID_API_O__:
|
||||
[[fallthrough]];
|
||||
case __ANDROID_API_O_MR1__:
|
||||
#ifdef __LP64__
|
||||
OFFSET_classlinker = 464 / 8;
|
||||
#else
|
||||
OFFSET_classlinker = 284 / 4;
|
||||
#endif
|
||||
if constexpr(edxp::is64) {
|
||||
OFFSET_classlinker = 464;
|
||||
} else {
|
||||
OFFSET_classlinker = 284;
|
||||
}
|
||||
break;
|
||||
case __ANDROID_API_P__:
|
||||
#ifdef __LP64__
|
||||
OFFSET_classlinker = 528 / 8;
|
||||
#else
|
||||
OFFSET_classlinker = 336 / 4;
|
||||
#endif
|
||||
if constexpr(edxp::is64) {
|
||||
OFFSET_classlinker = 528;
|
||||
} else {
|
||||
OFFSET_classlinker = 336;
|
||||
}
|
||||
break;
|
||||
case __ANDROID_API_Q__:
|
||||
#ifdef __LP64__
|
||||
OFFSET_classlinker = 480 / 8;
|
||||
#else
|
||||
OFFSET_classlinker = 280 / 4;
|
||||
#endif
|
||||
if constexpr(edxp::is64) {
|
||||
OFFSET_classlinker = 480;
|
||||
} else {
|
||||
OFFSET_classlinker = 280;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
LOGE("No valid offset for art::Runtime::class_linker_ found. Using Android R.");
|
||||
[[fallthrough]];
|
||||
case __ANDROID_API_R__:
|
||||
#ifdef __LP64__
|
||||
OFFSET_classlinker = 472 / 8;
|
||||
#else
|
||||
OFFSET_classlinker = 276 / 4;
|
||||
#endif
|
||||
if constexpr(edxp::is64) {
|
||||
OFFSET_classlinker = 472;
|
||||
} else {
|
||||
OFFSET_classlinker = 276;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
void *thiz = *reinterpret_cast<void **>(
|
||||
reinterpret_cast<size_t>(Runtime::Current()->Get()) + OFFSET_classlinker);
|
||||
// ClassLinker* GetClassLinker() but inlined
|
||||
void* cl = reinterpret_cast<void*>(
|
||||
reinterpret_cast<size_t*>(Runtime::Current()->Get()) + OFFSET_classlinker
|
||||
);
|
||||
LOGD("Classlinker object: %p", cl);
|
||||
instance_ = new ClassLinker(cl);
|
||||
LOGD("Classlinker object: %p", thiz);
|
||||
instance_ = new ClassLinker(thiz);
|
||||
|
||||
HOOK_FUNC(Constructor, "_ZN3art11ClassLinkerC2EPNS_11InternTableE",
|
||||
"_ZN3art11ClassLinkerC2EPNS_11InternTableEb"); // 10.0
|
||||
|
|
@ -119,7 +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_R__ &&
|
||||
access(edxp::kLibSandHookNativePath.c_str(), F_OK) == -1) {
|
||||
LOGD("Not sandhook, installing _ZN3art11ClassLinker30ShouldUseInterpreterEntrypointEPNS_9ArtMethodEPKv");
|
||||
HOOK_FUNC(ShouldUseInterpreterEntrypoint,
|
||||
"_ZN3art11ClassLinker30ShouldUseInterpreterEntrypointEPNS_9ArtMethodEPKv");
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
#include "collector/gc_type.h"
|
||||
#include "gc_cause.h"
|
||||
#include "../thread.h"
|
||||
#include "../runtime.h"
|
||||
|
||||
namespace art {
|
||||
|
||||
|
|
@ -22,14 +23,6 @@ namespace art {
|
|||
return art::gc::collector::GcType::kGcTypeNone;
|
||||
}
|
||||
|
||||
CREATE_HOOK_STUB_ENTRIES(void, PreZygoteFork, void *thiz) {
|
||||
if (instance_)
|
||||
instance_->Reset(thiz);
|
||||
else
|
||||
instance_ = new Heap(thiz);
|
||||
PreZygoteForkBackup(thiz);
|
||||
}
|
||||
|
||||
public:
|
||||
Heap(void *thiz) : HookedObject(thiz) {}
|
||||
|
||||
|
|
@ -39,7 +32,47 @@ namespace art {
|
|||
|
||||
// @ApiSensitive(Level.MIDDLE)
|
||||
static void Setup(void *handle, HookFunType hook_func) {
|
||||
HOOK_FUNC(PreZygoteFork, "_ZN3art2gc4Heap13PreZygoteForkEv");
|
||||
int api_level = edxp::GetAndroidApiLevel();
|
||||
size_t OFFSET_classlinker; // Get offset from art::Runtime::RunRootClinits() call in IDA
|
||||
switch (api_level) {
|
||||
case __ANDROID_API_O__:
|
||||
[[fallthrough]];
|
||||
case __ANDROID_API_O_MR1__:
|
||||
if constexpr(edxp::is64) {
|
||||
OFFSET_classlinker = 464;
|
||||
} else {
|
||||
OFFSET_classlinker = 284;
|
||||
}
|
||||
break;
|
||||
case __ANDROID_API_P__:
|
||||
if constexpr(edxp::is64) {
|
||||
OFFSET_classlinker = 528;
|
||||
} else {
|
||||
OFFSET_classlinker = 336;
|
||||
}
|
||||
break;
|
||||
case __ANDROID_API_Q__:
|
||||
if constexpr(edxp::is64) {
|
||||
OFFSET_classlinker = 480;
|
||||
} else {
|
||||
OFFSET_classlinker = 280;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
LOGE("No valid offset for art::Runtime::class_linker_ found. Using Android R.");
|
||||
[[fallthrough]];
|
||||
case __ANDROID_API_R__:
|
||||
if constexpr(edxp::is64) {
|
||||
OFFSET_classlinker = 392;
|
||||
} else {
|
||||
OFFSET_classlinker = 236;
|
||||
}
|
||||
break;
|
||||
}
|
||||
void *thiz = *reinterpret_cast<void **>(
|
||||
reinterpret_cast<size_t>(Runtime::Current()->Get()) + OFFSET_classlinker);
|
||||
LOGD("HEAP object: %p", thiz);
|
||||
instance_ = new Heap(thiz);
|
||||
RETRIEVE_FUNC_SYMBOL(WaitForGcToComplete,
|
||||
"_ZN3art2gc4Heap19WaitForGcToCompleteENS0_7GcCauseEPNS_6ThreadE");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,19 +16,6 @@ namespace art {
|
|||
DeoptimizeBootImageSym(thiz);
|
||||
}
|
||||
|
||||
CREATE_HOOK_STUB_ENTRIES(bool, Init, void *thiz, void *runtime_options) {
|
||||
if (LIKELY(instance_))
|
||||
instance_->Reset(thiz);
|
||||
else
|
||||
instance_ = new Runtime(thiz);
|
||||
bool success = InitBackup(thiz, runtime_options);
|
||||
if (edxp::ConfigManager::GetInstance()->IsDeoptBootImageEnabled()) {
|
||||
DeoptimizeBootImage(thiz);
|
||||
LOGI("DeoptimizeBootImage done");
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
public:
|
||||
Runtime(void *thiz) : HookedObject(thiz) {}
|
||||
|
||||
|
|
@ -38,19 +25,13 @@ namespace art {
|
|||
|
||||
// @ApiSensitive(Level.LOW)
|
||||
static void Setup(void *handle, HookFunType hook_func) {
|
||||
HOOK_FUNC(Init, "_ZN3art7Runtime4InitEONS_18RuntimeArgumentMapE");
|
||||
RETRIEVE_FUNC_SYMBOL(DeoptimizeBootImage,
|
||||
"_ZN3art7Runtime19DeoptimizeBootImageEv");
|
||||
RETRIEVE_FIELD_SYMBOL(thiz, "_ZN3art7Runtime9instance_E");
|
||||
RETRIEVE_FIELD_SYMBOL(instance, "_ZN3art7Runtime9instance_E");
|
||||
void * thiz = *reinterpret_cast<void**>(instance);
|
||||
LOGD("_ZN3art7Runtime9instance_E = %p", thiz);
|
||||
instance_ = new Runtime(thiz);
|
||||
}
|
||||
|
||||
ALWAYS_INLINE void DeoptimizeBootImage() const {
|
||||
if (LIKELY(thiz_))
|
||||
DeoptimizeBootImage(thiz_);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,6 +12,17 @@ namespace edxp {
|
|||
//#define LOG_DISABLED
|
||||
//#define DEBUG
|
||||
|
||||
|
||||
inline bool constexpr Is64() {
|
||||
#if defined(__LP64__)
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
inline constexpr bool is64 = Is64();
|
||||
|
||||
#if defined(__LP64__)
|
||||
# define LP_SELECT(lp32, lp64) (lp64)
|
||||
#else
|
||||
|
|
|
|||
|
|
@ -18,6 +18,9 @@
|
|||
#include <sstream>
|
||||
#include "edxp_context.h"
|
||||
#include "config_manager.h"
|
||||
#include "art/runtime/runtime.h"
|
||||
#include "art/runtime/gc/heap.h"
|
||||
#include "native_hook.h"
|
||||
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wunused-value"
|
||||
|
|
@ -242,9 +245,22 @@ namespace edxp {
|
|||
}
|
||||
|
||||
|
||||
int Context::OnNativeForkSystemServerPost(JNIEnv *env, jclass clazz, jint res) {
|
||||
int
|
||||
Context::OnNativeForkSystemServerPost(JNIEnv *env, [[maybe_unused]] jclass clazz, jint res) {
|
||||
if (res == 0) {
|
||||
if (!skip_) {
|
||||
if (void *buf = mmap(nullptr, 1, PROT_READ | PROT_WRITE | PROT_EXEC,
|
||||
MAP_ANONYMOUS | MAP_PRIVATE, -1,
|
||||
0);
|
||||
buf == MAP_FAILED) {
|
||||
skip_ = true;
|
||||
LOGE("skip injecting into android because sepolicy was not loaded properly");
|
||||
} else {
|
||||
munmap(buf, 1);
|
||||
}
|
||||
}
|
||||
if (!skip_) {
|
||||
InstallInlineHooks();
|
||||
PrepareJavaEnv(env);
|
||||
// only do work in child since FindAndCall would print log
|
||||
FindAndCall(env, "forkSystemServerPost", "(I)V", res);
|
||||
|
|
@ -345,6 +361,7 @@ namespace edxp {
|
|||
if (res == 0) {
|
||||
const JUTFString process_name(env, nice_name_);
|
||||
if (!skip_) {
|
||||
InstallInlineHooks();
|
||||
PrepareJavaEnv(env);
|
||||
LOGD("Done prepare");
|
||||
FindAndCall(env, "forkAndSpecializePost",
|
||||
|
|
|
|||
|
|
@ -9,18 +9,17 @@
|
|||
|
||||
namespace edxp {
|
||||
|
||||
static std::vector<void *> deopted_methods;
|
||||
static std::unordered_set<void *> deopted_methods;
|
||||
|
||||
static void ClassLinker_setEntryPointsToInterpreter(JNI_START, jobject method) {
|
||||
void *reflected_method = getArtMethod(env, method);
|
||||
if (std::find(deopted_methods.begin(), deopted_methods.end(), reflected_method) !=
|
||||
deopted_methods.end()) {
|
||||
if (deopted_methods.count(reflected_method)) {
|
||||
LOGD("method %p has been deopted before, skip...", reflected_method);
|
||||
return;
|
||||
}
|
||||
LOGD("deoptimizing method: %p", reflected_method);
|
||||
art::ClassLinker::Current()->SetEntryPointsToInterpreter(reflected_method);
|
||||
deopted_methods.push_back(reflected_method);
|
||||
deopted_methods.insert(reflected_method);
|
||||
LOGD("method deoptimized: %p", reflected_method);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -24,7 +24,6 @@ namespace edxp {
|
|||
// TODO exclude unrelated processes
|
||||
static void onModuleLoaded() {
|
||||
LOG(INFO) << "onModuleLoaded: welcome to EdXposed!";
|
||||
InstallInlineHooks();
|
||||
}
|
||||
|
||||
static int shouldSkipUid(int uid) {
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ namespace edxp {
|
|||
|
||||
static volatile bool installed = false;
|
||||
static volatile bool art_hooks_installed = false;
|
||||
static HookFunType hook_func = nullptr;
|
||||
static HookFunType hook_func = reinterpret_cast<HookFunType>(DobbyHook);
|
||||
|
||||
void InstallArtHooks(void *art_handle);
|
||||
|
||||
|
|
@ -42,8 +42,6 @@ namespace edxp {
|
|||
}
|
||||
LOGI("Using api level %d", api_level);
|
||||
InstallRiruHooks();
|
||||
hook_func = reinterpret_cast<HookFunType>(DobbyHook);
|
||||
|
||||
// install ART hooks
|
||||
if (api_level >= __ANDROID_API_Q__) {
|
||||
// From Riru v22 we can't get ART handle by hooking dlopen, so we get libart.so from soinfo.
|
||||
|
|
@ -73,9 +71,7 @@ namespace edxp {
|
|||
if (art_hooks_installed) {
|
||||
return;
|
||||
}
|
||||
if (ConfigManager::GetInstance()->IsHiddenAPIBypassEnabled()) {
|
||||
art::hidden_api::DisableHiddenApi(art_handle, hook_func);
|
||||
}
|
||||
art::hidden_api::DisableHiddenApi(art_handle, hook_func);
|
||||
art::Runtime::Setup(art_handle, hook_func);
|
||||
art::gc::Heap::Setup(art_handle, hook_func);
|
||||
art::ClassLinker::Setup(art_handle, hook_func);
|
||||
|
|
|
|||
Loading…
Reference in New Issue